package nl.tudelft.simulation.introspection.gui; import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyListener; import java.util.Collection; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumnModel; import nl.tudelft.simulation.introspection.mapping.CellPresentationConfiguration; import nl.tudelft.simulation.introspection.mapping.DefaultConfiguration; import nl.tudelft.simulation.introspection.sortable.SortDefinition; import nl.tudelft.simulation.introspection.sortable.SortingTableHeader; /** * * A customization of a standard JTable to allow the display of an introspected object. The behaviour of the * ObjectJTable depends on the contained TableModel. {see ObjectTableModel}provides a view of the properties and values * of a single introspected object. {see CollectionTableModel}provides a view on a collection of instances: usually the * value of a composite property. *

* A configuration mechanism is implemented to load the editors and renders to be used by this JTable. See {see * #setConfig(nl.tudelft.simulation.introspection.mapping.CellPresentationConfiguration)} for details. *

* copyright (c) 2002-2018 Delft University of Technology.
* BSD-style license. See DSOL License.
* @author Peter Jacobs. * @author Alexander Verbraeck. * @author Niels Lang. * @since 1.5 */ public class ObjectJTable extends JTable implements ObjectJTableInterface, ICellPresentationConfigProvider { /** */ private static final long serialVersionUID = 20140831L; /** the updateTimer. */ private static UpdateTimer updateTimer = new UpdateTimer(100L); /** hasShown? */ protected boolean hasShown = false; /** the introspectionTableModel. */ private IntrospectingTableModelInterface introspectionTableModel; /** * The configuration used to assign renderers and editors to cells. */ private final CellPresentationConfiguration CONFIG; /** * constructs a new ObjectJTable. * @param dm the defaultTableModel */ public ObjectJTable(final IntrospectingTableModelInterface dm) { this(dm, DefaultConfiguration.getDefaultConfiguration()); } /** * constructs a new ObjectJTable. * @param dm the defaultTableModel * @param config the CellPresentationConfiguration */ public ObjectJTable(final IntrospectingTableModelInterface dm, final CellPresentationConfiguration config) { super(new SortingObjectTableModel(dm)); this.CONFIG = config; init(dm); } /** * Constructor for ObjectJTable. * @param dm the defaultTableModel * @param cm the tableColumnModel */ public ObjectJTable(final IntrospectingTableModelInterface dm, final TableColumnModel cm) { super(new SortingObjectTableModel(dm), cm); this.CONFIG = DefaultConfiguration.getDefaultConfiguration(); init(dm); } /** * Constructor for ObjectJTable. * @param dm the defaultTableModel * @param cm the tableColumnModel * @param sm the listSelectionModel */ public ObjectJTable(final IntrospectingTableModelInterface dm, final TableColumnModel cm, final ListSelectionModel sm) { super(new SortingObjectTableModel(dm), cm, sm); this.CONFIG = DefaultConfiguration.getDefaultConfiguration(); init(dm); } /** {@inheritDoc} */ @Override public CellPresentationConfiguration getCellPresentationConfiguration() { return this.CONFIG; } /** * initializes the objectJTable. * @param model the model */ private void init(IntrospectingTableModelInterface model) { this.introspectionTableModel = model; initConfig(); setPreferredScrollableViewportSize(this.getPreferredSize()); JTableHeader header = new SortingTableHeader(new SortDefinition[]{new SortDefinition(0, true)}); this.setTableHeader(header); header.setColumnModel(this.getColumnModel()); ObjectJTable.updateTimer.add(this); } /** * Enables the installation of a special renderer for arrays and Collections. * @see javax.swing.JTable#getDefaultRenderer(java.lang.Class) */ @Override public TableCellRenderer getDefaultRenderer(Class columnClass) { if (columnClass.isArray()) return super.getDefaultRenderer(Object[].class); if (Collection.class.isAssignableFrom(columnClass)) return super.getDefaultRenderer(Collection.class); return super.getDefaultRenderer(columnClass); } /** * the ParentListener. */ protected class ParentListener implements HierarchyListener { /** {@inheritDoc} */ @Override public void hierarchyChanged(final HierarchyEvent e) { if (e.getChangeFlags() == HierarchyEvent.DISPLAYABILITY_CHANGED) { if (!ObjectJTable.this.hasShown && isDisplayable()) { ObjectJTable.this.hasShown = true; return; } if (ObjectJTable.this.hasShown && !isDisplayable()) { ObjectJTable.this.getModel().removeTableModelListener(ObjectJTable.this); } } } } /** * Initializes the configuration, by propagating its settings to the table's set of default renderers/editors. */ private void initConfig() { addHierarchyListener(new ParentListener()); Class[][] renderers = this.CONFIG.getRenderers(); Class[][] editors = this.CONFIG.getEditors(); try { for (int i = 0; i < renderers.length; i++) { this.setDefaultRenderer(renderers[i][0], (TableCellRenderer) renderers[i][1].newInstance()); } for (int i = 0; i < editors.length; i++) { this.setDefaultEditor(editors[i][0], (TableCellEditor) editors[i][1].newInstance()); } } catch (Exception e) { throw new IllegalArgumentException("Configuration " + this.CONFIG + "failed, " + "probably invalid classes."); } this.getColumn(getColumnName(0)).setPreferredWidth(70); this.getColumn(getColumnName(1)).setMaxWidth(25); this.getColumn(getColumnName(2)).setPreferredWidth(450); this.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); } /** {@inheritDoc} */ @Override public IntrospectingTableModelInterface getIntrospectingTableModel() { return this.introspectionTableModel; } }