- /*
- * @(#)JTable.java 1.121 01/11/29
- *
- * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
- package javax.swing;
- import java.util.*;
- import java.awt.*;
- import java.awt.event.*;
- import java.beans.*;
- import java.io.Serializable;
- import java.io.ObjectOutputStream;
- import java.io.ObjectInputStream;
- import java.io.IOException;
- import javax.accessibility.*;
- import javax.swing.event.*;
- import javax.swing.plaf.*;
- import javax.swing.table.*;
- import javax.swing.border.*;
- import java.text.DateFormat;
- import java.text.NumberFormat;
- /**
- * JTable is a user-interface component that presents data in a two-dimensional
- * table format. The JTable has many facilities that make it possible to
- * customize its rendering and editing but provides defaults
- * for these features so that simple tables can be set up easily.
- * For example, to set up a table with 10 rows and 10 columns of numbers:
- * <p>
- * <pre>
- * TableModel dataModel = new AbstractTableModel() {
- * public int getColumnCount() { return 10; }
- * public int getRowCount() { return 10;}
- * public Object getValueAt(int row, int col) { return new Integer(row*col); }
- * };
- * JTable table = new JTable(dataModel);
- * JScrollPane scrollpane = new JScrollPane(table);
- * </pre>
- * <p>
- * Because the JTable is now much easier to set up with custom models
- * the DefaultTableModel is less useful than it was in previous releases.
- * Instead of copying the data in an application into the DefaultTableModel,
- * we recommend wrapping it in the methods of the TableModel interface and
- * passing the real data to the JTable as above. This technique is nearly as concise
- * as using a DefaultTableModel and starting this way has a number of advantages
- * over the longer term. In particular: it is a scalable technique,
- * is easier to handle dynamic or editable tables and often results in much
- * more efficient applications because the model is free to choose the
- * internal representation that best suits the data.
- * <p>
- * The "Table" directory in the examples/demo area gives a number of complete
- * examples of JTable usage, covering how the JTable can be used to provide
- * an editable view of data taken from a database and how to modify the columns
- * in the display to use specialized renderers and editors. For example, overriding
- * AbstractTableModel's <code>getColumnClass()</code> method to return a value of
- * <code>ImageIcon.class</code> for a given column allows icons to be displayed,
- * while returning a value of <code>Number.class</code> allows digits to be
- * right-justified in the column.
- * <p>
- * The JTable uses integers exclusively to refer to both the rows and the columns
- * of the model that it displays. The JTable simply takes a tabular range of cells
- * and uses <code>getValueAt(int, int)</code> to retrieve and display the appropriate
- * values from the model.
- * <p>
- * If <code>getTableHeader().setReorderingAllowed(boolean)</code> is used to
- * enable column reordering columns may be rearranged in the JTable so that the
- * view's columns appear in a different order to the columns in the model.
- * This does not affect the implementation of the model at all: when the
- * columns are reordered, the JTable maintains the new order of the columns
- * internally and converts its column indices before querying the model.
- * <p>
- * So, when writing a TableModel, it is not necessary to listen for column
- * reordering events as the the model will be queried in its own co-ordinate
- * system regardless of what is happening in the view.
- * In the examples area there is a demonstration of a sorting algorithm making
- * use of exactly this technique to interpose yet another co-ordinate system
- * where the order of the rows is changed, rather than the order of the columns.
- * <p>
- * The general rule for the JTable API and the APIs of all its associated classes,
- * including the the column model and both the row and column selection models, is:
- * methods using integer indices for rows and columns always use the co-ordinate
- * system of the view. There are three exceptions to this rule:
- * <ul>
- * <li> All references to rows and columns in the TableModel
- * interface are in the co-ordinate system of the model.
- * <li> The index <I>modelIndex</I> in the TableColumn constructors
- * refers to the index of the column in the model, not the view.
- * <li> All constructors for the TableModelEvent, which describes changes
- * that have taken place in a table model, use the co-ordinate system
- * of the model.
- * </ul>
- * The TableColumn provides a slot for holding an identifier or "tag" for each column
- * and the JTable and TableColumModel both support <I>getColumn(Object id)</I>
- * conveniences for locating columns by their identifier. If no identifier is
- * explicitly set, the TableColumn returns its header value (the name of the column)
- * as a default. A different identifier, which can be of any type, can be set
- * using the TableColumn's <I>setIdentifier()</I> method. All of the JTable's
- * functions operate correctly regardless of the type and uniqueness of these
- * identifiers.
- * <p>
- * The <I>convertColumnIndexToView()</I> and
- * <I>convertColumnIndexToModel()</I> methods have been provided to
- * convert between the two co-ordinate systems but
- * they are rarely needed during normal use.
- * <p>
- * Like all JComponent classes, you can use
- * {@link JComponent#registerKeyboardAction} to associate an
- * {@link Action} object with a {@link KeyStroke} and execute the
- * action under specified conditions.
- * <p>
- * See <a href="http://java.sun.com/docs/books/tutorial/ui/swing/table.html">How to Use Tables</a>
- * in <a href="http://java.sun.com/Series/Tutorial/index.html"><em>The Java Tutorial</em></a>
- * for further documentation.
- * <p>
- * For the keyboard keys used by this component in the standard Look and
- * Feel (L&F) renditions, see the
- * <a href="doc-files/Key-Index.html#JTable">JTable</a> key assignments.
- * <p>
- * <strong>Warning:</strong>
- * Serialized objects of this class will not be compatible with
- * future Swing releases. The current serialization support is appropriate
- * for short term storage or RMI between applications running the same
- * version of Swing. A future release of Swing will provide support for
- * long term persistence.
- *
- *
- * @beaninfo
- * attribute: isContainer false
- *
- * @version 1.121 11/29/01
- * @author Philip Milne
- * @author Alan Chung
- */
- public class JTable extends JComponent implements TableModelListener, Scrollable,
- TableColumnModelListener, ListSelectionListener, CellEditorListener,
- Accessible
- {
- //
- // Static Constants
- //
- /**
- * @see #getUIClassID
- * @see #readObject
- */
- private static final String uiClassID = "TableUI";
- /** Do not adjust column widths automatically, use a scrollbar */
- public static final int AUTO_RESIZE_OFF = 0;
- /** When a column is adjusted in the UI, adjust the next column the opposite way */
- public static final int AUTO_RESIZE_NEXT_COLUMN = 1;
- /** During UI adjustment, change subsequent columns to preserve the total width */
- public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
- /** During all resize operations, apply adjustments to the last column only */
- public static final int AUTO_RESIZE_LAST_COLUMN = 3;
- /** During all resize operations, proportionately resize all columns */
- public static final int AUTO_RESIZE_ALL_COLUMNS = 4;
- //
- // Instance Variables
- //
- /** The TableModel of the table */
- protected TableModel dataModel;
- /** The TableColumnModel of the table */
- protected TableColumnModel columnModel;
- /** The ListSelectionModel of the table, used to keep track of row selections */
- protected ListSelectionModel selectionModel;
- /** The TableHeader working with the table */
- protected JTableHeader tableHeader;
- /** The height of all rows in the table */
- protected int rowHeight;
- /** The height margin between rows */
- protected int rowMargin;
- /** The color of the grid */
- protected Color gridColor;
- /** The table draws horizontal lines between cells if showHorizontalLines is true */
- protected boolean showHorizontalLines;
- /** The table draws vertical lines between cells if showVerticalLines is true */
- protected boolean showVerticalLines;
- /**
- * This mode value determines if table automatically resizes the
- * width the table's columns to take up the entire width of the
- * table, and how it does the resizing.
- */
- protected int autoResizeMode;
- /**
- * The table will query the TableModel to build the default
- * set of columns if this is true.
- */
- protected boolean autoCreateColumnsFromModel;
- /** Used by the Scrollable interface to determine the initial visible area */
- protected Dimension preferredViewportSize;
- /** Row selection allowed in this table */
- protected boolean rowSelectionAllowed;
- /**
- * If this is true, then both a row selection and a column selection
- * can be non-empty at the same time, the selected cells are the
- * the cells whose row and column are both selected.
- */
- protected boolean cellSelectionEnabled;
- /** If editing, Component that is handling the editing. */
- transient protected Component editorComp;
- /**
- * The object that overwrites the screen real estate occupied by the
- * current cell and allows the user to change those contents.
- */
- transient protected TableCellEditor cellEditor;
- /** Identifies the column of the cell being edited. */
- transient protected int editingColumn;
- /** Identifies the row of the cell being edited. */
- transient protected int editingRow;
- /**
- * A table of objects that display the contents of a cell,
- * indexed by class.
- */
- transient protected Hashtable defaultRenderersByColumnClass;
- /**
- * A table of objects that display and edit the contents of a cell,
- * indexed by class.
- */
- transient protected Hashtable defaultEditorsByColumnClass;
- /** The foreground color of selected cells */
- protected Color selectionForeground;
- /** The background color of selected cells */
- protected Color selectionBackground;
- //
- // Constructors
- //
- /**
- * Constructs a default JTable which is initialized with a default
- * data model, a default column model, and a default selection
- * model.
- *
- * @see #createDefaultDataModel
- * @see #createDefaultColumnModel
- * @see #createDefaultSelectionModel
- */
- public JTable() {
- this(null, null, null);
- }
- /**
- * Constructs a JTable which is initialized with <i>dm</i> as the
- * data model, a default column model, and a default selection
- * model.
- *
- * @param dm The data model for the table
- * @see #createDefaultColumnModel
- * @see #createDefaultSelectionModel
- */
- public JTable(TableModel dm) {
- this(dm, null, null);
- }
- /**
- * Constructs a JTable which is initialized with <i>dm</i> as the
- * data model, <i>cm</i> as the column model, and a default selection
- * model.
- *
- * @param dm The data model for the table
- * @param cm The column model for the table
- * @see #createDefaultSelectionModel
- */
- public JTable(TableModel dm, TableColumnModel cm) {
- this(dm, cm, null);
- }
- /**
- * Constructs a JTable which is initialized with <i>dm</i> as the
- * data model, <i>cm</i> as the column model, and <i>sm</i> as the
- * selection model. If any of the parameters are <b>null</b> this
- * method will initialize the table with the corresponding
- * default model. The <i>autoCreateColumnsFromModel</i> flag is set
- * to false if <i>cm</i> is non-null, otherwise it is set to true
- * and the column model is populated with suitable TableColumns
- * for the columns in <i>dm</i>.
- *
- * @param dm The data model for the table
- * @param cm The column model for the table
- * @param sm The row selection model for the table
- * @see #createDefaultDataModel
- * @see #createDefaultColumnModel
- * @see #createDefaultSelectionModel
- */
- public JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
- super();
- setLayout(null);
- if (cm == null) {
- cm = createDefaultColumnModel();
- autoCreateColumnsFromModel = true;
- }
- setColumnModel(cm);
- if (sm == null)
- sm = createDefaultSelectionModel();
- setSelectionModel(sm);
- // Set the model last, that way if the autoCreatColumnsFromModel has
- // been set above, we will automatically populate an empty columnModel
- // with suitable columns for the new model.
- if (dm == null)
- dm = createDefaultDataModel();
- setModel(dm);
- initializeLocalVars();
- updateUI();
- }
- /**
- * Constructs a JTable with <i>numRows</i> and <i>numColumns</i> of
- * empty cells using the DefaultTableModel. The columns will have
- * names of the form "A", "B", "C", etc.
- *
- * @param numRows The number of rows the table holds
- * @param numColumns The number of columns the table holds
- * @see javax.swing.table.DefaultTableModel
- */
- public JTable(int numRows, int numColumns) {
- this(new DefaultTableModel(numRows, numColumns));
- }
- /**
- * Constructs a JTable to display the values in the Vector of Vectors,
- * <i>rowData</i>, with column names, <i>columnNames</i>.
- * The Vectors contained in <i>rowData</i> should contain the values
- * for that row. In other words, the value of the cell at row 1,
- * column 5 can be obtained with the following code:
- * <p>
- * <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
- * <p>
- * All rows must be of the same length as <i>columnNames</i>.
- * <p>
- * @param rowData The data for the new table
- * @param columnNames Names of each column
- */
- public JTable(final Vector rowData, final Vector columnNames) {
- this(new AbstractTableModel() {
- public String getColumnName(int column) { return columnNames.elementAt(column).toString(); }
- public int getRowCount() { return rowData.size(); }
- public int getColumnCount() { return columnNames.size(); }
- public Object getValueAt(int row, int column) {
- return ((Vector)rowData.elementAt(row)).elementAt(column);
- }
- public boolean isCellEditable(int row, int column) { return true; }
- public void setValueAt(Object value, int row, int column) {
- ((Vector)rowData.elementAt(row)).setElementAt(value, column);
- fireTableCellUpdated(row, column);
- }
- });
- }
- /**
- * Constructs a JTable to display the values in the two dimensional array,
- * <i>rowData</i>, with column names, <i>columnNames</i>.
- * <i>rowData</i> is an Array of rows, so the value of the cell at row 1,
- * column 5 can be obtained with the following code:
- * <p>
- * <pre> rowData[1][5]; </pre>
- * <p>
- * All rows must be of the same length as <i>columnNames</i>.
- * <p>
- * @param rowData The data for the new table
- * @param columnNames Names of each column
- */
- public JTable(final Object[][] rowData, final Object[] columnNames) {
- this(new AbstractTableModel() {
- public String getColumnName(int column) { return columnNames[column].toString(); }
- public int getRowCount() { return rowData.length; }
- public int getColumnCount() { return columnNames.length; }
- public Object getValueAt(int row, int col) { return rowData[row][col]; }
- public boolean isCellEditable(int row, int column) { return true; }
- public void setValueAt(Object value, int row, int col) {
- rowData[row][col] = value;
- fireTableCellUpdated(row, col);
- }
- });
- }
- /**
- * Calls <code>configureEnclosingScrollPane</code>.
- *
- * @see #configureEnclosingScrollPane
- */
- public void addNotify() {
- super.addNotify();
- configureEnclosingScrollPane();
- }
- /**
- * If the JTable is the viewportView of an enclosing JScrollPane
- * (the usual situation), configure this ScrollPane by, amongst other things,
- * installing the table's tableHeader as the columnHeaderView of the scrollpane.
- * When a JTable is added to a JScrollPane in the usual way,
- * using <code>new JScrollPane(myTable)</code>, <code>addNotify</code> is
- * called in the JTable (when the table is added to the viewport).
- * JTable's <code>addNotify</code> method in turn calls this method
- * which is protected so that this default installation procedure can
- * be overridden by a subclass.
- *
- * @see #addNotify
- */
- protected void configureEnclosingScrollPane() {
- Container p = getParent();
- if (p instanceof JViewport) {
- Container gp = p.getParent();
- if (gp instanceof JScrollPane) {
- JScrollPane scrollPane = (JScrollPane)gp;
- // Make certain we are the viewPort's view and not, for
- // example, the rowHeaderView of the scrollPane -
- // an implementor of fixed columns might do this.
- JViewport viewport = scrollPane.getViewport();
- if (viewport == null || viewport.getView() != this) {
- return;
- }
- scrollPane.setColumnHeaderView(getTableHeader());
- scrollPane.getViewport().setBackingStoreEnabled(true);
- Border border = scrollPane.getBorder();
- if (border == null || border instanceof UIResource) {
- scrollPane.setBorder(UIManager.getBorder("Table.scrollPaneBorder"));
- }
- }
- }
- }
- //
- // Static Methods
- //
- /**
- * Equivalent to <code>new JScrollPane(aTable)</code>.
- *
- * @deprecated As of Swing version 1.0.2,
- * replaced by <code>new JScrollPane(aTable)</code>.
- */
- static public JScrollPane createScrollPaneForTable(JTable aTable) {
- return new JScrollPane(aTable);
- }
- //
- // Table Attributes
- //
- /**
- * Sets the tableHeader working with this JTable to <I>newHeader</I>.
- * It is legal to have a <B>null</B> tableHeader.
- *
- * @param newHeader new tableHeader
- * @see #getTableHeader
- * @beaninfo
- * description: The JTableHeader instance which renders the column headers.
- */
- public void setTableHeader(JTableHeader newHeader) {
- if (tableHeader != newHeader) {
- // Release the old header
- if (tableHeader != null)
- tableHeader.setTable(null);
- tableHeader = newHeader;
- if (tableHeader != null)
- tableHeader.setTable(this);
- }
- }
- /**
- * Returns the tableHeader working with this JTable.
- *
- * @return the tableHeader working with the receiver
- * @see #setTableHeader
- */
- public JTableHeader getTableHeader() {
- return tableHeader;
- }
- /**
- * Sets the height for rows to <I>newRowHeight</I> and invokes tile
- *
- * @param newRowHeight new row height
- * @exception IllegalArgumentException If <I>newRowHeight</I> is
- * less than 1.
- * @see #getRowHeight
- * @beaninfo
- * description: The height of the cells including the inter-cell spacing.
- */
- public void setRowHeight(int newHeight) {
- if (newHeight <= 0) {
- throw new IllegalArgumentException("New row height less than 1");
- }
- rowHeight = newHeight;
- resizeAndRepaint();
- }
- /**
- * Returns the height of a table row in the receiver.
- * The default row height is 16.0.
- *
- * @return the height of each row in the receiver
- * @see #setRowHeight
- */
- public int getRowHeight() {
- return rowHeight;
- }
- /**
- * Sets the amount of emtpy space between rows.
- *
- * @see #getRowMargin
- */
- public void setRowMargin(int rowMargin) {
- this.rowMargin = rowMargin;
- }
- /**
- * Gets the amount of emtpy space between rows. Equivalent to:
- * <code>getIntercellSpacing().height</code>.
- *
- * @see #setRowMargin
- */
- public int getRowMargin() {
- return rowMargin;
- }
- /**
- * Sets the width and height between cells to <I>newSpacing</I> and
- * redisplays the receiver.
- *
- * @param newSpacing The new width and height intercellSpacing
- * @see #getIntercellSpacing
- * @beaninfo
- * description: The spacing between the cells, drawn in the background color of the JTable.
- */
- public void setIntercellSpacing(Dimension newSpacing) {
- // Set the rowMargin here and columnMargin in the TableColumnModel
- rowMargin = newSpacing.height;
- getColumnModel().setColumnMargin(newSpacing.width);
- resizeAndRepaint();
- }
- /**
- * Returns the horizontal and vertical spacing between cells.
- * The default spacing is (3, 2).
- *
- * @return the horizontal and vertical spacing between cells
- * @see #setIntercellSpacing
- */
- public Dimension getIntercellSpacing() {
- return new Dimension(getColumnModel().getColumnMargin(), rowMargin);
- }
- /**
- * Sets the color used to draw grid lines to <I>color</I> and redisplays
- * the receiver. The default color is gray.
- *
- * @param color new color of the grid
- * @exception IllegalArgumentException if <I>color</I> is null
- * @see #getGridColor
- */
- public void setGridColor(Color newColor) {
- if (newColor == null) {
- throw new IllegalArgumentException("New color is null");
- }
- gridColor = newColor;
- // Redraw
- repaint();
- }
- /**
- * Returns the color used to draw grid lines. The default color is gray.
- *
- * @return the color used to draw grid lines
- * @see #setGridColor
- */
- public Color getGridColor() {
- return gridColor;
- }
- /**
- * Sets whether the receiver draws grid lines around cells.
- * If <I>flag</I> is true it does; if it is false it doesn't.
- * There is no getShowGrid() method as the this state is held
- * in two variables: showHorizontalLines and showVerticalLines
- * each of which may be queried independently.
- *
- * @param flag true if table view should draw grid lines
- *
- * @see #setShowVerticalLines
- * @see #setShowHorizontalLines
- * @beaninfo
- * description: The color used to draw the grid lines.
- */
- public void setShowGrid(boolean b) {
- setShowHorizontalLines(b);
- setShowVerticalLines(b);
- // Redraw
- repaint();
- }
- /**
- * Sets whether the receiver draws horizontal lines between cells.
- * If <I>flag</I> is true it does; if it is false it doesn't.
- *
- * @param flag true if table view should draw horizontal lines
- * @see #getShowHorizontalLines
- * @see #setShowGrid
- * @see #setShowVerticalLines
- * @beaninfo
- * description: Whether horizontal lines should be drawn in between the cells.
- */
- public void setShowHorizontalLines(boolean b) {
- showHorizontalLines = b;
- // Redraw
- repaint();
- }
- /**
- * Sets whether the receiver draws vertical lines between cells.
- * If <I>flag</I> is true it does; if it is false it doesn't.
- *
- * @param flag true if table view should draw vertical lines
- * @see #getShowVerticalLines
- * @see #setShowGrid
- * @see #setShowHorizontalLines
- * @beaninfo
- * description: Whether vertical lines should be drawn in between the cells.
- */
- public void setShowVerticalLines(boolean b) {
- showVerticalLines = b;
- // Redraw
- repaint();
- }
- /**
- * Returns true if the receiver draws horizontal lines between cells, false if it
- * doesn't. The default is true.
- *
- * @return true if the receiver draws horizontal lines between cells, false if it
- * doesn't
- * @see #setShowHorizontalLines
- */
- public boolean getShowHorizontalLines() {
- return showHorizontalLines;
- }
- /**
- * Returns true if the receiver draws vertical lines between cells, false if it
- * doesn't. The default is true.
- *
- * @return true if the receiver draws vertical lines between cells, false if it
- * doesn't
- * @see #setShowVerticalLines
- */
- public boolean getShowVerticalLines() {
- return showVerticalLines;
- }
- /**
- * Sets the table's auto resize mode when the table is resized.
- *
- * @param mode One of 5 legal values:
- * AUTO_RESIZE_OFF,
- * AUTO_RESIZE_NEXT_COLUMN,
- * AUTO_RESIZE_SUBSEQUENT_COLUMNS,
- * AUTO_RESIZE_LAST_COLUMN,
- * AUTO_RESIZE_ALL_COLUMNS
- *
- * @see #getAutoResizeMode
- * @see #sizeColumnsToFit(int)
- * @beaninfo
- * description: Whether the columns should adjust themselves automatically.
- * enum: AUTO_RESIZE_OFF JTable.AUTO_RESIZE_OFF
- * AUTO_RESIZE_NEXT_COLUMN JTable.AUTO_RESIZE_NEXT_COLUMN
- * AUTO_RESIZE_SUBSEQUENT_COLUMNS JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS
- * AUTO_RESIZE_LAST_COLUMN JTable.AUTO_RESIZE_LAST_COLUMN
- * AUTO_RESIZE_ALL_COLUMNS JTable.AUTO_RESIZE_ALL_COLUMNS
- */
- public void setAutoResizeMode(int mode) {
- if ((mode == AUTO_RESIZE_OFF) ||
- (mode == AUTO_RESIZE_NEXT_COLUMN) ||
- (mode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) ||
- (mode == AUTO_RESIZE_LAST_COLUMN) ||
- (mode == AUTO_RESIZE_ALL_COLUMNS)) {
- autoResizeMode = mode;
- resizeAndRepaint();
- if (tableHeader != null) {
- tableHeader.resizeAndRepaint();
- }
- }
- }
- /**
- * Returns auto resize mode of the table.
- *
- * @return the autoResizeMode of the table
- *
- * @see #setAutoResizeMode
- * @see #sizeColumnsToFit(int)
- */
- public int getAutoResizeMode() {
- return autoResizeMode;
- }
- /**
- * Sets the table's autoCreateColumnsFromModel flag. This method
- * will call createDefaultColumnsFromModel() if <i>createColumns</i>
- * is true.
- *
- * @param createColumns true if JTable should auto create columns
- * @see #getAutoCreateColumnsFromModel
- * @see #createDefaultColumnsFromModel
- * @beaninfo
- * description: Automatically populate the columnModel when a new TableModel is submitted.
- */
- public void setAutoCreateColumnsFromModel(boolean createColumns) {
- if (autoCreateColumnsFromModel != createColumns) {
- autoCreateColumnsFromModel = createColumns;
- if (autoCreateColumnsFromModel)
- createDefaultColumnsFromModel();
- }
- }
- /**
- * Returns whether the table will create default columns from the model.
- * If this is true, setModel() will clear any existing columns and
- * create new columns from the new model. Also if the event in the
- * the tableChanged() notification specified the entired table changed
- * then the columns will be rebuilt. The default is true.
- *
- * @return the autoCreateColumnsFromModel of the table
- * @see #setAutoCreateColumnsFromModel
- * @see #createDefaultColumnsFromModel
- */
- public boolean getAutoCreateColumnsFromModel() {
- return autoCreateColumnsFromModel;
- }
- /**
- * This method will create default columns for the table from
- * the data model using the getColumnCount() and getColumnClass() methods
- * defined in the TableModel interface.
- * <p>
- * This method will clear any exsiting columns before creating the
- * new columns based on information from the model.
- *
- * @see #getAutoCreateColumnsFromModel
- */
- public void createDefaultColumnsFromModel() {
- TableModel m = getModel();
- if (m != null) {
- // Remove any current columns
- TableColumnModel cm = getColumnModel();
- cm.removeColumnModelListener(this);
- while (cm.getColumnCount() > 0)
- cm.removeColumn(cm.getColumn(0));
- // Create new columns from the data model info
- for (int i = 0; i < m.getColumnCount(); i++) {
- TableColumn newColumn = new TableColumn(i);
- addColumn(newColumn);
- }
- cm.addColumnModelListener(this);
- }
- }
- /**
- * Set a default renderer to be used if no renderer has been set in
- * a TableColumn. If renderer is null, remove the default renderer
- * for this column class.
- *
- * @see #getDefaultRenderer
- * @see #setDefaultEditor
- */
- public void setDefaultRenderer(Class columnClass, TableCellRenderer renderer) {
- if (renderer != null) {
- defaultRenderersByColumnClass.put(columnClass, renderer);
- }
- else {
- defaultRenderersByColumnClass.remove(columnClass);
- }
- }
- /**
- * Returns the renderer to be used when no renderer has been set in
- * a TableColumn. During the rendering of cells the renderer is fetched from
- * a Hashtable of entries according to the class of the cells in the column. If
- * there is no entry for this <I>columnClass</I> the method returns
- * the entry for the most specific superclass. The JTable installs entries
- * for <I>Object</I>, <I>Number</I> and <I>Boolean</I> all which can be modified
- * or replaced.
- *
- * @see #setDefaultRenderer
- * @see #getColumnClass
- */
- public TableCellRenderer getDefaultRenderer(Class columnClass) {
- if (columnClass == null) {
- return null;
- }
- else {
- Object renderer = defaultRenderersByColumnClass.get(columnClass);
- if (renderer != null) {
- return (TableCellRenderer)renderer;
- }
- else {
- return getDefaultRenderer(columnClass.getSuperclass());
- }
- }
- }
- /**
- * Set a default editor to be used if no editor has been set in
- * a TableColumn. If no editing is required in a table, or a
- * particular column in a table, use the isCellEditable()
- * method in the TableModel interface to ensure that the
- * JTable will not start an editor in these columns.
- * If editor is null, remove the default editor for this
- * column class.
- *
- * @see TableModel#isCellEditable
- * @see #getDefaultEditor
- * @see #setDefaultRenderer
- */
- public void setDefaultEditor(Class columnClass, TableCellEditor editor) {
- if (editor != null) {
- defaultEditorsByColumnClass.put(columnClass, editor);
- }
- else {
- defaultEditorsByColumnClass.remove(columnClass);
- }
- }
- /**
- * Returns the editor to be used when no editor has been set in
- * a TableColumn. During the editing of cells the editor is fetched from
- * a Hashtable of entries according to the class of the cells in the column. If
- * there is no entry for this <I>columnClass</I> the method returns
- * the entry for the most specific superclass. The JTable installs entries
- * for <I>Object</I>, <I>Number</I> and <I>Boolean</I> all which can be modified
- * or replaced.
- *
- * @see #setDefaultEditor
- * @see #getColumnClass
- */
- public TableCellEditor getDefaultEditor(Class columnClass) {
- if (columnClass == null) {
- return null;
- }
- else {
- Object editor = defaultEditorsByColumnClass.get(columnClass);
- if (editor != null) {
- return (TableCellEditor)editor;
- }
- else {
- return getDefaultEditor(columnClass.getSuperclass());
- }
- }
- }
- //
- // Selection methods
- //
- /**
- * Sets the table's selection mode to allow only single selections, a single
- * contiguous interval, or multiple intervals.
- *
- * NOTE:<br>
- * JTable provides all the methods for handling column and row selection.
- * When setting states, such as setSelectionMode, it not only
- * updates the mode for the row selection model but also sets similar
- * values in the selection model of the columnModel.
- * If you want to have the row and column selection models operating
- * in different modes, set them both directly.
- * <p>
- * Both the row and column selection models for the JTable default
- * to using a DefaultListSelectionModel so that JTable works the same
- * way as the JList. See setSelectionMode() in JList for details
- * about the modes.
- *
- * @see JList#setSelectionMode
- * @beaninfo
- * description: The selection mode used by the row and column selection models.
- * enum: SINGLE_SELECTION ListSelectionModel.SINGLE_SELECTION
- * SINGLE_INTERVAL_SELECTION ListSelectionModel.SINGLE_INTERVAL_SELECTION
- * MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
- */
- public void setSelectionMode(int selectionMode) {
- clearSelection();
- getSelectionModel().setSelectionMode(selectionMode);
- getColumnModel().getSelectionModel().setSelectionMode(selectionMode);
- }
- /**
- * Sets whether the rows in this model can be selected.
- *
- * @see #getRowSelectionAllowed
- * @beaninfo
- * description: If true, an entire row is selected for each selected cell.
- */
- public void setRowSelectionAllowed(boolean flag) {
- rowSelectionAllowed = flag;
- }
- /**
- * Returns true if rows can be selected.
- *
- * @return true if rows can be selected
- * @see #setRowSelectionAllowed
- */
- public boolean getRowSelectionAllowed() {
- return rowSelectionAllowed;
- }
- /**
- * Sets whether the columns in this model can be selected.
- *
- * @see #getColumnSelectionAllowed
- * @beaninfo
- * description: If true, an entire column is selected for each selected cell.
- */
- public void setColumnSelectionAllowed(boolean flag) {
- columnModel.setColumnSelectionAllowed(flag);
- }
- /**
- * Returns true if columns can be selected.
- *
- * @return true if columns can be selected.
- * @see #setColumnSelectionAllowed
- */
- public boolean getColumnSelectionAllowed() {
- return columnModel.getColumnSelectionAllowed();
- }
- /**
- * Sets whether this table allows both a column selection and a
- * row selection to exist at the same time. When set, this results
- * in a facility to select a rectangular region of cells in the display.
- * This flag over-rides the row and column selection
- * modes ensuring that cell selection is possible whenever this flag is set.
- * @see #getCellSelectionEnabled
- * @beaninfo
- * description: Select a rectangular region of cells rather than rows or columns.
- */
- public void setCellSelectionEnabled(boolean flag) {
- cellSelectionEnabled = flag;
- }
- /**
- * Returns true if simultaneous row and column selections are allowed
- *
- * @return true if simultaneous row and column selections are allowed
- * @see #setCellSelectionEnabled
- */
- public boolean getCellSelectionEnabled() {
- return cellSelectionEnabled;
- }
- /**
- * Select all rows, columns and cells in the table.
- */
- public void selectAll() {
- // If I'm currently editing, then I should stop editing
- if (isEditing()) {
- removeEditor();
- }
- setRowSelectionInterval(0, getRowCount()-1);
- setColumnSelectionInterval(0, getColumnCount()-1);
- }
- /**
- * Deselects all selected columns and rows.
- */
- public void clearSelection() {
- columnModel.getSelectionModel().clearSelection();
- selectionModel.clearSelection();
- }
- /**
- * Selects the rows from <i>index0</i> to <i>index1</i> inclusive.
- *
- * @param index0 one end of the interval.
- * @param index1 other end of the interval
- */
- public void setRowSelectionInterval(int index0, int index1) {
- selectionModel.setSelectionInterval(index0, index1);
- }
- /**
- * Selects the columns from <i>index0</i> to <i>index1</i> inclusive.
- *
- * @param index0 one end of the interval.
- * @param index1 other end of the interval
- */
- public void setColumnSelectionInterval(int index0, int index1) {
- columnModel.getSelectionModel().setSelectionInterval(index0, index1);
- }
- /**
- * Adds the rows from <i>index0</i> to <i>index0</i> inclusive to
- * the current selection.
- *
- * @param index0 one end of the interval.
- * @param index1 other end of the interval
- */
- public void addRowSelectionInterval(int index0, int index1) {
- selectionModel.addSelectionInterval(index0, index1);
- }
- /**
- * Adds the columns from <i>index0</i> to <i>index0</i> inclusive to
- * the current selection.
- *
- * @param index0 one end of the interval.
- * @param index1 other end of the interval
- */
- public void addColumnSelectionInterval(int index0, int index1) {
- columnModel.getSelectionModel().addSelectionInterval(index0, index1);
- }
- /**
- * Deselects the rows from <i>index0</i> to <i>index0</i> inclusive.
- *
- * @param index0 one end of the interval.
- * @param index1 other end of the interval
- */
- public void removeRowSelectionInterval(int index0, int index1) {
- selectionModel.removeSelectionInterval(index0, index1);
- }
- /**
- * Deselects the columns from <i>index0</i> to <i>index0</i> inclusive.
- *
- * @param index0 one end of the interval.
- * @param index1 other end of the interval
- */
- public void removeColumnSelectionInterval(int index0, int index1) {
- columnModel.getSelectionModel().removeSelectionInterval(index0, index1);
- }
- /**
- * Returns the index of the first selected row, -1 if no row is selected.
- */
- public int getSelectedRow() {
- return selectionModel.getMinSelectionIndex();
- }
- /**
- * Returns the index of the first selected column, -1 if no column is selected.
- */
- public int getSelectedColumn() {
- return columnModel.getSelectionModel().getMinSelectionIndex();
- }
- /**
- * Returns the indices of all selected rows.
- *
- * @return an array of ints containing the indices of all selected rows,
- * or an empty array if no row is selected.
- * @see #getSelectedRow
- */
- public int[] getSelectedRows() {
- if (selectionModel != null) {
- int iMin = selectionModel.getMinSelectionIndex();
- int iMax = selectionModel.getMaxSelectionIndex();
- if ((iMin == -1) || (iMax == -1)) {
- return new int[0];
- }
- int[] rvTmp = new int[1+ (iMax - iMin)];
- int n = 0;
- for(int i = iMin; i <= iMax; i++) {
- if (selectionModel.isSelectedIndex(i)) {
- rvTmp[n++] = i;
- }
- }
- int[] rv = new int[n];
- System.arraycopy(rvTmp, 0, rv, 0, n);
- return rv;
- }
- return new int[0];
- }
- /**
- * Returns the indices of all selected columns.
- *
- * @return an array of ints containing the indices of all selected columns,
- * or an empty array if no column is selected.
- * @see #getSelectedColumn
- */
- public int[] getSelectedColumns() {
- return columnModel.getSelectedColumns();
- }
- /**
- * Returns the number of selected rows.
- *
- * @return the number of selected rows, 0 if no columns are selected
- */
- public int getSelectedRowCount() {
- if (selectionModel != null) {
- int iMin = selectionModel.getMinSelectionIndex();
- int iMax = selectionModel.getMaxSelectionIndex();
- int count = 0;
- for(int i = iMin; i <= iMax; i++) {
- if (selectionModel.isSelectedIndex(i)) {
- count++;
- }
- }
- return count;
- }
- return 0;
- }
- /**
- * Returns the number of selected columns.
- *
- * @return the number of selected columns, 0 if no columns are selected
- */
- public int getSelectedColumnCount() {
- return columnModel.getSelectedColumnCount();
- }
- /**
- * Returns true if the row at the specified index is selected
- *
- * @return true if the row at index <I>row</I> is selected, where 0 is the
- * first row
- * @exception IllegalArgumentException if <I>row</I> is not in the
- * valid range
- */
- public boolean isRowSelected(int row) {
- if (selectionModel != null)
- return selectionModel.isSelectedIndex(row);
- return false;
- }
- /**
- * Returns true if the column at the specified index is selected
- *
- * @return true if the column at index <I>column</I> is selected, where
- * 0 is the first column
- * @exception IllegalArgumentException if <I>column</I> is not in the
- * valid range
- */
- public boolean isColumnSelected(int column) {
- return columnModel.getSelectionModel().isSelectedIndex(column);
- }
- /**
- * Returns true if the cell at the specified position is selected.
- *
- * @return true if the cell at index <I>(row, column)</I> is selected,
- * where the first row and first column are at index 0
- * @exception IllegalArgumentException if <I>row</I> or <I>column</I>
- * are not in the valid range
- */
- public boolean isCellSelected(int row, int column) {
- if (cellSelectionEnabled)
- return isRowSelected(row) && isColumnSelected(column);
- else
- return (getRowSelectionAllowed() && isRowSelected(row)) ||
- (getColumnSelectionAllowed() && isColumnSelected(column));
- }
- /**
- * Returns the foreground color for selected cells.
- *
- * @return the Color object for the foreground property
- * @see #setSelectionForeground
- * @see #setSelectionBackground
- */
- public Color getSelectionForeground() {
- return selectionForeground;
- }
- /**
- * Set the foreground color for selected cells. Cell renderers
- * can use this color to render text and graphics for selected
- * cells.
- * <p>
- * The default value of this property is defined by the look
- * and feel implementation.
- * <p>
- * This is a JavaBeans bound property.
- *
- * @param selectionForeground the Color to use in the foreground
- * for selected list items
- * @see #getSelectionForeground
- * @see #setSelectionBackground
- * @see #setForeground
- * @see #setBackground
- * @see #setFont
- * @beaninfo
- * bound: true
- * description: A default foreground color for selected cells.
- */
- public void setSelectionForeground(Color selectionForeground) {
- Color oldValue = this.selectionForeground;
- this.selectionForeground = selectionForeground;
- firePropertyChange("selectionForeground", oldValue, selectionForeground);
- }
- /**
- * Returns the background color for selected cells.
- *
- * @return the Color used for the background of selected list items
- * @see #setSelectionBackground
- * @see #setSelectionForeground
- */
- public Color getSelectionBackground() {
- return selectionBackground;
- }
- /**
- * Set the background color for selected cells. Cell renderers
- * can use this color to the fill selected cells.
- * <p>
- * The default value of this property is defined by the look
- * and feel implementation.
- * <p>
- * This is a JavaBeans bound property.
- *
- * @param selectionBackground the Color to use for the background
- * of selected cells
- * @see #getSelectionBackground
- * @see #setSelectionForeground
- * @see #setForeground
- * @see #setBackground
- * @see #setFont
- * @beaninfo
- * bound: true
- * description: A default background color for selected cells.
- */
- public void setSelectionBackground(Color selectionBackground) {
- Color oldValue = this.selectionBackground;
- this.selectionBackground = selectionBackground;
- firePropertyChange("selectionBackground", oldValue, selectionBackground);
- }
- /**
- * Returns the <B>TableColumn</B> object for the column in the table
- * whose identifier is equal to <I>identifier</I>, when compared using
- * <I>equals()</I>.
- *
- * @return the TableColumn object with matching identifier
- * @exception IllegalArgumentException if <I>identifier</I> is null or no TableColumn has this identifier
- *
- * @param identifier the identifier object
- */
- public TableColumn getColumn(Object identifier) {
- TableColumnModel cm = getColumnModel();
- int columnIndex = cm.getColumnIndex(identifier);
- return cm.getColumn(columnIndex);
- }
- //
- // Informally implement the TableModel interface.
- //
- /**
- * Return the index of the column in the model whose data is being displayed in
- * the column <I>viewColumnIndex</I> in the display. Returns <I>viewColumnIndex</I>
- * unchanged when <I>viewColumnIndex</I> is less than zero.
- *
- * @see #convertColumnIndexToView
- */
- public int convertColumnIndexToModel(int viewColumnIndex) {
- if (viewColumnIndex < 0) {
- return viewColumnIndex;
- }
- return getColumnModel().getColumn(viewColumnIndex).getModelIndex();
- }
- /**
- * Return the index of the column in the view which is displaying the
- * data from the column <I>modelColumnIndex</I> in the model. Returns
- * -1 if this column is not being displayed. Returns <I>modelColumnIndex</I>
- * unchanged when <I>modelColumnIndex</I> is less than zero.
- *
- * @see #convertColumnIndexToModel
- */
- public int convertColumnIndexToView(int modelColumnIndex) {
- if (modelColumnIndex < 0) {
- return modelColumnIndex;
- }
- TableColumnModel cm = getColumnModel();
- for (int column = 0; column < getColumnCount(); column++) {
- if (cm.getColumn(column).getModelIndex() == modelColumnIndex) {
- return column;
- }
- }
- return -1;
- }
- /**
- * Returns the number of rows in the table.
- *
- * @see #getColumnCount
- */
- public int getRowCount() {
- return getModel().getRowCount();
- }
- /**
- * Returns the number of columns in the column model, note this may
- * be different to the number of columns in the table model.
- *
- * @return the number of columns in the table
- * @see #getRowCount
- */
- public int getColumnCount() {
- return getColumnModel().getColumnCount();
- }
- /**
- * Returns the name of the column at the specified view position.
- *
- * @return the name of the column at position <I>column</I> in the view
- * where the first column is column 0.
- */
- public String getColumnName(int column) {
- return getModel().getColumnName(convertColumnIndexToModel(column));
- }
- /**
- * Returns the type of the column at the specified view position.
- *
- * @return the type of the column at position <I>column</I> in the view
- * where the first column is column 0.
- */
- public Class getColumnClass(int column) {
- return getModel().getColumnClass(convertColumnIndexToModel(column));
- }
- /**
- * Returns the cell value at <I>row</I> and <I>column</I>.
- * <p>
- * <b>NOTE</b>: The column is specified in the table view's display
- * order, and not in the TableModel's column order. This is
- * an important distinction because as the user rearranges
- * the columns in the table, what is at column 2 changes.
- * Meanwhile the user's actions never affect the model's
- * column ordering.
- *
- * @param row the row whose value is to be looked up
- * @param column the column whose value is to be looked up
- * @return the Object at the specified cell
- */
- public Object getValueAt(int row, int column) {
- return getModel().getValueAt(row, convertColumnIndexToModel(column));
- }
- /**
- * Sets the value for the cell at <I>row</I> and <I>column</I>.
- * <I>aValue</I> is the new value.
- *
- * @param aValue the new value
- * @param row the row whose value is to be changed
- * @param column the column whose value is to be changed
- * @see #getValueAt
- */
- public void setValueAt(Object aValue, int row, int column) {
- getModel().setValueAt(aValue, row, convertColumnIndexToModel(column));
- }
- /**
- * Returns true if the cell at <I>row</I> and <I>column</I>
- * is editable. Otherwise, setValueAt() on the cell will not change
- * the value of that cell.
- *
- * @param row the row whose value is to be looked up
- * @param column the column whose value is to be looked up
- * @return true if the cell is editable.
- * @see #setValueAt
- */
- public boolean isCellEditable(int row, int column) {
- return getModel().isCellEditable(row, convertColumnIndexToModel(column));
- }
- //
- // Adding and removing columns in the view
- //
- /**
- * Appends <I>aColumn</I> to the end of the array of columns held by
- * the JTable's column model.
- * If the header value of <I>aColumn</I> is <I>null</I>,
- * sets the header value of <I>aColumn</I> to the name
- * returned by <code>getModel().getColumnName()</code>.
- * <p>
- * To add a column to the JTable to display the <I>modelColumn</I>'th column of
- * data in the model, with a given <I>width</I>,
- * <I>cellRenderer</I> and <I>cellEditor</I> you can use:
- * <pre>
- *
- * addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
- *
- * </pre>
- * [All of the other constructors in the TableColumn can be used in place of
- * this one.] The model column is stored inside the TableColumn and is used during
- * rendering and editing to locate the appropriate data values in the
- * model. The model column does not change when columns are reordered
- * in the view.
- *
- * @param aColumn The <B>TableColumn</B> to be added
- * @see #removeColumn
- */
- public void addColumn(TableColumn aColumn) {
- int modelColumn = aColumn.getModelIndex();
- String columnName = getModel().getColumnName(modelColumn);
- if (aColumn.getHeaderValue() == null) {
- aColumn.setHeaderValue(columnName);
- }
- getColumnModel().addColumn(aColumn);
- }
- /**
- * Removes <I>aColumn</I> from the JTable's array of columns.
- * Note: this method does not remove the column of data from the
- * model it just removes the TableColumn that was displaying it.
- *
- * @param aColumn The <B>TableColumn</B> to be removed
- * @see #addColumn
- */
- public void removeColumn(TableColumn aColumn) {
- getColumnModel().removeColumn(aColumn);
- }
- /**
- * Moves the column <I>column</I> to the position currently occupied by the
- * column <I>targetColumn</I>. The old column at <I>targetColumn</I> is
- * shifted left or right to make room.
- *
- * @param column the index of column to be moved
- * @param targetColumn the new index of the column
- */
- public void moveColumn(int column, int targetColumn) {
- getColumnModel().moveColumn(column, targetColumn);
- }
- //
- // Cover methods for various models and helper methods
- //
- /**
- * Returns the index of the column that <I>point</I> lies in, or -1 if it
- * lies outside the receiver's bounds.
- *
- * @return the index of the column that <I>point</I> lies in, or -1 if it
- * lies outside the receiver's bounds
- * @see #rowAtPoint
- */
- public int columnAtPoint(Point point) {
- return getColumnModel().getColumnIndexAtX(point.x);
- }
- /**
- * Returns the index of the row that <I>point</I> lies in, or -1 if is
- * not in the range [0, getRowCount()-1].
- *
- * @return the index of the row that <I>point</I> lies in, or -1 if it
- * is not in the range [0, getRowCount()-1]
- * @see #columnAtPoint
- */
- public int rowAtPoint(Point point) {
- int y = point.y;
- // if (y < 0 || y >= getBounds().height) {
- // return -1;
- // }
- int rowHeight = getRowHeight();
- int rowSpacing = getIntercellSpacing().height;
- int totalRowHeight = rowHeight + rowSpacing;
- int result = ytotalRowHeight;
- if (result < 0) {
- return -1;
- }
- else if (result >= getRowCount()) {
- return -1;
- }
- else {
- return result;
- }
- }
- /**
- * Returns a rectangle locating the cell that lies at the intersection of
- * <I>row</I> and <I>column</I>. If <I>includeSpacing</I> is true then
- * the value returned includes the intercellSpacing margin. If it is false,
- * then the returned rect is inset by half of intercellSpacing.
- * (This is the true frame of the cell)
- *
- * @param row the row to compute
- * @param column the column to compute
- * @param includeSpacing if true, the rect returned will
- * include the correct
- * intercellSpacing
- * @return the rectangle containing the cell at index
- * <I>row</I>,<I>column</I>
- * @exception IllegalArgumentException If <I>row</I> or <I>column</I>
- * are not in the valid range.
- */
- public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
- int index = 0;
- Rectangle cellFrame;
- int columnMargin = getColumnModel().getColumnMargin();
- Enumeration enumeration = getColumnModel().getColumns();
- TableColumn aColumn;
- cellFrame = new Rectangle();
- cellFrame.height = getRowHeight() + rowMargin;
- cellFrame.y = row * cellFrame.height;
- while (enumeration.hasMoreElements()) {
- aColumn = (TableColumn)enumeration.nextElement();
- cellFrame.width = aColumn.getWidth() + columnMargin;
- if (index == column)
- break;
- cellFrame.x += cellFrame.width;
- index++;
- }
- if (!includeSpacing) {
- Dimension spacing = getIntercellSpacing();
- // This is not the same as grow(), it rounds differently.
- cellFrame.setBounds(cellFrame.x + spacing.width2,
- cellFrame.y + spacing.height2,
- cellFrame.width - spacing.width,
- cellFrame.height - spacing.height);
- }
- return cellFrame;
- }
- /**
- * Calls super.reshape(), and is overridden simply to detect changes in
- * our bounds. After reshaping we resize the columns (similar to triggering
- * a layout) to fit the new bounds for the component using sizeColumnsToFit().
- *
- * @see #sizeColumnsToFit(int)
- */
- public void reshape(int x, int y, int width, int height) {