package org.openslx.dozmod.gui.changemonitor; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Comparator; import javax.swing.JTable; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.TableModel; /** * Monitoring a JTable etc. */ class TableWrapper extends AbstractControlWrapper { private static final Comparator COMPARATOR = new Comparator() { public int compare(ClonedTableModel o1, ClonedTableModel o2) { if (o1 == null && o2 == null) return 0; if (o1 == null) return -o2.rowCount; if (o2 == null) return o1.rowCount; if (o1.rowCount != o2.rowCount) return o2.rowCount - o1.rowCount; if (o1.columnCount != o2.columnCount) return o2.columnCount - o1.columnCount; for (int i = 0; i < o1.grid.length; ++i) { Object c1 = o1.grid[i]; Object c2 = o2.grid[i]; if (c1 == c2) continue; if (c1 == null) return c2.hashCode(); if (c2 == null) return c1.hashCode(); if (c1.equals(c2)) continue; return c1.hashCode() - c2.hashCode(); } return 0; } }; private final JTable component; public TableWrapper(DialogChangeMonitor dcm, JTable table) { super(dcm, COMPARATOR); this.component = table; final TableModelListener changeListener = new TableModelListener() { public void tableChanged(TableModelEvent e) { contentChanged(); } }; // Make sure we notice when the whole model changes table.addPropertyChangeListener("model", new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { Object o = evt.getOldValue(); Object n = evt.getNewValue(); if (o != null && o instanceof TableModel) { ((TableModel)o).removeTableModelListener(changeListener); } if (n != null && n instanceof TableModel) { ((TableModel)n).addTableModelListener(changeListener); } } }); // Add listener to the current model if (table.getModel() != null) { table.getModel().addTableModelListener(changeListener); } } ClonedTableModel getCurrentValue() { TableModel model = component.getModel(); if (model == null) return null; return new ClonedTableModel(model); } } class ClonedTableModel implements TableModel { protected final Object[] grid; protected final int columnCount, rowCount; protected ClonedTableModel(TableModel other) { columnCount = other.getColumnCount(); rowCount = other.getRowCount(); grid = new Object[columnCount * rowCount]; for (int y = 0; y < rowCount; ++y) { for (int x = 0; x < columnCount; ++x) { // Hopefully we mostly deal with imutable types so we don't need clone grid[y * columnCount + x] = other.getValueAt(y, x); } } } @Override public int getRowCount() { return rowCount; } @Override public int getColumnCount() { return columnCount; } @Override public String getColumnName(int columnIndex) { return null; } @Override public Class getColumnClass(int columnIndex) { if (grid[columnIndex] == null) return Object.class; return grid[columnIndex].getClass(); } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return false; } @Override public Object getValueAt(int rowIndex, int columnIndex) { return grid[rowIndex * rowCount + columnCount]; } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { throw new RuntimeException("A cloned table model is read only"); } @Override public void addTableModelListener(TableModelListener l) { throw new RuntimeException("A cloned table model is read only"); } @Override public void removeTableModelListener(TableModelListener l) { throw new RuntimeException("A cloned table model is read only"); } }