package com.vistatec.ocelot.rules; import java.awt.Component; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumnModel; import com.vistatec.ocelot.ui.OTable; import com.vistatec.ocelot.ui.TableRowToggleMouseAdapter; /** * Class that wraps a {@link JTable} that contains rule information * and checkboxes to select them. */ public abstract class FilterViewTable { private JTable table; private AbstractTableModel tableModel; private RuleConfiguration ruleConfig; private boolean allowSelection; public FilterViewTable(RuleConfiguration ruleConfig) { this.table = createFilterViewTable(); this.ruleConfig = ruleConfig; this.allowSelection = getInitialAllowSelection(); } public JTable getTable() { return table; } protected RuleConfiguration getConfig() { return ruleConfig; } protected abstract boolean getInitialAllowSelection(); protected abstract AbstractTableModel getTableModel(); protected JTable createFilterViewTable() { tableModel = getTableModel(); JTable table = new OTable(tableModel); table.setTableHeader(null); table.setCellSelectionEnabled(false); table.setShowGrid(false); table.setDefaultRenderer(Boolean.class, new GreyableCheckboxRenderer()); table.setDefaultRenderer(DataCategoryFlag.class, new DataCategoryFlagRenderer()); // Add a little little breathing room, particularly around the edge table.setRowHeight(table.getRowHeight() + 4); TableColumnModel columnModel = table.getColumnModel(); // Hack - size the column to fit a checkbox exactly. Otherwise // there's a rendering glitch where the checkbox can jump around // in the cell when clicked. JCheckBox cb = new JCheckBox(); int cbWidth = cb.getPreferredSize().width + 4; columnModel.getColumn(0).setMinWidth(cbWidth); columnModel.getColumn(0).setPreferredWidth(cbWidth); columnModel.getColumn(0).setMaxWidth(cbWidth); columnModel.getColumn(1).setMinWidth(100); columnModel.getColumn(1).setPreferredWidth(325); columnModel.getColumn(1).setMaxWidth(325); columnModel.getColumn(2).setMinWidth(25); columnModel.getColumn(2).setPreferredWidth(25); columnModel.getColumn(2).setMaxWidth(25); table.addMouseListener(new TableRowToggleMouseAdapter() { @Override protected boolean acceptEvent(int row, int column) { return (allowSelection && column > 0); } }); return table; } public void setAllowSelection(boolean allowSelection) { this.allowSelection = allowSelection; tableModel.fireTableDataChanged(); } class GreyableCheckboxRenderer extends JCheckBox implements TableCellRenderer { private static final long serialVersionUID = 1L; @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { this.setEnabled(allowSelection); setHorizontalAlignment(JLabel.CENTER); if (value instanceof Boolean) { this.setSelected((Boolean)value); } return this; } } abstract class FilterTableModel extends AbstractTableModel { private static final long serialVersionUID = 1L; @Override public int getColumnCount() { return 3; } @Override public boolean isCellEditable(int row, int column) { return allowSelection && column == 0; } @Override public abstract int getRowCount(); @Override public abstract Object getValueAt(int row, int column); @Override public Class<?> getColumnClass(int columnIndex) { switch (columnIndex) { case 0: return Boolean.class; case 1: return String.class; case 2: return DataCategoryFlag.class; } throw new IllegalArgumentException("Invalid column " + columnIndex); } @Override public abstract void setValueAt(Object obj, int row, int column); } }