1. /*
  2. * @(#)JTable.java 1.168 01/02/09
  3. *
  4. * Copyright 1997-2001 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing;
  11. import java.util.*;
  12. import java.awt.*;
  13. import java.awt.event.*;
  14. import java.beans.*;
  15. import java.io.Serializable;
  16. import java.io.ObjectOutputStream;
  17. import java.io.ObjectInputStream;
  18. import java.io.IOException;
  19. import javax.accessibility.*;
  20. import javax.swing.event.*;
  21. import javax.swing.plaf.*;
  22. import javax.swing.table.*;
  23. import javax.swing.border.*;
  24. import java.text.NumberFormat;
  25. import java.text.DateFormat;
  26. /**
  27. * <code>JTable</code> is a user-interface component that presents data in
  28. * a two-dimensional table format.
  29. * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/table.html">How to Use Tables</a>
  30. * in <em>The Java Tutorial</em>
  31. * for task-oriented documentation and examples of using <code>JTable</code>.
  32. *
  33. * <p>
  34. * The <code>JTable</code> has many
  35. * facilities that make it possible to customize its rendering and editing
  36. * but provides defaults for these features so that simple tables can be
  37. * set up easily. For example, to set up a table with 10 rows and 10
  38. * columns of numbers:
  39. * <p>
  40. * <pre>
  41. * TableModel dataModel = new AbstractTableModel() {
  42. * public int getColumnCount() { return 10; }
  43. * public int getRowCount() { return 10;}
  44. * public Object getValueAt(int row, int col) { return new Integer(row*col); }
  45. * };
  46. * JTable table = new JTable(dataModel);
  47. * JScrollPane scrollpane = new JScrollPane(table);
  48. * </pre>
  49. * <p>
  50. * Because the <code>JTable</code> is now much easier to set up with custom models
  51. * the <code>DefaultTableModel</code> is less useful than it was in previous releases.
  52. * Instead of copying the data in an application into the <code>DefaultTableModel</code>,
  53. * we recommend wrapping it in the methods of the <code>TableModel</code> interface and
  54. * passing the real data to the <code>JTable</code> as above. This technique is nearly as concise
  55. * as using a <code>DefaultTableModel</code> and starting this way has a number of advantages
  56. * over the longer term. In particular: it is a scalable technique,
  57. * can more easily handle dynamic or editable tables, and often results in much
  58. * more efficient applications because the model is free to choose the
  59. * internal representation that best suits the data.
  60. * <p>
  61. * The "Table" directory in the examples/demo area gives a number of complete
  62. * examples of <code>JTable</code> usage, covering how the <code>JTable</code> can be used to provide
  63. * an editable view of data taken from a database and how to modify the columns
  64. * in the display to use specialized renderers and editors. For example, overriding
  65. * <code>AbstractTableModel</code>'s <code>getColumnClass</code> method to return a value of
  66. * <code>ImageIcon.class</code> for a given column allows icons to be displayed,
  67. * while returning a value of <code>Number.class</code> allows digits to be
  68. * right-justified in the column.
  69. * <p>
  70. * The <code>JTable</code> uses integers exclusively to refer to both the rows and the columns
  71. * of the model that it displays. The <code>JTable</code> simply takes a tabular range of cells
  72. * and uses <code>getValueAt(int, int)</code> to retrieve and display the appropriate
  73. * values from the model.
  74. * <p>
  75. * If <code>getTableHeader().setReorderingAllowed(boolean)</code> is used to
  76. * enable column reordering columns may be rearranged in the <code>JTable</code> so that the
  77. * view's columns appear in a different order to the columns in the model.
  78. * This does not affect the implementation of the model at all: when the
  79. * columns are reordered, the <code>JTable</code> maintains the new order of the columns
  80. * internally and converts its column indices before querying the model.
  81. * <p>
  82. * So, when writing a <code>TableModel</code>, it is not necessary to listen for column
  83. * reordering events as the model will be queried in its own coordinate
  84. * system regardless of what is happening in the view.
  85. * In the examples area there is a demonstration of a sorting algorithm making
  86. * use of exactly this technique to interpose yet another coordinate system
  87. * where the order of the rows is changed, rather than the order of the columns.
  88. * <p>
  89. * The general rule for the <code>JTable</code> API and the APIs of all its associated classes,
  90. * including the column model and both the row and column selection models, is:
  91. * methods using integer indices for rows and columns always use the coordinate
  92. * system of the view. There are three exceptions to this rule:
  93. * <ul>
  94. * <li> All references to rows and columns in the <code>TableModel</code>
  95. * interface are in the coordinate system of the model.
  96. * <li> The index <code>modelIndex</code> in the <code>TableColumn</code> constructors
  97. * refers to the index of the column in the model, not the view.
  98. * <li> All constructors for the <code>TableModelEvent</code>, which describes changes
  99. * that have taken place in a table model, use the coordinate system
  100. * of the model.
  101. * </ul>
  102. * The <code>TableColumn</code> provides a slot for holding an identifier or "tag" for each column,
  103. * and the <code>JTable</code> and <code>TableColumnModel</code> both support <code>getColumn(Object id)</code>
  104. * conveniences for locating columns by their identifier. If no identifier is
  105. * explicitly set, the <code>TableColumn</code> returns its header value (the name of the column)
  106. * as a default. A different identifier, which can be of any type, can be set
  107. * using the <code>TableColumn</code>'s <code>setIdentifier</code> method. All of the <code>JTable</code>'s
  108. * functions operate correctly regardless of the type and uniqueness of these
  109. * identifiers.
  110. * <p>
  111. * The <code>convertColumnIndexToView</code> and
  112. * <code>convertColumnIndexToModel</code> methods have been provided to
  113. * convert between the two coordinate systems but
  114. * they are rarely needed during normal use.
  115. * <p>
  116. * As for all <code>JComponent</code> classes, you can use
  117. * {@link InputMap} and {@link ActionMap} to associate an
  118. * {@link Action} object with a {@link KeyStroke} and execute the
  119. * action under specified conditions.
  120. * <p>
  121. * For the keyboard keys used by this component in the standard Look and
  122. * Feel (L&F) renditions, see the
  123. * <a href="doc-files/Key-Index.html#JTable"><code>JTable</code></a> key assignments.
  124. * <p>
  125. * <strong>Warning:</strong>
  126. * Serialized objects of this class will not be compatible with
  127. * future Swing releases. The current serialization support is appropriate
  128. * for short term storage or RMI between applications running the same
  129. * version of Swing. A future release of Swing will provide support for
  130. * long term persistence.
  131. *
  132. *
  133. * @beaninfo
  134. * attribute: isContainer false
  135. * description: A component which displays data in a two dimensional grid.
  136. *
  137. * @version 1.168 02/09/01
  138. * @author Philip Milne
  139. */
  140. /* The first versions of the JTable, contained in Swing-0.1 through
  141. * Swing-0.4, were written by Alan Chung.
  142. */
  143. public class JTable extends JComponent implements TableModelListener, Scrollable,
  144. TableColumnModelListener, ListSelectionListener, CellEditorListener,
  145. Accessible
  146. {
  147. //
  148. // Static Constants
  149. //
  150. /**
  151. * @see #getUIClassID
  152. * @see #readObject
  153. */
  154. private static final String uiClassID = "TableUI";
  155. /** Do not adjust column widths automatically; use a scrollbar. */
  156. public static final int AUTO_RESIZE_OFF = 0;
  157. /** When a column is adjusted in the UI, adjust the next column the opposite way. */
  158. public static final int AUTO_RESIZE_NEXT_COLUMN = 1;
  159. /** During UI adjustment, change subsequent columns to preserve the total width;
  160. * this is the default behavior. */
  161. public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
  162. /** During all resize operations, apply adjustments to the last column only. */
  163. public static final int AUTO_RESIZE_LAST_COLUMN = 3;
  164. /** During all resize operations, proportionately resize all columns. */
  165. public static final int AUTO_RESIZE_ALL_COLUMNS = 4;
  166. //
  167. // Instance Variables
  168. //
  169. /** The <code>TableModel</code> of the table. */
  170. protected TableModel dataModel;
  171. /** The <code>TableColumnModel</code> of the table. */
  172. protected TableColumnModel columnModel;
  173. /** The <code>ListSelectionModel</code> of the table, used to keep track of row selections. */
  174. protected ListSelectionModel selectionModel;
  175. /** The <code>TableHeader</code> working with the table. */
  176. protected JTableHeader tableHeader;
  177. /** The height in pixels of each row in the table. */
  178. protected int rowHeight;
  179. /** The height in pixels of the margin between the cells in each row. */
  180. protected int rowMargin;
  181. /** The color of the grid. */
  182. protected Color gridColor;
  183. /** The table draws horizontal lines between cells if <code>showHorizontalLines</code> is true. */
  184. protected boolean showHorizontalLines;
  185. /** The table draws vertical lines between cells if <code>showVerticalLines</code> is true. */
  186. protected boolean showVerticalLines;
  187. /**
  188. * Determines if the table automatically resizes the
  189. * width of the table's columns to take up the entire width of the
  190. * table, and how it does the resizing.
  191. */
  192. protected int autoResizeMode;
  193. /**
  194. * The table will query the <code>TableModel</code> to build the default
  195. * set of columns if this is true.
  196. */
  197. protected boolean autoCreateColumnsFromModel;
  198. /** Used by the <code>Scrollable</code> interface to determine the initial visible area. */
  199. protected Dimension preferredViewportSize;
  200. /** True if row selection is allowed in this table. */
  201. protected boolean rowSelectionAllowed;
  202. /**
  203. * Obsolete as of Java 2 platform v1.3. Please use the
  204. * <code>rowSelectionAllowed</code> property and the
  205. * <code>columnSelectionAllowed</code> property of the
  206. * <code>columnModel</code> instead. Or use the
  207. * method <code>getCellSelectionEnabled</code>.
  208. */
  209. /*
  210. * If true, both a row selection and a column selection
  211. * can be non-empty at the same time, the selected cells are the
  212. * the cells whose row and column are both selected.
  213. */
  214. protected boolean cellSelectionEnabled;
  215. /** If editing, the <code>Component</code> that is handling the editing. */
  216. transient protected Component editorComp;
  217. /**
  218. * The object that overwrites the screen real estate occupied by the
  219. * current cell and allows the user to change its contents.
  220. */
  221. transient protected TableCellEditor cellEditor;
  222. /** Identifies the column of the cell being edited. */
  223. transient protected int editingColumn;
  224. /** Identifies the row of the cell being edited. */
  225. transient protected int editingRow;
  226. /**
  227. * A table of objects that display the contents of a cell,
  228. * indexed by class as declared in <code>getColumnClass</code>
  229. * in the <code>TableModel</code> interface.
  230. */
  231. transient protected Hashtable defaultRenderersByColumnClass;
  232. /**
  233. * A table of objects that display and edit the contents of a cell,
  234. * indexed by class as declared in <code>getColumnClass</code>
  235. * in the <code>TableModel</code> interface.
  236. */
  237. transient protected Hashtable defaultEditorsByColumnClass;
  238. /** The foreground color of selected cells. */
  239. protected Color selectionForeground;
  240. /** The background color of selected cells. */
  241. protected Color selectionBackground;
  242. //
  243. // Private state
  244. //
  245. private boolean reentrantCall = false;
  246. private SizeSequence rowModel;
  247. //
  248. // Constructors
  249. //
  250. /**
  251. * Constructs a default <code>JTable</code> that is initialized with a default
  252. * data model, a default column model, and a default selection
  253. * model.
  254. *
  255. * @see #createDefaultDataModel
  256. * @see #createDefaultColumnModel
  257. * @see #createDefaultSelectionModel
  258. */
  259. public JTable() {
  260. this(null, null, null);
  261. }
  262. /**
  263. * Constructs a <code>JTable</code> that is initialized with
  264. * <code>dm</code> as the data model, a default column model,
  265. * and a default selection model.
  266. *
  267. * @param dm the data model for the table
  268. * @see #createDefaultColumnModel
  269. * @see #createDefaultSelectionModel
  270. */
  271. public JTable(TableModel dm) {
  272. this(dm, null, null);
  273. }
  274. /**
  275. * Constructs a <code>JTable</code> that is initialized with
  276. * <code>dm</code> as the data model, <code>cm</code>
  277. * as the column model, and a default selection model.
  278. *
  279. * @param dm the data model for the table
  280. * @param cm the column model for the table
  281. * @see #createDefaultSelectionModel
  282. */
  283. public JTable(TableModel dm, TableColumnModel cm) {
  284. this(dm, cm, null);
  285. }
  286. /**
  287. * Constructs a <code>JTable</code> that is initialized with
  288. * <code>dm</code> as the data model, <code>cm</code> as the
  289. * column model, and <code>sm</code> as the selection model.
  290. * If any of the parameters are <code>null</code> this method
  291. * will initialize the table with the corresponding default model.
  292. * The <code>autoCreateColumnsFromModel</code> flag is set to false
  293. * if <code>cm</code> is non-null, otherwise it is set to true
  294. * and the column model is populated with suitable
  295. * <code>TableColumns</code> for the columns in <code>dm</code>.
  296. *
  297. * @param dm the data model for the table
  298. * @param cm the column model for the table
  299. * @param sm the row selection model for the table
  300. * @see #createDefaultDataModel
  301. * @see #createDefaultColumnModel
  302. * @see #createDefaultSelectionModel
  303. */
  304. public JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
  305. super();
  306. setLayout(null);
  307. if (cm == null) {
  308. cm = createDefaultColumnModel();
  309. autoCreateColumnsFromModel = true;
  310. }
  311. setColumnModel(cm);
  312. if (sm == null) {
  313. sm = createDefaultSelectionModel();
  314. }
  315. setSelectionModel(sm);
  316. // Set the model last, that way if the autoCreatColumnsFromModel has
  317. // been set above, we will automatically populate an empty columnModel
  318. // with suitable columns for the new model.
  319. if (dm == null) {
  320. dm = createDefaultDataModel();
  321. }
  322. setModel(dm);
  323. initializeLocalVars();
  324. updateUI();
  325. }
  326. /**
  327. * Constructs a <code>JTable</code> with <code>numRows</code>
  328. * and <code>numColumns</code> of empty cells using
  329. * <code>DefaultTableModel</code>. The columns will have
  330. * names of the form "A", "B", "C", etc.
  331. *
  332. * @param numRows the number of rows the table holds
  333. * @param numColumns the number of columns the table holds
  334. * @see javax.swing.table.DefaultTableModel
  335. */
  336. public JTable(int numRows, int numColumns) {
  337. this(new DefaultTableModel(numRows, numColumns));
  338. }
  339. /**
  340. * Constructs a <code>JTable</code> to display the values in the
  341. * <code>Vector</code> of <code>Vectors</code>, <code>rowData</code>,
  342. * with column names, <code>columnNames</code>. The
  343. * <code>Vectors</code> contained in <code>rowData</code>
  344. * should contain the values for that row. In other words,
  345. * the value of the cell at row 1, column 5 can be obtained
  346. * with the following code:
  347. * <p>
  348. * <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
  349. * <p>
  350. * Each row must contain a value for each column or an exception
  351. * will be raised.
  352. * <p>
  353. * @param rowData the data for the new table
  354. * @param columnNames names of each column
  355. */
  356. public JTable(final Vector rowData, final Vector columnNames) {
  357. this(new AbstractTableModel() {
  358. public String getColumnName(int column) { return columnNames.elementAt(column).toString(); }
  359. public int getRowCount() { return rowData.size(); }
  360. public int getColumnCount() { return columnNames.size(); }
  361. public Object getValueAt(int row, int column) {
  362. return ((Vector)rowData.elementAt(row)).elementAt(column);
  363. }
  364. public boolean isCellEditable(int row, int column) { return true; }
  365. public void setValueAt(Object value, int row, int column) {
  366. ((Vector)rowData.elementAt(row)).setElementAt(value, column);
  367. fireTableCellUpdated(row, column);
  368. }
  369. });
  370. }
  371. /**
  372. * Constructs a <code>JTable</code> to display the values in the two dimensional array,
  373. * <code>rowData</code>, with column names, <code>columnNames</code>.
  374. * <code>rowData</code> is an array of rows, so the value of the cell at row 1,
  375. * column 5 can be obtained with the following code:
  376. * <p>
  377. * <pre> rowData[1][5]; </pre>
  378. * <p>
  379. * All rows must be of the same length as <code>columnNames</code>.
  380. * <p>
  381. * @param rowData the data for the new table
  382. * @param columnNames names of each column
  383. */
  384. public JTable(final Object[][] rowData, final Object[] columnNames) {
  385. this(new AbstractTableModel() {
  386. public String getColumnName(int column) { return columnNames[column].toString(); }
  387. public int getRowCount() { return rowData.length; }
  388. public int getColumnCount() { return columnNames.length; }
  389. public Object getValueAt(int row, int col) { return rowData[row][col]; }
  390. public boolean isCellEditable(int row, int column) { return true; }
  391. public void setValueAt(Object value, int row, int col) {
  392. rowData[row][col] = value;
  393. fireTableCellUpdated(row, col);
  394. }
  395. });
  396. }
  397. /**
  398. * Calls the <code>configureEnclosingScrollPane</code> method.
  399. *
  400. * @see #configureEnclosingScrollPane
  401. */
  402. public void addNotify() {
  403. super.addNotify();
  404. configureEnclosingScrollPane();
  405. }
  406. /**
  407. * If this <code>JTable</code> is the <code>viewportView</code> of an enclosing <code>JScrollPane</code>
  408. * (the usual situation), configure this <code>ScrollPane</code> by, amongst other things,
  409. * installing the table's <code>tableHeader</code> as the <code>columnHeaderView</code> of the scroll pane.
  410. * When a <code>JTable</code> is added to a <code>JScrollPane</code> in the usual way,
  411. * using <code>new JScrollPane(myTable)</code>, <code>addNotify</code> is
  412. * called in the <code>JTable</code> (when the table is added to the viewport).
  413. * <code>JTable</code>'s <code>addNotify</code> method in turn calls this method,
  414. * which is protected so that this default installation procedure can
  415. * be overridden by a subclass.
  416. *
  417. * @see #addNotify
  418. */
  419. protected void configureEnclosingScrollPane() {
  420. Container p = getParent();
  421. if (p instanceof JViewport) {
  422. Container gp = p.getParent();
  423. if (gp instanceof JScrollPane) {
  424. JScrollPane scrollPane = (JScrollPane)gp;
  425. // Make certain we are the viewPort's view and not, for
  426. // example, the rowHeaderView of the scrollPane -
  427. // an implementor of fixed columns might do this.
  428. JViewport viewport = scrollPane.getViewport();
  429. if (viewport == null || viewport.getView() != this) {
  430. return;
  431. }
  432. scrollPane.setColumnHeaderView(getTableHeader());
  433. // scrollPane.getViewport().setBackingStoreEnabled(true);
  434. Border border = scrollPane.getBorder();
  435. if (border == null || border instanceof UIResource) {
  436. scrollPane.setBorder(UIManager.getBorder("Table.scrollPaneBorder"));
  437. }
  438. }
  439. }
  440. }
  441. /**
  442. * Calls the <code>unconfigureEnclosingScrollPane</code> method.
  443. *
  444. * @see #unconfigureEnclosingScrollPane
  445. */
  446. public void removeNotify() {
  447. unconfigureEnclosingScrollPane();
  448. super.removeNotify();
  449. }
  450. /**
  451. * Reverses the effect of <code>configureEnclosingScrollPane</code>
  452. * by replacing the <code>columnHeaderView</code> of the enclosing scroll pane with
  453. * <code>null</code>. <code>JTable</code>'s <code>removeNotify</code> method calls
  454. * this method, which is protected so that this default uninstallation
  455. * procedure can be overridden by a subclass.
  456. *
  457. * @see #removeNotify
  458. * @see #configureEnclosingScrollPane
  459. */
  460. protected void unconfigureEnclosingScrollPane() {
  461. Container p = getParent();
  462. if (p instanceof JViewport) {
  463. Container gp = p.getParent();
  464. if (gp instanceof JScrollPane) {
  465. JScrollPane scrollPane = (JScrollPane)gp;
  466. // Make certain we are the viewPort's view and not, for
  467. // example, the rowHeaderView of the scrollPane -
  468. // an implementor of fixed columns might do this.
  469. JViewport viewport = scrollPane.getViewport();
  470. if (viewport == null || viewport.getView() != this) {
  471. return;
  472. }
  473. scrollPane.setColumnHeaderView(null);
  474. }
  475. }
  476. }
  477. //
  478. // Static Methods
  479. //
  480. /**
  481. * Equivalent to <code>new JScrollPane(aTable)</code>.
  482. *
  483. * @deprecated As of Swing version 1.0.2,
  484. * replaced by <code>new JScrollPane(aTable)</code>.
  485. */
  486. static public JScrollPane createScrollPaneForTable(JTable aTable) {
  487. return new JScrollPane(aTable);
  488. }
  489. //
  490. // Table Attributes
  491. //
  492. /**
  493. * Sets the <code>tableHeader</code> working with this <code>JTable</code> to <code>newHeader</code>.
  494. * It is legal to have a <code>null</code> <code>tableHeader</code>.
  495. *
  496. * @param newHeader new tableHeader
  497. * @see #getTableHeader
  498. * @beaninfo
  499. * bound: true
  500. * description: The JTableHeader instance which renders the column headers.
  501. */
  502. public void setTableHeader(JTableHeader tableHeader) {
  503. if (this.tableHeader != tableHeader) {
  504. JTableHeader old = this.tableHeader;
  505. // Release the old header
  506. if (old != null) {
  507. old.setTable(null);
  508. }
  509. this.tableHeader = tableHeader;
  510. if (tableHeader != null) {
  511. tableHeader.setTable(this);
  512. }
  513. firePropertyChange("tableHeader", old, tableHeader);
  514. }
  515. }
  516. /**
  517. * Returns the <code>tableHeader</code> used by this <code>JTable</code>.
  518. *
  519. * @return the <code>tableHeader</code> used by this table
  520. * @see #setTableHeader
  521. */
  522. public JTableHeader getTableHeader() {
  523. return tableHeader;
  524. }
  525. /**
  526. * Sets the height, in pixels, of all cells to <code>rowHeight</code>,
  527. * revalidates, and repaints.
  528. * The height of the cells in this row will be equal to the row height minus
  529. * the row margin.
  530. *
  531. * @param rowHeight new row height
  532. * @exception IllegalArgumentException if <code>rowHeight</code> is
  533. * less than 1
  534. * @see #getRowHeight
  535. * @beaninfo
  536. * bound: true
  537. * description: The height of the specified row.
  538. */
  539. public void setRowHeight(int rowHeight) {
  540. if (rowHeight <= 0) {
  541. throw new IllegalArgumentException("New row height less than 1");
  542. }
  543. int old = this.rowHeight;
  544. this.rowHeight = rowHeight;
  545. rowModel = null;
  546. resizeAndRepaint();
  547. firePropertyChange("rowHeight", old, rowHeight);
  548. }
  549. /**
  550. * Returns the height of a table row, in pixels.
  551. * The default row height is 16.0.
  552. *
  553. * @return the height in pixels of a table row
  554. * @see #setRowHeight
  555. */
  556. public int getRowHeight() {
  557. return rowHeight;
  558. }
  559. private SizeSequence getRowModel() {
  560. if (rowModel == null) {
  561. rowModel = new SizeSequence(getRowCount(), getRowHeight());
  562. }
  563. return rowModel;
  564. }
  565. /**
  566. * Sets the height for <code>row</code> to <code>rowHeight</code>,
  567. * revalidates, and repaints. The height of the cells in this row
  568. * will be equal to the row height minus the row margin.
  569. *
  570. * @param row the row whose height is being
  571. changed
  572. * @param rowHeight new row height, in pixels
  573. * @exception IllegalArgumentException if <code>rowHeight</code> is
  574. * less than 1
  575. * @beaninfo
  576. * bound: true
  577. * description: The height in pixels of the cells in <code>row</code>
  578. */
  579. public void setRowHeight(int row, int rowHeight) {
  580. if (rowHeight <= 0) {
  581. throw new IllegalArgumentException("New row height less than 1");
  582. }
  583. getRowModel().setSize(row, rowHeight);
  584. resizeAndRepaint();
  585. }
  586. /**
  587. * Returns the height, in pixels, of the cells in <code>row</code>.
  588. * @param row the row whose height is to be returned
  589. * @return the height, in pixels, of the cells in the row
  590. */
  591. public int getRowHeight(int row) {
  592. return (rowModel == null) ? getRowHeight() : rowModel.getSize(row);
  593. }
  594. /**
  595. * Sets the amount of empty space between cells in adjacent rows.
  596. *
  597. * @param rowMargin the number of pixels between cells in a row
  598. * @see #getRowMargin
  599. * @beaninfo
  600. * bound: true
  601. * description: The amount of space between cells.
  602. */
  603. public void setRowMargin(int rowMargin) {
  604. int old = this.rowMargin;
  605. this.rowMargin = rowMargin;
  606. resizeAndRepaint();
  607. firePropertyChange("rowMargin", old, rowMargin);
  608. }
  609. /**
  610. * Gets the amount of empty space, in pixels, between cells. Equivalent to:
  611. * <code>getIntercellSpacing().height</code>.
  612. * @return the number of pixels between cells in a row
  613. *
  614. * @see #setRowMargin
  615. */
  616. public int getRowMargin() {
  617. return rowMargin;
  618. }
  619. /**
  620. * Sets the <code>rowMargin</code> and the <code>columnMargin</code> --
  621. * the height and width of the space between cells -- to
  622. * <code>intercellSpacing</code>.
  623. *
  624. * @param intercellSpacing a <code>Dimension</code>
  625. * specifying the new width
  626. * and height between cells
  627. * @see #getIntercellSpacing
  628. * @beaninfo
  629. * description: The spacing between the cells,
  630. * drawn in the background color of the JTable.
  631. */
  632. public void setIntercellSpacing(Dimension intercellSpacing) {
  633. // Set the rowMargin here and columnMargin in the TableColumnModel
  634. setRowMargin(intercellSpacing.height);
  635. getColumnModel().setColumnMargin(intercellSpacing.width);
  636. resizeAndRepaint();
  637. }
  638. /**
  639. * Returns the horizontal and vertical space between cells.
  640. * The default spacing is (1, 1), which provides room to draw the grid.
  641. *
  642. * @return the horizontal and vertical spacing between cells
  643. * @see #setIntercellSpacing
  644. */
  645. public Dimension getIntercellSpacing() {
  646. return new Dimension(getColumnModel().getColumnMargin(), rowMargin);
  647. }
  648. /**
  649. * Sets the color used to draw grid lines to <code>gridColor</code> and redisplays.
  650. * The default color is <code>Color.gray</code>.
  651. *
  652. * @param gridColor the new color of the grid lines
  653. * @exception IllegalArgumentException if <code>gridColor</code> is <code>null</code>
  654. * @see #getGridColor
  655. * @beaninfo
  656. * bound: true
  657. * description: The grid color.
  658. */
  659. public void setGridColor(Color gridColor) {
  660. if (gridColor == null) {
  661. throw new IllegalArgumentException("New color is null");
  662. }
  663. Color old = this.gridColor;
  664. this.gridColor = gridColor;
  665. firePropertyChange("gridColor", old, gridColor);
  666. // Redraw
  667. repaint();
  668. }
  669. /**
  670. * Returns the color used to draw grid lines. The default color is <code>Color.gray</code>.
  671. *
  672. * @return the color used to draw grid lines
  673. * @see #setGridColor
  674. */
  675. public Color getGridColor() {
  676. return gridColor;
  677. }
  678. /**
  679. * Sets whether the table draws grid lines around cells.
  680. * If <code>showGrid</code> is true it does; if it is false it doesn't.
  681. * There is no <code>getShowGrid</code> method as this state is held
  682. * in two variables -- <code>showHorizontalLines</code> and <code>showVerticalLines</code> --
  683. * each of which can be queried independently.
  684. *
  685. * @param showGrid true if table view should draw grid lines
  686. *
  687. * @see #setShowVerticalLines
  688. * @see #setShowHorizontalLines
  689. * @beaninfo
  690. * description: The color used to draw the grid lines.
  691. */
  692. public void setShowGrid(boolean showGrid) {
  693. setShowHorizontalLines(showGrid);
  694. setShowVerticalLines(showGrid);
  695. // Redraw
  696. repaint();
  697. }
  698. /**
  699. * Sets whether the table draws horizontal lines between cells.
  700. * If <code>showHorizontalLines</code> is true it does; if it is false it doesn't.
  701. *
  702. * @param showHorizontalLines true if table view should draw horizontal lines
  703. * @see #getShowHorizontalLines
  704. * @see #setShowGrid
  705. * @see #setShowVerticalLines
  706. * @beaninfo
  707. * bound: true
  708. * description: Whether horizontal lines should be drawn in between the cells.
  709. */
  710. public void setShowHorizontalLines(boolean showHorizontalLines) {
  711. boolean old = showHorizontalLines;
  712. this.showHorizontalLines = showHorizontalLines;
  713. firePropertyChange("showHorizontalLines", old, showHorizontalLines);
  714. // Redraw
  715. repaint();
  716. }
  717. /**
  718. * Sets whether the table draws vertical lines between cells.
  719. * If <code>showVerticalLines</code> is true it does; if it is false it doesn't.
  720. *
  721. * @param showVerticalLines true if table view should draw vertical lines
  722. * @see #getShowVerticalLines
  723. * @see #setShowGrid
  724. * @see #setShowHorizontalLines
  725. * @beaninfo
  726. * bound: true
  727. * description: Whether vertical lines should be drawn in between the cells.
  728. */
  729. public void setShowVerticalLines(boolean showVerticalLines) {
  730. boolean old = showVerticalLines;
  731. this.showVerticalLines = showVerticalLines;
  732. firePropertyChange("showVerticalLines", old, showVerticalLines);
  733. // Redraw
  734. repaint();
  735. }
  736. /**
  737. * Returns true if the table draws horizontal lines between cells, false if it
  738. * doesn't. The default is true.
  739. *
  740. * @return true if the table draws horizontal lines between cells, false if it
  741. * doesn't
  742. * @see #setShowHorizontalLines
  743. */
  744. public boolean getShowHorizontalLines() {
  745. return showHorizontalLines;
  746. }
  747. /**
  748. * Returns true if the table draws vertical lines between cells, false if it
  749. * doesn't. The default is true.
  750. *
  751. * @return true if the table draws vertical lines between cells, false if it
  752. * doesn't
  753. * @see #setShowVerticalLines
  754. */
  755. public boolean getShowVerticalLines() {
  756. return showVerticalLines;
  757. }
  758. /**
  759. * Sets the table's auto resize mode when the table is resized.
  760. *
  761. * @param mode One of 5 legal values:
  762. * AUTO_RESIZE_OFF,
  763. * AUTO_RESIZE_NEXT_COLUMN,
  764. * AUTO_RESIZE_SUBSEQUENT_COLUMNS,
  765. * AUTO_RESIZE_LAST_COLUMN,
  766. * AUTO_RESIZE_ALL_COLUMNS
  767. *
  768. * @see #getAutoResizeMode
  769. * @see #sizeColumnsToFit(int)
  770. * @beaninfo
  771. * bound: true
  772. * description: Whether the columns should adjust themselves automatically.
  773. * enum: AUTO_RESIZE_OFF JTable.AUTO_RESIZE_OFF
  774. * AUTO_RESIZE_NEXT_COLUMN JTable.AUTO_RESIZE_NEXT_COLUMN
  775. * AUTO_RESIZE_SUBSEQUENT_COLUMNS JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS
  776. * AUTO_RESIZE_LAST_COLUMN JTable.AUTO_RESIZE_LAST_COLUMN
  777. * AUTO_RESIZE_ALL_COLUMNS JTable.AUTO_RESIZE_ALL_COLUMNS
  778. */
  779. public void setAutoResizeMode(int mode) {
  780. if ((mode == AUTO_RESIZE_OFF) ||
  781. (mode == AUTO_RESIZE_NEXT_COLUMN) ||
  782. (mode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) ||
  783. (mode == AUTO_RESIZE_LAST_COLUMN) ||
  784. (mode == AUTO_RESIZE_ALL_COLUMNS)) {
  785. int old = autoResizeMode;
  786. autoResizeMode = mode;
  787. resizeAndRepaint();
  788. if (tableHeader != null) {
  789. tableHeader.resizeAndRepaint();
  790. }
  791. firePropertyChange("autoResizeMode", old, autoResizeMode);
  792. }
  793. }
  794. /**
  795. * Returns the auto resize mode of the table. The default mode
  796. * is AUTO_RESIZE_SUBSEQUENT_COLUMNS.
  797. *
  798. * @return the autoResizeMode of the table
  799. *
  800. * @see #setAutoResizeMode
  801. * @see #sizeColumnsToFit(int)
  802. */
  803. public int getAutoResizeMode() {
  804. return autoResizeMode;
  805. }
  806. /**
  807. * Sets this table's <code>autoCreateColumnsFromModel</code> flag.
  808. * This method calls <code>createDefaultColumnsFromModel</code> if
  809. * <code>autoCreateColumnsFromModel</code> changes from false to true.
  810. *
  811. * @param autoCreateColumnsFromModel true if <code>JTable</code> should automatically create columns
  812. * @see #getAutoCreateColumnsFromModel
  813. * @see #createDefaultColumnsFromModel
  814. * @beaninfo
  815. * bound: true
  816. * description: Automatically populates the columnModel when a new TableModel is submitted.
  817. */
  818. public void setAutoCreateColumnsFromModel(boolean autoCreateColumnsFromModel) {
  819. if (this.autoCreateColumnsFromModel != autoCreateColumnsFromModel) {
  820. boolean old = this.autoCreateColumnsFromModel;
  821. this.autoCreateColumnsFromModel = autoCreateColumnsFromModel;
  822. if (autoCreateColumnsFromModel) {
  823. createDefaultColumnsFromModel();
  824. }
  825. firePropertyChange("autoCreateColumnsFromModel", old, autoCreateColumnsFromModel);
  826. }
  827. }
  828. /**
  829. * Determines whether the table will create default columns from the model.
  830. * If true, <code>setModel</code> will clear any existing columns and
  831. * create new columns from the new model. Also, if the event in
  832. * the <code>tableChanged</code> notification specifies that the
  833. * entire table changed, then the columns will be rebuilt.
  834. * The default is true.
  835. *
  836. * @return the autoCreateColumnsFromModel of the table
  837. * @see #setAutoCreateColumnsFromModel
  838. * @see #createDefaultColumnsFromModel
  839. */
  840. public boolean getAutoCreateColumnsFromModel() {
  841. return autoCreateColumnsFromModel;
  842. }
  843. /**
  844. * Creates default columns for the table from
  845. * the data model using the <code>getColumnCount</code> method
  846. * defined in the <code>TableModel</code> interface.
  847. * <p>
  848. * Clears any existing columns before creating the
  849. * new columns based on information from the model.
  850. *
  851. * @see #getAutoCreateColumnsFromModel
  852. */
  853. public void createDefaultColumnsFromModel() {
  854. TableModel m = getModel();
  855. if (m != null) {
  856. // Remove any current columns
  857. TableColumnModel cm = getColumnModel();
  858. while (cm.getColumnCount() > 0) {
  859. cm.removeColumn(cm.getColumn(0));
  860. }
  861. // Create new columns from the data model info
  862. for (int i = 0; i < m.getColumnCount(); i++) {
  863. TableColumn newColumn = new TableColumn(i);
  864. addColumn(newColumn);
  865. }
  866. }
  867. }
  868. /**
  869. * Sets a default cell renderer to be used if no renderer has been set in
  870. * a <code>TableColumn</code>. If renderer is <code>null</code>,
  871. * removes the default renderer for this column class.
  872. *
  873. * @param columnClass set the default cell renderer for this columnClass
  874. * @param renderer default cell renderer to be used for this
  875. * columnClass
  876. * @see #getDefaultRenderer
  877. * @see #setDefaultEditor
  878. */
  879. public void setDefaultRenderer(Class columnClass, TableCellRenderer renderer) {
  880. if (renderer != null) {
  881. defaultRenderersByColumnClass.put(columnClass, renderer);
  882. }
  883. else {
  884. defaultRenderersByColumnClass.remove(columnClass);
  885. }
  886. }
  887. /**
  888. * Returns the cell renderer to be used when no renderer has been set in
  889. * a <code>TableColumn</code>. During the rendering of cells the renderer is fetched from
  890. * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
  891. * there is no entry for this <code>columnClass</code> the method returns
  892. * the entry for the most specific superclass. The <code>JTable</code> installs entries
  893. * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
  894. * or replaced.
  895. *
  896. * @param columnClass return the default cell renderer
  897. * for this columnClass
  898. * @return the renderer for this columnClass
  899. * @see #setDefaultRenderer
  900. * @see #getColumnClass
  901. */
  902. public TableCellRenderer getDefaultRenderer(Class columnClass) {
  903. if (columnClass == null) {
  904. return null;
  905. }
  906. else {
  907. Object renderer = defaultRenderersByColumnClass.get(columnClass);
  908. if (renderer != null) {
  909. return (TableCellRenderer)renderer;
  910. }
  911. else {
  912. return getDefaultRenderer(columnClass.getSuperclass());
  913. }
  914. }
  915. }
  916. /**
  917. * Sets a default cell editor to be used if no editor has been set in
  918. * a <code>TableColumn</code>. If no editing is required in a table, or a
  919. * particular column in a table, uses the <code>isCellEditable</code>
  920. * method in the <code>TableModel</code> interface to ensure that this
  921. * <code>JTable</code> will not start an editor in these columns.
  922. * If editor is <code>null</code>, removes the default editor for this
  923. * column class.
  924. *
  925. * @param columnClass set the default cell editor for this columnClass
  926. * @param editor default cell editor to be used for this columnClass
  927. * @see TableModel#isCellEditable
  928. * @see #getDefaultEditor
  929. * @see #setDefaultRenderer
  930. */
  931. public void setDefaultEditor(Class columnClass, TableCellEditor editor) {
  932. if (editor != null) {
  933. defaultEditorsByColumnClass.put(columnClass, editor);
  934. }
  935. else {
  936. defaultEditorsByColumnClass.remove(columnClass);
  937. }
  938. }
  939. /**
  940. * Returns the editor to be used when no editor has been set in
  941. * a <code>TableColumn</code>. During the editing of cells the editor is fetched from
  942. * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
  943. * there is no entry for this <code>columnClass</code> the method returns
  944. * the entry for the most specific superclass. The <code>JTable</code> installs entries
  945. * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
  946. * or replaced.
  947. *
  948. * @param columnClass return the default cell editor for this columnClass
  949. * @return the default cell editor to be used for this columnClass
  950. * @see #setDefaultEditor
  951. * @see #getColumnClass
  952. */
  953. public TableCellEditor getDefaultEditor(Class columnClass) {
  954. if (columnClass == null) {
  955. return null;
  956. }
  957. else {
  958. Object editor = defaultEditorsByColumnClass.get(columnClass);
  959. if (editor != null) {
  960. return (TableCellEditor)editor;
  961. }
  962. else {
  963. return getDefaultEditor(columnClass.getSuperclass());
  964. }
  965. }
  966. }
  967. //
  968. // Selection methods
  969. //
  970. /**
  971. * Sets the table's selection mode to allow only single selections, a single
  972. * contiguous interval, or multiple intervals.
  973. * <P>
  974. * <bold>Note:</bold>
  975. * <code>JTable</code> provides all the methods for handling
  976. * column and row selection. When setting states,
  977. * such as <code>setSelectionMode</code>, it not only
  978. * updates the mode for the row selection model but also sets similar
  979. * values in the selection model of the <code>columnModel</code>.
  980. * If you want to have the row and column selection models operating
  981. * in different modes, set them both directly.
  982. * <p>
  983. * Both the row and column selection models for <code>JTable</code>
  984. * default to using a <code>DefaultListSelectionModel</code>
  985. * so that <code>JTable</code> works the same way as the
  986. * <code>JList</code>. See the <code>setSelectionMode</code> method
  987. * in <code>JList</code> for details about the modes.
  988. *
  989. * @see JList#setSelectionMode
  990. * @beaninfo
  991. * description: The selection mode used by the row and column selection models.
  992. * enum: SINGLE_SELECTION ListSelectionModel.SINGLE_SELECTION
  993. * SINGLE_INTERVAL_SELECTION ListSelectionModel.SINGLE_INTERVAL_SELECTION
  994. * MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
  995. */
  996. public void setSelectionMode(int selectionMode) {
  997. clearSelection();
  998. getSelectionModel().setSelectionMode(selectionMode);
  999. getColumnModel().getSelectionModel().setSelectionMode(selectionMode);
  1000. }
  1001. /**
  1002. * Sets whether the rows in this model can be selected.
  1003. *
  1004. * @param rowSelectionAllowed true if this model will allow row selection
  1005. * @see #getRowSelectionAllowed
  1006. * @beaninfo
  1007. * bound: true
  1008. * description: If true, an entire row is selected for each selected cell.
  1009. */
  1010. public void setRowSelectionAllowed(boolean rowSelectionAllowed) {
  1011. boolean old = this.rowSelectionAllowed;
  1012. this.rowSelectionAllowed = rowSelectionAllowed;
  1013. firePropertyChange("rowSelectionAllowed", old, rowSelectionAllowed);
  1014. }
  1015. /**
  1016. * Returns true if rows can be selected.
  1017. *
  1018. * @return true if rows can be selected, otherwise false
  1019. * @see #setRowSelectionAllowed
  1020. */
  1021. public boolean getRowSelectionAllowed() {
  1022. return rowSelectionAllowed;
  1023. }
  1024. /**
  1025. * Sets whether the columns in this model can be selected.
  1026. *
  1027. * @param columnSelectionAllowed true if this model will allow column selection
  1028. * @see #getColumnSelectionAllowed
  1029. * @beaninfo
  1030. * bound: true
  1031. * description: If true, an entire column is selected for each selected cell.
  1032. */
  1033. public void setColumnSelectionAllowed(boolean columnSelectionAllowed) {
  1034. boolean old = columnModel.getColumnSelectionAllowed();
  1035. columnModel.setColumnSelectionAllowed(columnSelectionAllowed);
  1036. firePropertyChange("columnSelectionAllowed", old, columnSelectionAllowed);
  1037. }
  1038. /**
  1039. * Returns true if columns can be selected.
  1040. *
  1041. * @return true if columns can be selected, otherwise false
  1042. * @see #setColumnSelectionAllowed
  1043. */
  1044. public boolean getColumnSelectionAllowed() {
  1045. return columnModel.getColumnSelectionAllowed();
  1046. }
  1047. /**
  1048. * Sets whether this table allows both a column selection and a
  1049. * row selection to exist simultaneously. When set,
  1050. * the table treats the intersection of the row and column selection
  1051. * models as the selected cells. Override <code>isCellSelected</code> to
  1052. * change this default behavior. This method is equivalent to setting
  1053. * both the <code>rowSelectionAllowed</code> property and
  1054. * <code>columnSelectionAllowed</code> property of the
  1055. * <code>columnModel</code> to the supplied value.
  1056. *
  1057. * @param cellSelectionEnabled true if simultaneous row and column
  1058. * selection is allowed
  1059. * @see #getCellSelectionEnabled
  1060. * @see #isCellSelected
  1061. * @beaninfo
  1062. * bound: true
  1063. * description: Select a rectangular region of cells rather than
  1064. * rows or columns.
  1065. */
  1066. public void setCellSelectionEnabled(boolean cellSelectionEnabled) {
  1067. setRowSelectionAllowed(cellSelectionEnabled);
  1068. setColumnSelectionAllowed(cellSelectionEnabled);
  1069. boolean old = this.cellSelectionEnabled;
  1070. this.cellSelectionEnabled = cellSelectionEnabled;
  1071. firePropertyChange("cellSelectionEnabled", old, cellSelectionEnabled);
  1072. }
  1073. /**
  1074. * Returns true if both row and column selection models are enabled.
  1075. * Equivalent to <code>getRowSelectionAllowed() &&
  1076. * getColumnSelectionAllowed()</code>.
  1077. *
  1078. * @return true if both row and column selection models are enabled
  1079. *
  1080. * @see #setCellSelectionEnabled
  1081. */
  1082. public boolean getCellSelectionEnabled() {
  1083. return getRowSelectionAllowed() && getColumnSelectionAllowed();
  1084. }
  1085. /**
  1086. * Selects all rows, columns, and cells in the table.
  1087. */
  1088. public void selectAll() {
  1089. // If I'm currently editing, then I should stop editing
  1090. if (isEditing()) {
  1091. removeEditor();
  1092. }
  1093. setRowSelectionInterval(0, getRowCount()-1);
  1094. setColumnSelectionInterval(0, getColumnCount()-1);
  1095. }
  1096. /**
  1097. * Deselects all selected columns and rows.
  1098. */
  1099. public void clearSelection() {
  1100. columnModel.getSelectionModel().clearSelection();
  1101. selectionModel.clearSelection();
  1102. }
  1103. private int boundRow(int row) throws IllegalArgumentException {
  1104. if (row < 0 || row >= getRowCount()) {
  1105. throw new IllegalArgumentException("Row index out of range");
  1106. }
  1107. return row;
  1108. }
  1109. private int boundColumn(int col) {
  1110. if (col< 0 || col >= getColumnCount()) {
  1111. throw new IllegalArgumentException("Column index out of range");
  1112. }
  1113. return col;
  1114. }
  1115. /**
  1116. * Selects the rows from <code>index0</code> to <code>index1</code>,
  1117. * inclusive.
  1118. *
  1119. * @exception IllegalArgumentException if <code>index0</code> or
  1120. * <code>index1</code> lie outside
  1121. * [0, <code>getRowCount()</code>-1]
  1122. * @param index0 one end of the interval
  1123. * @param index1 the other end of the interval
  1124. */
  1125. public void setRowSelectionInterval(int index0, int index1) {
  1126. selectionModel.setSelectionInterval(boundRow(index0), boundRow(index1));
  1127. }
  1128. /**
  1129. * Selects the columns from <code>index0</code> to <code>index1</code>,
  1130. * inclusive.
  1131. *
  1132. * @exception IllegalArgumentException if <code>index0</code> or
  1133. * <code>index1</code> lie outside
  1134. * [0, <code>getColumnCount()</code>-1]
  1135. * @param index0 one end of the interval
  1136. * @param index1 the other end of the interval
  1137. */
  1138. public void setColumnSelectionInterval(int index0, int index1) {
  1139. columnModel.getSelectionModel().setSelectionInterval(boundColumn(index0), boundColumn(index1));
  1140. }
  1141. /**
  1142. * Adds the rows from <code>index0</code> to <code>index1</code>, inclusive, to
  1143. * the current selection.
  1144. *
  1145. * @exception IllegalArgumentException if <code>index0</code> or <code>index1</code>
  1146. * lie outside [0, <code>getRowCount()</code>-1]
  1147. * @param index0 one end of the interval
  1148. * @param index1 the other end of the interval
  1149. */
  1150. public void addRowSelectionInterval(int index0, int index1) {
  1151. selectionModel.addSelectionInterval(boundRow(index0), boundRow(index1));
  1152. }
  1153. /**
  1154. * Adds the columns from <code>index0</code> to <code>index1</code>,
  1155. * inclusive, to the current selection.
  1156. *
  1157. * @exception IllegalArgumentException if <code>index0</code> or
  1158. * <code>index1</code> lie outside
  1159. * [0, <code>getColumnCount()</code>-1]
  1160. * @param index0 one end of the interval
  1161. * @param index1 the other end of the interval
  1162. */
  1163. public void addColumnSelectionInterval(int index0, int index1) {
  1164. columnModel.getSelectionModel().addSelectionInterval(boundColumn(index0), boundColumn(index1));
  1165. }
  1166. /**
  1167. * Deselects the rows from <code>index0</code> to <code>index1</code>, inclusive.
  1168. *
  1169. * @exception IllegalArgumentException if <code>index0</code> or
  1170. * <code>index1</code> lie outside
  1171. * [0, <code>getRowCount()</code>-1]
  1172. * @param index0 one end of the interval
  1173. * @param index1 the other end of the interval
  1174. */
  1175. public void removeRowSelectionInterval(int index0, int index1) {
  1176. selectionModel.removeSelectionInterval(boundRow(index0), boundRow(index1));
  1177. }
  1178. /**
  1179. * Deselects the columns from <code>index0</code> to <code>index1</code>, inclusive.
  1180. *
  1181. * @exception IllegalArgumentException if <code>index0</code> or
  1182. * <code>index1</code> lie outside
  1183. * [0, <code>getColumnCount()</code>-1]
  1184. * @param index0 one end of the interval
  1185. * @param index1 the other end of the interval
  1186. */
  1187. public void removeColumnSelectionInterval(int index0, int index1) {
  1188. columnModel.getSelectionModel().removeSelectionInterval(boundColumn(index0), boundColumn(index1));
  1189. }
  1190. /**
  1191. * Returns the index of the first selected row, -1 if no row is selected.
  1192. * @return the index of the first selected row
  1193. */
  1194. public int getSelectedRow() {
  1195. return selectionModel.getMinSelectionIndex();
  1196. }
  1197. /**
  1198. * Returns the index of the first selected column,
  1199. * -1 if no column is selected.
  1200. * @return the index of the first selected column
  1201. */
  1202. public int getSelectedColumn() {
  1203. return columnModel.getSelectionModel().getMinSelectionIndex();
  1204. }
  1205. /**
  1206. * Returns the indices of all selected rows.
  1207. *
  1208. * @return an array of integers containing the indices of all selected rows,
  1209. * or an empty array if no row is selected
  1210. * @see #getSelectedRow
  1211. */
  1212. public int[] getSelectedRows() {
  1213. if (selectionModel != null) {
  1214. int iMin = selectionModel.getMinSelectionIndex();
  1215. int iMax = selectionModel.getMaxSelectionIndex();
  1216. if ((iMin == -1) || (iMax == -1)) {
  1217. return new int[0];
  1218. }
  1219. int[] rvTmp = new int[1+ (iMax - iMin)];
  1220. int n = 0;
  1221. for(int i = iMin; i <= iMax; i++) {
  1222. if (selectionModel.isSelectedIndex(i)) {
  1223. rvTmp[n++] = i;
  1224. }
  1225. }
  1226. int[] rv = new int[n];
  1227. System.arraycopy(rvTmp, 0, rv, 0, n);
  1228. return rv;
  1229. }
  1230. return new int[0];
  1231. }
  1232. /**
  1233. * Returns the indices of all selected columns.
  1234. *
  1235. * @return an array of integers containing the indices of all selected columns,
  1236. * or an empty array if no column is selected
  1237. * @see #getSelectedColumn
  1238. */
  1239. public int[] getSelectedColumns() {
  1240. return columnModel.getSelectedColumns();
  1241. }
  1242. /**
  1243. * Returns the number of selected rows.
  1244. *
  1245. * @return the number of selected rows, 0 if no rows are selected
  1246. */
  1247. public int getSelectedRowCount() {
  1248. if (selectionModel != null) {
  1249. int iMin = selectionModel.getMinSelectionIndex();
  1250. int iMax = selectionModel.getMaxSelectionIndex();
  1251. int count = 0;
  1252. for(int i = iMin; i <= iMax; i++) {
  1253. if (selectionModel.isSelectedIndex(i)) {
  1254. count++;
  1255. }
  1256. }
  1257. return count;
  1258. }
  1259. return 0;
  1260. }
  1261. /**
  1262. * Returns the number of selected columns.
  1263. *
  1264. * @return the number of selected columns, 0 if no columns are selected
  1265. */
  1266. public int getSelectedColumnCount() {
  1267. return columnModel.getSelectedColumnCount();
  1268. }
  1269. /**
  1270. * Returns true if the row at the specified index is selected.
  1271. *
  1272. * @return true if the row at index <code>row</code> is selected, where 0 is the
  1273. * first row
  1274. * @exception IllegalArgumentException if <code>row</code> is not in the
  1275. * valid range
  1276. */
  1277. public boolean isRowSelected(int row) {
  1278. if (selectionModel != null)
  1279. return selectionModel.isSelectedIndex(row);
  1280. return false;
  1281. }
  1282. /**
  1283. * Returns true if the column at the specified index is selected.
  1284. *
  1285. * @param column the column in the column model
  1286. * @return true if the column at index <code>column</code> is selected, where
  1287. * 0 is the first column
  1288. * @exception IllegalArgumentException if <code>column</code> is not in the
  1289. * valid range
  1290. */
  1291. public boolean isColumnSelected(int column) {
  1292. return columnModel.getSelectionModel().isSelectedIndex(column);
  1293. }
  1294. /**
  1295. * Returns true if the cell at the specified position is selected.
  1296. * @param row the row being queried
  1297. * @param column the column being queried
  1298. *
  1299. * @return true if the cell at index <code>(row, column)</code> is selected,
  1300. * where the first row and first column are at index 0
  1301. * @exception IllegalArgumentException if <code>row</code> or <code>column</code>
  1302. * are not in the valid range
  1303. */
  1304. public boolean isCellSelected(int row, int column) {
  1305. if (!getRowSelectionAllowed() && !getColumnSelectionAllowed()) {
  1306. return false;
  1307. }
  1308. return (!getRowSelectionAllowed() || isRowSelected(row)) &&
  1309. (!getColumnSelectionAllowed() || isColumnSelected(column));
  1310. }
  1311. private void changeSelectionModel(ListSelectionModel sm, int index,
  1312. boolean toggle, boolean extend) {
  1313. if (extend) {
  1314. if (toggle) {
  1315. sm.setAnchorSelectionIndex(index);
  1316. }
  1317. else {
  1318. sm.setLeadSelectionIndex(index);
  1319. }
  1320. }
  1321. else {
  1322. if (toggle) {
  1323. if (sm.isSelectedIndex(index)) {
  1324. sm.removeSelectionInterval(index, index);
  1325. }
  1326. else {
  1327. sm.addSelectionInterval(index, index);
  1328. }
  1329. }
  1330. else {
  1331. sm.setSelectionInterval(index, index);
  1332. }
  1333. }
  1334. }
  1335. /**
  1336. * Updates the selection models of the table, depending on the state of the
  1337. * two flags: <code>toggle</code> and <code>extend</code>. All changes
  1338. * to the selection that are the result of keyboard or mouse events received
  1339. * by the UI are channeled through this method so that the behavior may be
  1340. * overridden by a subclass.
  1341. * <p>
  1342. * This implementation uses the following conventions:
  1343. * <ul>
  1344. * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>false</em>.
  1345. * Clear the previous selection and ensure the new cell is selected.
  1346. * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>true</em>.
  1347. * Extend the previous selection to include the specified cell.
  1348. * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>false</em>.
  1349. * If the specified cell is selected, deselect it. If it is not selected, select it.
  1350. * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>true</em>.
  1351. * Leave the selection state as it is, but move the anchor index to the specified location.
  1352. * </ul>
  1353. * @param rowIndex affects the selection at <code>row</code>
  1354. * @param columnIndex affects the selection at <code>column</code>
  1355. * @param toggle see description above
  1356. * @param extend if true, extend the current selection
  1357. *
  1358. */
  1359. public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
  1360. ListSelectionModel rsm = getSelectionModel();
  1361. ListSelectionModel csm = getColumnModel().getSelectionModel();
  1362. // Update column selection model
  1363. changeSelectionModel(csm, columnIndex, toggle, extend);
  1364. // Update row selection model
  1365. changeSelectionModel(rsm, rowIndex, toggle, extend);
  1366. // Scroll after changing the selection as blit scrolling is immediate,
  1367. // so that if we cause the repaint after the scroll we end up painting
  1368. // everything!
  1369. // Autoscrolling support.
  1370. if (getAutoscrolls()) {
  1371. Rectangle cellRect = getCellRect(rowIndex, columnIndex, false);
  1372. if (cellRect != null) {
  1373. scrollRectToVisible(cellRect);
  1374. }
  1375. }
  1376. }
  1377. /**
  1378. * Returns the foreground color for selected cells.
  1379. *
  1380. * @return the <code>Color</code> object for the foreground property
  1381. * @see #setSelectionForeground
  1382. * @see #setSelectionBackground
  1383. */
  1384. public Color getSelectionForeground() {
  1385. return selectionForeground;
  1386. }
  1387. /**
  1388. * Sets the foreground color for selected cells. Cell renderers
  1389. * can use this color to render text and graphics for selected
  1390. * cells.
  1391. * <p>
  1392. * The default value of this property is defined by the look
  1393. * and feel implementation.
  1394. * <p>
  1395. * This is a <a href="http://java.sun.com/docs/books/tutorial/javabeans/whatis/beanDefinition.html">JavaBeans</a> bound property.