/******************************************************************************* * Copyright (c) 2014 Open Door Logistics (www.opendoorlogistics.com) * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser Public License v3 * which accompanies this distribution, and is available at http://www.gnu.org/licenses/lgpl.txt ******************************************************************************/ package com.opendoorlogistics.studio.controls.checkboxtable; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Image; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingConstants; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import com.opendoorlogistics.core.utils.images.ImageUtils; import com.opendoorlogistics.core.utils.ui.ShowPanel; import com.opendoorlogistics.studio.InitialiseStudio; import com.opendoorlogistics.studio.controls.CustomTableItemRenderer; import com.opendoorlogistics.utils.ui.Icons; public class CheckboxTable extends JScrollPane{ private final HashSet<CheckChangedListener> checkChangedListeners = new HashSet<>(); private final HashSet<ButtonClickedListener> buttonClickedListeners = new HashSet<>(); private final JTable table; private final Dimension checkboxSize; private List<? extends CheckBoxItem> items; private boolean disableListeners=false; private final Icon []buttonIcons; private JCheckBox []boxes; private JButton [][]buttons; public static interface CheckChangedListener{ void checkStateChanged(); } public static interface ButtonClickedListener{ void buttonClicked(CheckBoxItem item, int buttonColumn); } // public CheckboxTable( Dimension checkboxSize, List<? extends CheckBoxItem> items){ // this(null, checkboxSize, items); // } public CheckboxTable(Icon[] buttonIcons, Dimension checkboxSize, List<? extends CheckBoxItem> items){ this.checkboxSize = checkboxSize; this.buttonIcons = buttonIcons; // create table table = new JTable(); table.setTableHeader(null); setViewportView(table); setItems(items); } private int getNbButtonCols(){ return buttonIcons!=null? buttonIcons.length:0; } public void setItems(final List<? extends CheckBoxItem> items) { this.items = items; // check for images and get the standard sizes Dimension imageSize=null; for(CheckBoxItem item: items){ BufferedImage image = item.getImage(); if(image!=null){ Dimension size = ImageUtils.getSize(image); if(imageSize==null){ imageSize = size; }else{ imageSize = new Dimension(Math.max(imageSize.width, size.width), Math.max(imageSize.height, size.height)); } } } // final Dimension stdImageSize = imageSize; final int imageCol = imageSize==null? -1: getNbButtonCols() + 1; final int checkboxCol = getNbButtonCols(); final int textCol = imageSize==null? getNbButtonCols() + 1: getNbButtonCols() + 2; final int nbCols = textCol+1; table.setModel(new AbstractTableModel() { @Override public Object getValueAt(int rowIndex, int col) { CheckBoxItem item = items.get(rowIndex); if(col==imageCol){ return item.getImage(); } else if(col == textCol){ return item.getText(); } return null; } @Override public Class<?> getColumnClass(int col) { if(col < getNbButtonCols()){ return JButton.class; } else if(checkboxCol==0){ return JCheckBox.class; }else if(col == imageCol){ return BufferedImage.class; } return String.class; } @Override public int getRowCount() { return items.size(); } @Override public int getColumnCount() { return nbCols; } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return true; } }); //table.getTableHeader().sev if(imageCol!=-1){ TableCellRenderer imageRenderer = new TableCellRenderer(){ @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { final BufferedImage img = items.get(row).getImage(); final int w = table.getColumnModel().getColumn(column).getWidth(); final int h = table.getRowHeight(row); return new JPanel(){ @Override protected void paintComponent(Graphics g) { super.paintComponent(g); if(img!=null){ // do white fill g.setColor(Color.WHITE); g.fillRect(0, 0, w, h); // draw centred int sw = Math.max(w - img.getWidth(),0); int sh = Math.max(h - img.getHeight(),0); g.drawImage(img, sw/2, sh/2, null); } } }; } }; TableColumn col=table.getColumnModel().getColumn(imageCol); col.setCellRenderer(imageRenderer); col.setMaxWidth(imageSize.width); // need to set row height later, presumably after table shown? final int rowHeight = Math.max(table.getRowHeight(),imageSize.height); EventQueue.invokeLater(new Runnable() { @Override public void run() { table.setRowHeight(rowHeight); } }); } // create buttons initButtons(items); initCheckboxes(items, checkboxCol); table.setRowHeight(checkboxSize.height); table.setFillsViewportHeight(true); //PackTableColumn.packAll(table, 4); } private void initButtons(final List<? extends CheckBoxItem> items) { if(getNbButtonCols()==0){ buttons = null; return; } buttons = new JButton[getNbButtonCols()][]; for(int i =0 ; i<getNbButtonCols() ; i++){ buttons[i] = new JButton[items.size()]; for(int j =0 ; j<buttons[i].length;j++){ final Image img; final Icon icon = buttonIcons[i]; if(icon!=null){ img = Icons.iconToImage(buttonIcons[i]); }else{ img = null; } final JButton button = new JButton(){ public void paint(Graphics g) { super.paint(g); if(img!=null){ } boolean shouldClearPaintFlags = false; if ((getWidth() <= 0) || (getHeight() <= 0)) { return; } Graphics componentGraphics = getComponentGraphics(g); Graphics co = componentGraphics.create(); try { Rectangle clipRect = co.getClipBounds(); // Dimension imgSize =icon new Dimension(3*clipRect.width/2, 3*clipRect.height/2); Dimension imgSize = new Dimension(icon.getIconWidth(), icon.getIconHeight()); int x = (clipRect.width - imgSize.width)/2; int y =(clipRect.height-imgSize.height)/2; co.drawImage(img,x,y, imgSize.width, imgSize.height , null); } catch (Exception e) { // TODO: handle exception }finally{ co.dispose(); } } }; final int colIndx=i; final CheckBoxItem item = items.get(j); buttons[i][j]=button; button.setHorizontalAlignment(SwingConstants.LEFT); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { for(ButtonClickedListener listener : buttonClickedListeners){ listener.buttonClicked(item, colIndx); } } }); } // set customer item renderer for the checkboxes CustomTableItemRenderer<JCheckBox> renderer = new CustomTableItemRenderer(buttons[i]); TableColumn checkBoxCol = table.getColumnModel().getColumn(i); checkBoxCol.setCellEditor(renderer); checkBoxCol.setCellRenderer(renderer); checkBoxCol.setMaxWidth(checkboxSize.width); } } /** * @param items * @param checkboxCol */ private void initCheckboxes(final List<? extends CheckBoxItem> items, final int checkboxCol) { // set all to left align... looks better boxes=new JCheckBox[items.size()]; for(int i =0 ; i<boxes.length;i++){ final JCheckBox box = new JCheckBox(); final CheckBoxItem item = items.get(i); boxes[i] = box; box.setHorizontalAlignment(SwingConstants.LEFT); box.setSelected(item.isSelected()); box.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { item.setSelected(box.isSelected()); fireListeners(); } }); } // set customer item renderer for the checkboxes CustomTableItemRenderer<JCheckBox> renderer = new CustomTableItemRenderer(boxes); TableColumn checkBoxCol = table.getColumnModel().getColumn(checkboxCol); checkBoxCol.setCellEditor(renderer); checkBoxCol.setCellRenderer(renderer); checkBoxCol.setMaxWidth(checkboxSize.width); } public synchronized void showHideAll(boolean showAll){ if(boxes!=null){ disableListeners = true; for(JCheckBox box:boxes){ box.setSelected(showAll); } disableListeners = false; fireListeners(); } repaint(); } public void addCheckChangedListener(CheckChangedListener listener){ checkChangedListeners.add(listener); } public void removeCheckChangedListener(CheckChangedListener listener){ checkChangedListeners.remove(listener); } public void addButtonClickedListener(ButtonClickedListener listener){ buttonClickedListeners.add(listener); } public void removeButtonClickedListener(ButtonClickedListener listener){ buttonClickedListeners.remove(listener); } public static void main(String[]args){ InitialiseStudio.initialise(false); // for(boolean showImage : new boolean[]{true,false}){ JPanel panel = new JPanel(); ArrayList<CheckBoxItem> items = new ArrayList<>(); items.add(new CheckBoxItemImpl(ImageUtils.createBlankImage(20, 20, Color.RED),"one")); items.add(new CheckBoxItemImpl(ImageUtils.createBlankImage(20, 20, Color.GREEN),"two")); items.add(new CheckBoxItemImpl(ImageUtils.createBlankImage(20, 20, Color.BLUE),"three")); CheckboxTable table = new CheckboxTable(new Icon[]{Icons.loadFromStandardPath("legend-zoom-best.png")},new Dimension(20, 20), items); panel.setLayout(new BorderLayout()); panel.add(table, BorderLayout.CENTER); ShowPanel.showPanel(panel,false); // } } public List<? extends CheckBoxItem> getItems(){ return items; } private void fireListeners() { if(!disableListeners){ for(CheckChangedListener listener : checkChangedListeners){ listener.checkStateChanged(); } } } }