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.
  1396. *
  1397. * @param selectionForeground the <code>Color</code> to use in the foreground
  1398. * for selected list items
  1399. * @see #getSelectionForeground
  1400. * @see #setSelectionBackground
  1401. * @see #setForeground
  1402. * @see #setBackground
  1403. * @see #setFont
  1404. * @beaninfo
  1405. * bound: true
  1406. * description: A default foreground color for selected cells.
  1407. */
  1408. public void setSelectionForeground(Color selectionForeground) {
  1409. Color old = this.selectionForeground;
  1410. this.selectionForeground = selectionForeground;
  1411. firePropertyChange("selectionForeground", old, selectionForeground);
  1412. if ( !selectionForeground.equals(old) )
  1413. {
  1414. repaint();
  1415. }
  1416. }
  1417. /**
  1418. * Returns the background color for selected cells.
  1419. *
  1420. * @return the <code>Color</code> used for the background of selected list items
  1421. * @see #setSelectionBackground
  1422. * @see #setSelectionForeground
  1423. */
  1424. public Color getSelectionBackground() {
  1425. return selectionBackground;
  1426. }
  1427. /**
  1428. * Sets the background color for selected cells. Cell renderers
  1429. * can use this color to the fill selected cells.
  1430. * <p>
  1431. * The default value of this property is defined by the look
  1432. * and feel implementation.
  1433. * <p>
  1434. * This is a <a href="http://java.sun.com/docs/books/tutorial/javabeans/whatis/beanDefinition.html">JavaBeans</a> bound property.
  1435. *
  1436. * @param selectionBackground the <code>Color</code> to use for the background
  1437. * of selected cells
  1438. * @see #getSelectionBackground
  1439. * @see #setSelectionForeground
  1440. * @see #setForeground
  1441. * @see #setBackground
  1442. * @see #setFont
  1443. * @beaninfo
  1444. * bound: true
  1445. * description: A default background color for selected cells.
  1446. */
  1447. public void setSelectionBackground(Color selectionBackground) {
  1448. Color old = this.selectionBackground;
  1449. this.selectionBackground = selectionBackground;
  1450. firePropertyChange("selectionBackground", old, selectionBackground);
  1451. if ( !selectionBackground.equals(old) )
  1452. {
  1453. repaint();
  1454. }
  1455. }
  1456. /**
  1457. * Returns the <code>TableColumn</code> object for the column in the table
  1458. * whose identifier is equal to <code>identifier</code>, when compared using
  1459. * <code>equals</code>.
  1460. *
  1461. * @return the <code>TableColumn</code> object that matches the identifier
  1462. * @exception IllegalArgumentException if <code>identifier</code> is <code>null</code> or no <code>TableColumn</code> has this identifier
  1463. *
  1464. * @param identifier the identifier object
  1465. */
  1466. public TableColumn getColumn(Object identifier) {
  1467. TableColumnModel cm = getColumnModel();
  1468. int columnIndex = cm.getColumnIndex(identifier);
  1469. return cm.getColumn(columnIndex);
  1470. }
  1471. //
  1472. // Informally implement the TableModel interface.
  1473. //
  1474. /**
  1475. * Maps the index of the column in the view at
  1476. * <code>viewColumnIndex</code> to the index of the column
  1477. * in the table model. Returns the index of the corresponding
  1478. * column in the model. If <code>viewColumnIndex</code>
  1479. * is less than zero, returns <code>viewColumnIndex</code>.
  1480. *
  1481. * @param viewColumnIndex the index of the column in the view
  1482. * @return the index of the corresponding column in the model
  1483. *
  1484. * @see #convertColumnIndexToView
  1485. */
  1486. public int convertColumnIndexToModel(int viewColumnIndex) {
  1487. if (viewColumnIndex < 0) {
  1488. return viewColumnIndex;
  1489. }
  1490. return getColumnModel().getColumn(viewColumnIndex).getModelIndex();
  1491. }
  1492. /**
  1493. * Maps the index of the column in the table model at
  1494. * <code>modelColumnIndex</code> to the index of the column
  1495. * in the view. Returns the index of the
  1496. * corresponding column in the view; returns -1 if this column is not
  1497. * being displayed. If <code>modelColumnIndex</code> is less than zero,
  1498. * returns <code>modelColumnIndex</code>.
  1499. *
  1500. * @param modelColumnIndex the index of the column in the model
  1501. * @return the index of the corresponding column in the view
  1502. *
  1503. * @see #convertColumnIndexToModel
  1504. */
  1505. public int convertColumnIndexToView(int modelColumnIndex) {
  1506. if (modelColumnIndex < 0) {
  1507. return modelColumnIndex;
  1508. }
  1509. TableColumnModel cm = getColumnModel();
  1510. for (int column = 0; column < getColumnCount(); column++) {
  1511. if (cm.getColumn(column).getModelIndex() == modelColumnIndex) {
  1512. return column;
  1513. }
  1514. }
  1515. return -1;
  1516. }
  1517. /**
  1518. * Returns the number of rows in this table's model.
  1519. * @return the number of rows in this table's model
  1520. *
  1521. * @see #getColumnCount
  1522. */
  1523. public int getRowCount() {
  1524. return getModel().getRowCount();
  1525. }
  1526. /**
  1527. * Returns the number of columns in the column model. Note that this may
  1528. * be different from the number of columns in the table model.
  1529. *
  1530. * @return the number of columns in the table
  1531. * @see #getRowCount
  1532. * @see #removeColumn
  1533. */
  1534. public int getColumnCount() {
  1535. return getColumnModel().getColumnCount();
  1536. }
  1537. /**
  1538. * Returns the name of the column appearing in the view at
  1539. * column position <code>column</code>.
  1540. *
  1541. * @param column the column in the view being queried
  1542. * @return the name of the column at position <code>column</code>
  1543. in the view where the first column is column 0
  1544. */
  1545. public String getColumnName(int column) {
  1546. return getModel().getColumnName(convertColumnIndexToModel(column));
  1547. }
  1548. /**
  1549. * Returns the type of the column appearing in the view at
  1550. * column position <code>column</code>.
  1551. *
  1552. * @param column the column in the view being queried
  1553. * @return the type of the column at position <code>column</code>
  1554. * in the view where the first column is column 0
  1555. */
  1556. public Class getColumnClass(int column) {
  1557. return getModel().getColumnClass(convertColumnIndexToModel(column));
  1558. }
  1559. /**
  1560. * Returns the cell value at <code>row</code> and <code>column</code>.
  1561. * <p>
  1562. * <b>Note</b>: The column is specified in the table view's display
  1563. * order, and not in the <code>TableModel</code>'s column
  1564. * order. This is an important distinction because as the
  1565. * user rearranges the columns in the table,
  1566. * the column at a given index in the view will change.
  1567. * Meanwhile the user's actions never affect the model's
  1568. * column ordering.
  1569. *
  1570. * @param row the row whose value is to be queried
  1571. * @param column the column whose value is to be queried
  1572. * @return the Object at the specified cell
  1573. */
  1574. public Object getValueAt(int row, int column) {
  1575. return getModel().getValueAt(row, convertColumnIndexToModel(column));
  1576. }
  1577. /**
  1578. * Sets the value for the cell in the table model at <code>row</code>
  1579. * and <code>column</code>.
  1580. * <p>
  1581. * <b>Note</b>: The column is specified in the table view's display
  1582. * order, and not in the <code>TableModel</code>'s column
  1583. * order. This is an important distinction because as the
  1584. * user rearranges the columns in the table,
  1585. * the column at a given index in the view will change.
  1586. * Meanwhile the user's actions never affect the model's
  1587. * column ordering.
  1588. *
  1589. * <code>aValue</code> is the new value.
  1590. *
  1591. * @param aValue the new value
  1592. * @param row the row of the cell to be changed
  1593. * @param column the column of the cell to be changed
  1594. * @see #getValueAt
  1595. */
  1596. public void setValueAt(Object aValue, int row, int column) {
  1597. getModel().setValueAt(aValue, row, convertColumnIndexToModel(column));
  1598. }
  1599. /**
  1600. * Returns true if the cell at <code>row</code> and <code>column</code>
  1601. * is editable. Otherwise, invoking <code>setValueAt</code> on the cell
  1602. * will have no effect.
  1603. * <p>
  1604. * <b>Note</b>: The column is specified in the table view's display
  1605. * order, and not in the <code>TableModel</code>'s column
  1606. * order. This is an important distinction because as the
  1607. * user rearranges the columns in the table,
  1608. * the column at a given index in the view will change.
  1609. * Meanwhile the user's actions never affect the model's
  1610. * column ordering.
  1611. *
  1612. *
  1613. * @param row the row whose value is to be queried
  1614. * @param column the column whose value is to be queried
  1615. * @return true if the cell is editable
  1616. * @see #setValueAt
  1617. */
  1618. public boolean isCellEditable(int row, int column) {
  1619. return getModel().isCellEditable(row, convertColumnIndexToModel(column));
  1620. }
  1621. //
  1622. // Adding and removing columns in the view
  1623. //
  1624. /**
  1625. * Appends <code>aColumn</code> to the end of the array of columns held by
  1626. * this <code>JTable</code>'s column model.
  1627. * If the column name of <code>aColumn</code> is <code>null</code>,
  1628. * sets the column name of <code>aColumn</code> to the name
  1629. * returned by <code>getModel().getColumnName()</code>.
  1630. * <p>
  1631. * To add a column to this <code>JTable</code> to display the
  1632. * <code>modelColumn</code>'th column of data in the model with a
  1633. * given <code>width</code>, <code>cellRenderer</code>,
  1634. * and <code>cellEditor</code> you can use:
  1635. * <pre>
  1636. *
  1637. * addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
  1638. *
  1639. * </pre>
  1640. * [Any of the <code>TableColumn</code> constructors can be used
  1641. * instead of this one.]
  1642. * The model column number is stored inside the <code>TableColumn</code>
  1643. * and is used during rendering and editing to locate the appropriates
  1644. * data values in the model. The model column number does not change
  1645. * when columns are reordered in the view.
  1646. *
  1647. * @param aColumn the <code>TableColumn</code> to be added
  1648. * @see #removeColumn
  1649. */
  1650. public void addColumn(TableColumn aColumn) {
  1651. int modelColumn = aColumn.getModelIndex();
  1652. String columnName = getModel().getColumnName(modelColumn);
  1653. if (aColumn.getHeaderValue() == null) {
  1654. aColumn.setHeaderValue(columnName);
  1655. }
  1656. getColumnModel().addColumn(aColumn);
  1657. }
  1658. /**
  1659. * Removes <code>aColumn</code> from this <code>JTable</code>'s
  1660. * array of columns. Note: this method does not remove the column
  1661. * of data from the model; it just removes the <code>TableColumn</code>
  1662. * that was responsible for displaying it.
  1663. *
  1664. * @param aColumn the <code>TableColumn</code> to be removed
  1665. * @see #addColumn
  1666. */
  1667. public void removeColumn(TableColumn aColumn) {
  1668. getColumnModel().removeColumn(aColumn);
  1669. }
  1670. /**
  1671. * Moves the column <code>column</code> to the position currently
  1672. * occupied by the column <code>targetColumn</code> in the view.
  1673. * The old column at <code>targetColumn</code> is
  1674. * shifted left or right to make room.
  1675. *
  1676. * @param column the index of column to be moved
  1677. * @param targetColumn the new index of the column
  1678. */
  1679. public void moveColumn(int column, int targetColumn) {
  1680. getColumnModel().moveColumn(column, targetColumn);
  1681. }
  1682. //
  1683. // Cover methods for various models and helper methods
  1684. //
  1685. /**
  1686. * Returns the index of the column that <code>point</code> lies in,
  1687. * or -1 if the result is not in the range
  1688. * [0, <code>getColumnCount()</code>-1].
  1689. *
  1690. * @param point the location of interest
  1691. * @return the index of the column that <code>point</code> lies in,
  1692. * or -1 if the result is not in the range
  1693. * [0, <code>getColumnCount()</code>-1]
  1694. * @see #rowAtPoint
  1695. */
  1696. public int columnAtPoint(Point point) {
  1697. return getColumnModel().getColumnIndexAtX(point.x);
  1698. }
  1699. /**
  1700. * Returns the index of the row that <code>point</code> lies in,
  1701. * or -1 if the result is not in the range
  1702. * [0, <code>getRowCount()</code>-1].
  1703. *
  1704. * @param point the location of interest
  1705. * @return the index of the row that <code>point</code> lies in,
  1706. * or -1 if the result is not in the range
  1707. * [0, <code>getRowCount()</code>-1]
  1708. * @see #columnAtPoint
  1709. */
  1710. public int rowAtPoint(Point point) {
  1711. int y = point.y;
  1712. int result = (rowModel == null) ? ygetRowHeight() : rowModel.getIndex(y);
  1713. if (result < 0) {
  1714. return -1;
  1715. }
  1716. else if (result >= getRowCount()) {
  1717. return -1;
  1718. }
  1719. else {
  1720. return result;
  1721. }
  1722. }
  1723. /**
  1724. * Returns a rectangle for the cell that lies at the intersection of
  1725. * <code>row</code> and <code>column</code>.
  1726. * If <code>includeSpacing</code> is true then the value returned
  1727. * has the full height and width of the row and column
  1728. * specified. If it is false, the returned rectangle is inset by the
  1729. * intercell spacing to return the true bounds of the rendering or
  1730. * editing component as it will be set during rendering.
  1731. * <p>
  1732. * If the column index is valid but the row index is less
  1733. * than zero the method returns a rectangle with the the
  1734. * <code>y</code> and <code>height</code> values set appropriately
  1735. * and the <code>x</code> and <code>width</code> values both set
  1736. * to zero. In general, when either the row or column indices indicate a
  1737. * cell outside the appropriate range, the method returns a rectangle
  1738. * depicting the closest edge of the closest cell that is within
  1739. * the table's range. When both row and column indices are out
  1740. * of range the returned rectangle covers the closest
  1741. * point of the closest cell.
  1742. * <p>
  1743. * In all cases, calulations that use this method to calculate
  1744. * results along one axix will not fail because of anomalies in
  1745. * calculations along other axis. When the cell is not valid the
  1746. * <I>includeSpacing</I> parameter is ignored.
  1747. *
  1748. * @param includeSpacing if false, return the true cell bounds -
  1749. * computed by subtracting the intercell
  1750. * spacing from the height and widths of
  1751. * the column and row models.
  1752. *
  1753. * @return the rectangle containing the cell at location
  1754. * <code>row</code>,<code>column</code>
  1755. */
  1756. public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
  1757. Rectangle r = new Rectangle();
  1758. boolean valid = true;
  1759. if (row < 0) {
  1760. // y = height = 0;
  1761. valid = false;
  1762. }
  1763. else if (row >= getRowCount()) {
  1764. r.y = getHeight();
  1765. valid = false;
  1766. }
  1767. else {
  1768. r.height = getRowHeight(row);
  1769. r.y = (rowModel == null) ? row * r.height : rowModel.getPosition(row);
  1770. }
  1771. if (column < 0) {
  1772. // x = width = 0;
  1773. valid = false;
  1774. }
  1775. else if (column >= getColumnCount()) {
  1776. r.x = getWidth();
  1777. valid = false;
  1778. }
  1779. else {
  1780. TableColumnModel cm = getColumnModel();
  1781. for(int i = 0; i < column; i++) {
  1782. r.x += cm.getColumn(i).getWidth();
  1783. }
  1784. r.width = cm.getColumn(column).getWidth();
  1785. }
  1786. if (valid && !includeSpacing) {
  1787. int rm = getRowMargin();
  1788. int cm = getColumnModel().getColumnMargin();
  1789. // This is not the same as grow(), it rounds differently.
  1790. r.setBounds(r.x + cm2, r.y + rm2, r.width - cm, r.height - rm);
  1791. }
  1792. return r;
  1793. }
  1794. private int viewIndexForColumn(TableColumn aColumn) {
  1795. TableColumnModel cm = getColumnModel();
  1796. for (int column = 0; column < cm.getColumnCount(); column++) {
  1797. if (cm.getColumn(column) == aColumn) {
  1798. return column;
  1799. }
  1800. }
  1801. return -1;
  1802. }
  1803. /**
  1804. * Causes this table to lay out its rows and columns. Overridden so
  1805. * that columns can be resized to accomodate a change in the size of
  1806. * a containing parent.
  1807. */
  1808. public void doLayout() {
  1809. sizeColumnsToFit(-1);
  1810. super.doLayout();
  1811. }
  1812. /**
  1813. * Sizes the table columns to fit the available space.
  1814. * @deprecated As of Swing version 1.0.3,
  1815. * replaced by <code>sizeColumnsToFit(int)</code>.
  1816. * @see #sizeColumnsToFit(int)
  1817. */
  1818. public void sizeColumnsToFit(boolean lastColumnOnly) {
  1819. int oldAutoResizeMode = autoResizeMode;
  1820. setAutoResizeMode(lastColumnOnly ? AUTO_RESIZE_LAST_COLUMN
  1821. : AUTO_RESIZE_ALL_COLUMNS);
  1822. sizeColumnsToFit(-1);
  1823. setAutoResizeMode(oldAutoResizeMode);
  1824. }
  1825. /**
  1826. * Resizes one or more of the columns in the table
  1827. * so that the total width of all of this <code>JTable</code>'s
  1828. * columns is equal to the width of the table.
  1829. * <p>
  1830. * When <code>doLayout</code> is called on this <code>JTable</code>,
  1831. * often as a result of the resizing of an enclosing window,
  1832. * this method is called with <code>resizingColumn</code>
  1833. * set to -1. This means that resizing has taken place "outside"
  1834. * the <code>JTable</code> and the change - or "delta" - should
  1835. * be distributed to all of the columns regardless of this
  1836. * <code>JTable</code>'s automatic resize mode.
  1837. * <p>
  1838. * If the <code>resizingColumn</code> is not -1, it is one of
  1839. * the columns in the table that has changed size rather than
  1840. * the table itself. In this case the auto-resize modes govern
  1841. * the way the extra (or deficit) space is distributed
  1842. * amongst the available columns.
  1843. * <p>
  1844. * The modes are:
  1845. * <ul>
  1846. * <li> AUTO_RESIZE_OFF: Don't automatically adjust the column's
  1847. * widths at all. Use a horizontal scrollbar to accomodate the
  1848. * columns when their sum exceeds the width of the
  1849. * <code>Viewport</code>. If the <code>JTable</code> is not
  1850. * enclosed in a <code>JScrollPane</code> this may
  1851. * leave parts of the table invisible.
  1852. * <li> AUTO_RESIZE_NEXT_COLUMN: Use just the column after the
  1853. * resizing column. This results in the "boundary" or divider
  1854. * between adjacent cells being independently adjustable.
  1855. * <li> AUTO_RESIZE_SUBSEQUENT_COLUMNS: Use all columns after the
  1856. * one being adjusted to absorb the changes. This is the
  1857. * default behavior.
  1858. * <li> AUTO_RESIZE_LAST_COLUMN: Automatically adjust the
  1859. * size of the last column only. If the bounds of the last column
  1860. * prevent the desired size from being allocated, set the
  1861. * width of the last column to the appropriate limit and make
  1862. * no further adjustments.
  1863. * <li> AUTO_RESIZE_ALL_COLUMNS: Spread the delta amongst all the columns
  1864. * in the <code>JTable</code>, including the one that is being
  1865. * adjusted.
  1866. * </ul>
  1867. * <p>
  1868. * <bold>Note:</bold> When a <code>JTable</code> makes adjustments
  1869. * to the widths of the columns it respects their minimum and
  1870. * maximum values absolutely. It is therefore possible that,
  1871. * even after this method is called, the total width of the columns
  1872. * is still not equal to the width of the table. When this happens
  1873. * the <code>JTable</code> does not put itself
  1874. * in AUTO_RESIZE_OFF mode to bring up a scroll bar, or break other
  1875. * commitments of its current auto-resize mode -- instead it
  1876. * allows its bounds to be set larger (or smaller) than the total of the
  1877. * column minimum or maximum, meaning, either that there
  1878. * will not be enough room to display all of the columns, or that the
  1879. * columns will not fill the <code>JTable</code>'s bounds.
  1880. * These respectively, result in the clipping of some columns
  1881. * or an area being painted in the <code>JTable</code>'s
  1882. * background color during painting.
  1883. * <p>
  1884. * The mechanism for distributing the delta amongst the available
  1885. * columns is provided in a private method in the <code>JTable</code>
  1886. * class:
  1887. * <pre>
  1888. * adjustSizes(long targetSize, final Resizable3 r, boolean inverse)
  1889. * </pre>
  1890. * an explanation of which is provided in the following section.
  1891. * <code>Resizable3</code> is a private
  1892. * interface that allows any data structure containing a collection
  1893. * of elements with a size, preferred size, maximum size and minimum size
  1894. * to have its elements manipulated by the algorithm.
  1895. * <p>
  1896. * <H3> Distributing the delta </H3>
  1897. * <p>
  1898. * <H4> Overview </H4>
  1899. * <P>
  1900. * Call "DELTA" the difference between the target size and the
  1901. * sum of the preferred sizes of the elements in r. The individual
  1902. * sizes are calculated by taking the original preferred
  1903. * sizes and adding a share of the DELTA - that share being based on
  1904. * how far each preferred size is from its limiting bound (minimum or
  1905. * maximum).
  1906. * <p>
  1907. * <H4>Definition</H4>
  1908. * <P>
  1909. * Call the individual constraints min[i], max[i], and pref[i].
  1910. * <p>
  1911. * Call their respective sums: MIN, MAX, and PREF.
  1912. * <p>
  1913. * Each new size will be calculated using:
  1914. * <p>
  1915. * <pre>
  1916. * size[i] = pref[i] + delta[i]
  1917. * </pre>
  1918. * where each individual delta[i] is calculated according to:
  1919. * <p>
  1920. * If (DELTA < 0) we are in shrink mode where:
  1921. * <p>
  1922. * <PRE>
  1923. * DELTA
  1924. * delta[i] = ------------ * (pref[i] - min[i])
  1925. * (PREF - MIN)
  1926. * </PRE>
  1927. * If (DELTA > 0) we are in expand mode where:
  1928. * <p>
  1929. * <PRE>
  1930. * DELTA
  1931. * delta[i] = ------------ * (max[i] - pref[i])
  1932. * (MAX - PREF)
  1933. * </PRE>
  1934. * <P>
  1935. * The overall effect is that the total size moves that same percentage,
  1936. * k, towards the total minimum or maximum and that percentage guarantees
  1937. * accomodation of the required space, DELTA.
  1938. *
  1939. * <H4>Details</H4>
  1940. * <P>
  1941. * Naive evaluation of the formulae presented here would be subject to
  1942. * the aggregated rounding errors caused by doing this operation in finite
  1943. * precision (using ints). To deal with this, the multiplying factor above,
  1944. * is constantly recalculated and this takes account of the rounding
  1945. * errors in the previous iterations. The result is an algorithm that
  1946. * produces a set of integers whose values exactly sum to the supplied
  1947. * <code>targetSize</code>, and does so by spreading the rounding
  1948. * errors evenly over the given elements.
  1949. *
  1950. * <H4>When the MAX and MIN bounds are hit</H4>
  1951. * <P>
  1952. * When <code>targetSize</code> is outside the [MIN, MAX] range,
  1953. * the algorithm sets all sizes to their appropriate limiting value
  1954. * (maximum or minimum).
  1955. *
  1956. * @param resizingColumn the column whose resizing made this adjustment
  1957. * necessary or -1 if there is no such column
  1958. * @see TableColumn#setWidth
  1959. */
  1960. public void sizeColumnsToFit(int resizingColumn) {
  1961. if (resizingColumn == -1) {
  1962. setWidthsFromPreferredWidths(false);
  1963. }
  1964. else {
  1965. if (autoResizeMode == AUTO_RESIZE_OFF) {
  1966. TableColumn aColumn = getColumnModel().getColumn(resizingColumn);
  1967. aColumn.setPreferredWidth(aColumn.getWidth());
  1968. }
  1969. else {
  1970. int delta = getWidth() - getColumnModel().getTotalColumnWidth();
  1971. accommodateDelta(resizingColumn, delta);
  1972. }
  1973. }
  1974. }
  1975. private void setWidthsFromPreferredWidths(final boolean inverse) {
  1976. int totalWidth = getWidth();
  1977. int totalPreferred = getPreferredSize().width;
  1978. int target = !inverse ? totalWidth : totalPreferred;
  1979. final TableColumnModel cm = columnModel;
  1980. Resizable3 r = new Resizable3() {
  1981. public int getElementCount() { return cm.getColumnCount(); }
  1982. public int getLowerBoundAt(int i) { return cm.getColumn(i).getMinWidth(); }
  1983. public int getUpperBoundAt(int i) { return cm.getColumn(i).getMaxWidth(); }
  1984. public int getMidPointAt(int i) {
  1985. if (!inverse) {
  1986. return cm.getColumn(i).getPreferredWidth();
  1987. }
  1988. else {
  1989. return cm.getColumn(i).getWidth();
  1990. }
  1991. }
  1992. public void setSizeAt(int s, int i) {
  1993. if (!inverse) {
  1994. cm.getColumn(i).setWidth(s);
  1995. }
  1996. else {
  1997. cm.getColumn(i).setPreferredWidth(s);
  1998. }
  1999. }
  2000. };
  2001. adjustSizes(target, r, inverse);
  2002. }
  2003. // Distribute delta over columns, as indicated by the autoresize mode.
  2004. private void accommodateDelta(int resizingColumnIndex, int delta) {
  2005. int columnCount = getColumnCount();
  2006. int from = resizingColumnIndex;
  2007. int to = columnCount;
  2008. // Use the mode to determine how to absorb the changes.
  2009. switch(autoResizeMode) {
  2010. case AUTO_RESIZE_NEXT_COLUMN: from = from + 1; to = from + 1; break;
  2011. case AUTO_RESIZE_SUBSEQUENT_COLUMNS: from = from + 1; to = columnCount; break;
  2012. case AUTO_RESIZE_LAST_COLUMN: from = columnCount - 1; to = from + 1; break;
  2013. case AUTO_RESIZE_ALL_COLUMNS: from = 0; to = columnCount; break;
  2014. default: return;
  2015. }
  2016. final int start = from;
  2017. final int end = to;
  2018. final TableColumnModel cm = columnModel;
  2019. Resizable3 r = new Resizable3() {
  2020. public int getElementCount() { return end-start; }
  2021. public int getLowerBoundAt(int i) { return cm.getColumn(i+start).getMinWidth(); }
  2022. public int getUpperBoundAt(int i) { return cm.getColumn(i+start).getMaxWidth(); }
  2023. public int getMidPointAt(int i) { return cm.getColumn(i+start).getWidth(); }
  2024. public void setSizeAt(int s, int i) { cm.getColumn(i+start).setWidth(s); }
  2025. };
  2026. int totalWidth = 0;
  2027. for(int i = from; i < to; i++) {
  2028. TableColumn aColumn = columnModel.getColumn(i);
  2029. int input = aColumn.getWidth();
  2030. totalWidth = totalWidth + input;
  2031. }
  2032. adjustSizes(totalWidth + delta, r, false);
  2033. setWidthsFromPreferredWidths(true);
  2034. // setWidthsFromPreferredWidths(false);
  2035. return;
  2036. }
  2037. private interface Resizable2 {
  2038. public int getElementCount();
  2039. public int getLowerBoundAt(int i);
  2040. public int getUpperBoundAt(int i);
  2041. public void setSizeAt(int newSize, int i);
  2042. }
  2043. private interface Resizable3 extends Resizable2 {
  2044. public int getMidPointAt(int i);
  2045. }
  2046. private void adjustSizes(long target, final Resizable3 r, boolean inverse) {
  2047. int N = r.getElementCount();
  2048. long totalPreferred = 0;
  2049. for(int i = 0; i < N; i++) {
  2050. totalPreferred += r.getMidPointAt(i);
  2051. }
  2052. Resizable2 s;
  2053. if ((target < totalPreferred) == !inverse) {
  2054. s = new Resizable2() {
  2055. public int getElementCount() { return r.getElementCount(); }
  2056. public int getLowerBoundAt(int i) { return r.getLowerBoundAt(i); }
  2057. public int getUpperBoundAt(int i) { return r.getMidPointAt(i); }
  2058. public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
  2059. };
  2060. }
  2061. else {
  2062. s = new Resizable2() {
  2063. public int getElementCount() { return r.getElementCount(); }
  2064. public int getLowerBoundAt(int i) { return r.getMidPointAt(i); }
  2065. public int getUpperBoundAt(int i) { return r.getUpperBoundAt(i); }
  2066. public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
  2067. };
  2068. }
  2069. adjustSizes(target, s, !inverse);
  2070. }
  2071. private void adjustSizes(long target, Resizable2 r, boolean limitToRange) {
  2072. long totalLowerBound = 0;
  2073. long totalUpperBound = 0;
  2074. for(int i = 0; i < r.getElementCount(); i++) {
  2075. totalLowerBound += r.getLowerBoundAt(i);
  2076. totalUpperBound += r.getUpperBoundAt(i);
  2077. }
  2078. if (limitToRange) {
  2079. target = Math.min(Math.max(totalLowerBound, target), totalUpperBound);
  2080. }
  2081. for(int i = 0; i < r.getElementCount(); i++) {
  2082. int lowerBound = r.getLowerBoundAt(i);
  2083. int upperBound = r.getUpperBoundAt(i);
  2084. // Check for zero. This happens when the distribution of the delta
  2085. // finishes early due to a series of "fixed" entries at the end.
  2086. // In this case, lowerBound == upperBound, for all subsequent terms.
  2087. int newSize;
  2088. if (totalLowerBound == totalUpperBound) {
  2089. newSize = lowerBound;
  2090. }
  2091. else {
  2092. double f = (double)(target - totalLowerBound)/(totalUpperBound - totalLowerBound);
  2093. newSize = (int)Math.round(lowerBound+f*(upperBound - lowerBound));
  2094. // We'd need to round manually in an all integer version.
  2095. // size[i] = (int)(((totalUpperBound - target) * lowerBound +
  2096. // (target - totalLowerBound) * upperBound)/(totalUpperBound-totalLowerBound));
  2097. }
  2098. r.setSizeAt(newSize, i);
  2099. target -= newSize;
  2100. totalLowerBound -= lowerBound;
  2101. totalUpperBound -= upperBound;
  2102. }
  2103. }
  2104. /**
  2105. * Overrides <code>JComponent</code>'s <code>getToolTipText</code>
  2106. * method in order to allow the renderer's tips to be used
  2107. * if it has text set.
  2108. * <p>
  2109. * <bold>Note:</bold> For <code>JTable</code> to properly display
  2110. * tooltips of its renderers
  2111. * <code>JTable</code> must be a registered component with the
  2112. * <code>ToolTipManager</code>.
  2113. * This is done automatically in <code>initializeLocalVars</code>,
  2114. * but if at a later point <code>JTable</code> is told
  2115. * <code>setToolTipText(null)</code> it will unregister the table
  2116. * component, and no tips from renderers will display anymore.
  2117. *
  2118. * @see JComponent#getToolTipText
  2119. */
  2120. public String getToolTipText(MouseEvent event) {
  2121. String tip = null;
  2122. Point p = event.getPoint();
  2123. // Locate the renderer under the event location
  2124. int hitColumnIndex = columnAtPoint(p);
  2125. int hitRowIndex = rowAtPoint(p);
  2126. if ((hitColumnIndex != -1) && (hitRowIndex != -1)) {
  2127. TableCellRenderer renderer = getCellRenderer(hitRowIndex, hitColumnIndex);
  2128. Component component = prepareRenderer(renderer, hitRowIndex, hitColumnIndex);
  2129. // Now have to see if the component is a JComponent before
  2130. // getting the tip
  2131. if (component instanceof JComponent) {
  2132. // Convert the event to the renderer's coordinate system
  2133. Rectangle cellRect = getCellRect(hitRowIndex, hitColumnIndex, false);
  2134. p.translate(-cellRect.x, -cellRect.y);
  2135. MouseEvent newEvent = new MouseEvent(component, event.getID(),
  2136. event.getWhen(), event.getModifiers(),
  2137. p.x, p.y, event.getClickCount(),
  2138. event.isPopupTrigger());
  2139. tip = ((JComponent)component).getToolTipText(newEvent);
  2140. }
  2141. }
  2142. // No tip from the renderer get our own tip
  2143. if (tip == null)
  2144. tip = getToolTipText();
  2145. return tip;
  2146. }
  2147. //
  2148. // Editing Support
  2149. //
  2150. /**
  2151. * Programmatically starts editing the cell at <code>row</code> and
  2152. * <code>column</code>, if the cell is editable.
  2153. *
  2154. * @param row the row to be edited
  2155. * @param column the column to be edited
  2156. * @exception IllegalArgumentException If <code>row</code> or <code>column</code>
  2157. * is not in the valid range
  2158. * @return false if for any reason the cell cannot be edited
  2159. */
  2160. public boolean editCellAt(int row, int column) {
  2161. return editCellAt(row, column, null);
  2162. }
  2163. /**
  2164. * Programmatically starts editing the cell at <code>row</code> and
  2165. * <code>column</code>, if the cell is editable.
  2166. * To prevent the <code>JTable</code> from editing a particular table, column or
  2167. * cell value, return false from the <code>isCellEditable</code> method in the
  2168. * <code>TableModel</code> interface.
  2169. *
  2170. * @param row the row to be edited
  2171. * @param column the column to be edited
  2172. * @param e event to pass into
  2173. * shouldSelectCell
  2174. * @exception IllegalArgumentException If <code>row</code> or <code>column</code>
  2175. * is not in the valid range
  2176. * @return false if for any reason the cell cannot be edited
  2177. */
  2178. public boolean editCellAt(int row, int column, EventObject e){
  2179. if (cellEditor != null && !cellEditor.stopCellEditing()) {
  2180. return false;
  2181. }
  2182. if (row < 0 || row >= getRowCount() ||
  2183. column < 0 || column >= getColumnCount()) {
  2184. return false;
  2185. }
  2186. if (!isCellEditable(row, column))
  2187. return false;
  2188. TableCellEditor editor = getCellEditor(row, column);
  2189. if (editor != null && editor.isCellEditable(e)) {
  2190. editorComp = prepareEditor(editor, row, column);
  2191. if (editorComp == null) {
  2192. removeEditor();
  2193. return false;
  2194. }
  2195. editorComp.setBounds(getCellRect(row, column, false));
  2196. add(editorComp);
  2197. editorComp.validate();
  2198. setCellEditor(editor);
  2199. setEditingRow(row);
  2200. setEditingColumn(column);
  2201. editor.addCellEditorListener(this);
  2202. return true;
  2203. }
  2204. return false;
  2205. }
  2206. /**
  2207. * Returns true if a cell is being edited.
  2208. *
  2209. * @return true if the table is editing a cell
  2210. * @see #editingColumn
  2211. * @see #editingRow
  2212. */
  2213. public boolean isEditing() {
  2214. return (cellEditor == null)? false : true;
  2215. }
  2216. /**
  2217. * Returns the component that is handling the editing session.
  2218. * If nothing is being edited, returns null.
  2219. *
  2220. * @return Component handling editing session
  2221. */
  2222. public Component getEditorComponent() {
  2223. return editorComp;
  2224. }
  2225. /**
  2226. * Returns the index of the column that contains the cell currently
  2227. * being edited. If nothing is being edited, returns -1.
  2228. *
  2229. * @return the index of the column that contains the cell currently
  2230. * being edited; returns -1 if nothing being edited
  2231. * @see #editingRow
  2232. */
  2233. public int getEditingColumn() {
  2234. return editingColumn;
  2235. }
  2236. /**
  2237. * Returns the index of the row that contains the cell currently
  2238. * being edited. If nothing is being edited, returns -1.
  2239. *
  2240. * @return the index of the row that contains the cell currently
  2241. * being edited; returns -1 if nothing being edited
  2242. * @see #editingColumn
  2243. */
  2244. public int getEditingRow() {
  2245. return editingRow;
  2246. }
  2247. //
  2248. // Managing TableUI
  2249. //
  2250. /**
  2251. * Returns the L&F object that renders this component.
  2252. *
  2253. * @return the <code>TableUI</code> object that renders this component
  2254. */
  2255. public TableUI getUI() {
  2256. return (TableUI)ui;
  2257. }
  2258. /**
  2259. * Sets the L&F object that renders this component and repaints.
  2260. *
  2261. * @param ui the TableUI L&F object
  2262. * @see UIDefaults#getUI
  2263. */
  2264. public void setUI(TableUI ui) {
  2265. if (this.ui != ui) {
  2266. super.setUI(ui);
  2267. repaint();
  2268. }
  2269. }
  2270. private void updateSubComponentUI(Object componentShell) {
  2271. if (componentShell == null) {
  2272. return;
  2273. }
  2274. Component component = null;
  2275. if (componentShell instanceof Component) {
  2276. component = (Component)componentShell;
  2277. }
  2278. if (componentShell instanceof DefaultCellEditor) {
  2279. component = ((DefaultCellEditor)componentShell).getComponent();
  2280. }
  2281. if (component != null && component instanceof JComponent) {
  2282. ((JComponent)component).updateUI();
  2283. }
  2284. }
  2285. /**
  2286. * Notification from the <code>UIManager</code> that the L&F has changed.
  2287. * Replaces the current UI object with the latest version from the
  2288. * <code>UIManager</code>.
  2289. *
  2290. * @see JComponent#updateUI
  2291. */
  2292. public void updateUI() {
  2293. // Update the UIs of the cell renderers, cell editors and header renderers.
  2294. TableColumnModel cm = getColumnModel();
  2295. for(int column = 0; column < cm.getColumnCount(); column++) {
  2296. TableColumn aColumn = cm.getColumn(column);
  2297. updateSubComponentUI(aColumn.getCellRenderer());
  2298. updateSubComponentUI(aColumn.getCellEditor());
  2299. updateSubComponentUI(aColumn.getHeaderRenderer());
  2300. }
  2301. // Update the UIs of all the default renderers.
  2302. Enumeration defaultRenderers = defaultRenderersByColumnClass.elements();
  2303. while (defaultRenderers.hasMoreElements()) {
  2304. updateSubComponentUI(defaultRenderers.nextElement());
  2305. }
  2306. // Update the UIs of all the default editors.
  2307. Enumeration defaultEditors = defaultEditorsByColumnClass.elements();
  2308. while (defaultEditors.hasMoreElements()) {
  2309. updateSubComponentUI(defaultEditors.nextElement());
  2310. }
  2311. setUI((TableUI)UIManager.getUI(this));
  2312. resizeAndRepaint();
  2313. }
  2314. /**
  2315. * Returns the suffix used to construct the name of the L&F class used to
  2316. * render this component.
  2317. *
  2318. * @return the string "TableUI"
  2319. * @see JComponent#getUIClassID
  2320. * @see UIDefaults#getUI
  2321. */
  2322. public String getUIClassID() {
  2323. return uiClassID;
  2324. }
  2325. //
  2326. // Managing models
  2327. //
  2328. /**
  2329. * Sets the data model for this table to <code>newModel</code> and registers
  2330. * with it for listener notifications from the new data model.
  2331. *
  2332. * @param newModel the new data source for this table
  2333. * @exception IllegalArgumentException if <code>newModel</code> is <code>null</code>
  2334. * @see #getModel
  2335. * @beaninfo
  2336. * bound: true
  2337. * description: The model that is the source of the data for this view.
  2338. */
  2339. public void setModel(TableModel dataModel) {
  2340. if (dataModel == null) {
  2341. throw new IllegalArgumentException("Cannot set a null TableModel");
  2342. }
  2343. if (this.dataModel != dataModel) {
  2344. TableModel old = this.dataModel;
  2345. if (old != null) {
  2346. old.removeTableModelListener(this);
  2347. }
  2348. this.dataModel = dataModel;
  2349. dataModel.addTableModelListener(this);
  2350. // If this method is called from the JTable constructor,
  2351. // the column model will be null. In this case we can't use
  2352. // the usual methods to update the internal state. In all other
  2353. // cases, use the usual tableChanged() method to reconfigure
  2354. // the JTable for the new model.
  2355. if (getColumnModel() != null) {
  2356. tableChanged(new TableModelEvent(dataModel, TableModelEvent.HEADER_ROW));
  2357. }
  2358. firePropertyChange("model", old, dataModel);
  2359. }
  2360. }
  2361. /**
  2362. * Returns the <code>TableModel</code> that provides the data displayed by this
  2363. * <code>JTable</code>.
  2364. *
  2365. * @return the <code>TableModel</code> that provides the data displayed by this <code>JTable</code>
  2366. * @see #setModel
  2367. */
  2368. public TableModel getModel() {
  2369. return dataModel;
  2370. }
  2371. /**
  2372. * Sets the column model for this table to <code>newModel</code> and registers
  2373. * for listener notifications from the new column model. Also sets
  2374. * the column model of the <code>JTableHeader</code> to <code>columnModel</code>.
  2375. *
  2376. * @param columnModel the new data source for this table
  2377. * @exception IllegalArgumentException if <code>columnModel</code> is <code>null</code>
  2378. * @see #getColumnModel
  2379. * @beaninfo
  2380. * bound: true
  2381. * description: The object governing the way columns appear in the view.
  2382. */
  2383. public void setColumnModel(TableColumnModel columnModel) {
  2384. if (columnModel == null) {
  2385. throw new IllegalArgumentException("Cannot set a null ColumnModel");
  2386. }
  2387. TableColumnModel old = this.columnModel;
  2388. if (columnModel != old) {
  2389. if (old != null) {
  2390. old.removeColumnModelListener(this);
  2391. }
  2392. this.columnModel = columnModel;
  2393. columnModel.addColumnModelListener(this);
  2394. // Set the column model of the header as well.
  2395. if (tableHeader != null) {
  2396. tableHeader.setColumnModel(columnModel);
  2397. }
  2398. firePropertyChange("columnModel", old, columnModel);
  2399. resizeAndRepaint();
  2400. }
  2401. }
  2402. /**
  2403. * Returns the <code>TableColumnModel</code> that contains all column information
  2404. * of this table.
  2405. *
  2406. * @return the object that provides the column state of the table
  2407. * @see #setColumnModel
  2408. */
  2409. public TableColumnModel getColumnModel() {
  2410. return columnModel;
  2411. }
  2412. /**
  2413. * Sets the row selection model for this table to <code>newModel</code>
  2414. * and registers for listener notifications from the new selection model.
  2415. *
  2416. * @param newModel the new selection model
  2417. * @exception IllegalArgumentException if <code>newModel</code> is <code>null</code>
  2418. * @see #getSelectionModel
  2419. * @beaninfo
  2420. * bound: true
  2421. * description: The selection model for rows.
  2422. */
  2423. public void setSelectionModel(ListSelectionModel newModel) {
  2424. if (newModel == null) {
  2425. throw new IllegalArgumentException("Cannot set a null SelectionModel");
  2426. }
  2427. ListSelectionModel oldModel = selectionModel;
  2428. if (newModel != oldModel) {
  2429. if (oldModel != null) {
  2430. oldModel.removeListSelectionListener(this);
  2431. }
  2432. selectionModel = newModel;
  2433. if (newModel != null) {
  2434. newModel.addListSelectionListener(this);
  2435. }
  2436. firePropertyChange("selectionModel", oldModel, newModel);
  2437. repaint();
  2438. }
  2439. }
  2440. /**
  2441. * Returns the <code>ListSelectionModel</code> that is used to maintain row
  2442. * selection state.
  2443. *
  2444. * @return the object that provides row selection state, <code>null</code>
  2445. * if row selection is not allowed
  2446. * @see #setSelectionModel
  2447. */
  2448. public ListSelectionModel getSelectionModel() {
  2449. return selectionModel;
  2450. }
  2451. //
  2452. // Implementing TableModelListener interface
  2453. //
  2454. /**
  2455. * Invoked when this table's <code>TableModel</code> generates
  2456. * a <code>TableModelEvent</code>.
  2457. * The <code>TableModelEvent</code> should be constructed in the
  2458. * coordinate system of the model; the appropriate mapping to the
  2459. * view coordinate system is performed by this <code>JTable</code>
  2460. * when it receives the event.
  2461. * <p>
  2462. * Application code will not use these methods explicitly, they
  2463. * are used internally by JTable.
  2464. */
  2465. public void tableChanged(TableModelEvent e) {
  2466. if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
  2467. // The whole thing changed
  2468. clearSelection();
  2469. if (getAutoCreateColumnsFromModel()) {
  2470. // This will effect invalidation of the JTable and JTableHeader.
  2471. createDefaultColumnsFromModel();
  2472. return;
  2473. }
  2474. resizeAndRepaint();
  2475. return;
  2476. }
  2477. // The totalRowHeight calculated below will be incorrect if
  2478. // there are variable height rows. Repaint the visible region,
  2479. // but don't return as a revalidate may be necessary as well.
  2480. if (rowModel != null) {
  2481. repaint();
  2482. }
  2483. if (e.getType() == TableModelEvent.INSERT) {
  2484. tableRowsInserted(e);
  2485. return;
  2486. }
  2487. if (e.getType() == TableModelEvent.DELETE) {
  2488. tableRowsDeleted(e);
  2489. return;
  2490. }
  2491. int modelColumn = e.getColumn();
  2492. int start = e.getFirstRow();
  2493. int end = e.getLastRow();
  2494. Rectangle dirtyRegion;
  2495. if (modelColumn == TableModelEvent.ALL_COLUMNS) {
  2496. // 1 or more rows changed
  2497. dirtyRegion = new Rectangle(0, start * getRowHeight(),
  2498. getColumnModel().getTotalColumnWidth(), 0);
  2499. }
  2500. else {
  2501. // A cell or column of cells has changed.
  2502. // Unlike the rest of the methods in the JTable, the TableModelEvent
  2503. // uses the coordinate system of the model instead of the view.
  2504. // This is the only place in the JTable where this "reverse mapping"
  2505. // is used.
  2506. int column = convertColumnIndexToView(modelColumn);
  2507. dirtyRegion = getCellRect(start, column, false);
  2508. }
  2509. // Now adjust the height of the dirty region according to the value of "end".
  2510. // Check for Integer.MAX_VALUE as this will cause an overflow.
  2511. if (end != Integer.MAX_VALUE) {
  2512. dirtyRegion.height = (end-start+1)*getRowHeight();
  2513. repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
  2514. }
  2515. // In fact, if the end is Integer.MAX_VALUE we need to revalidate anyway
  2516. // because the scrollbar may need repainting.
  2517. else {
  2518. clearSelection();
  2519. resizeAndRepaint();
  2520. }
  2521. }
  2522. /*
  2523. * Invoked when rows have been inserted into the table.
  2524. * <p>
  2525. * Application code will not use these methods explicitly, they
  2526. * are used internally by JTable.
  2527. *
  2528. * @param e the TableModelEvent encapsulating the insertion
  2529. */
  2530. private void tableRowsInserted(TableModelEvent e) {
  2531. int start = e.getFirstRow();
  2532. int end = e.getLastRow();
  2533. if (start < 0) {
  2534. start = 0;
  2535. }
  2536. if (end < 0) {
  2537. end = getRowCount()-1;
  2538. }
  2539. // Adjust the selection to account for the new rows.
  2540. int length = end - start + 1;
  2541. selectionModel.insertIndexInterval(start, length, true);
  2542. // If we have variable height rows, adjust the row model.
  2543. if (rowModel != null) {
  2544. rowModel.insertEntries(start, length, getRowHeight());
  2545. }
  2546. int rh = getRowHeight() ;
  2547. Rectangle drawRect = new Rectangle(0, start * rh,
  2548. getColumnModel().getTotalColumnWidth(),
  2549. (getRowCount()-start) * rh);
  2550. revalidate();
  2551. // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
  2552. // repaint still required in the unusual case where there is no ScrollPane
  2553. repaint(drawRect);
  2554. }
  2555. /*
  2556. * Invoked when rows have been removed from the table.
  2557. * <p>
  2558. * Application code will not use these methods explicitly, they
  2559. * are used internally by JTable.
  2560. *
  2561. * @param e the TableModelEvent encapsulating the deletion
  2562. */
  2563. private void tableRowsDeleted(TableModelEvent e) {
  2564. int start = e.getFirstRow();
  2565. int end = e.getLastRow();
  2566. if (start < 0) {
  2567. start = 0;
  2568. }
  2569. if (end < 0) {
  2570. end = getRowCount()-1;
  2571. }
  2572. int deletedCount = end - start + 1;
  2573. int previousRowCount = getRowCount() + deletedCount;
  2574. // Adjust the selection to account for the new rows
  2575. selectionModel.removeIndexInterval(start, end);
  2576. // If we have variable height rows, adjust the row model.
  2577. if (rowModel != null) {
  2578. rowModel.removeEntries(start, deletedCount);
  2579. }
  2580. int rh = getRowHeight();
  2581. Rectangle drawRect = new Rectangle(0, start * rh,
  2582. getColumnModel().getTotalColumnWidth(),
  2583. (previousRowCount - start) * rh);
  2584. revalidate();
  2585. // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
  2586. // repaint still required in the unusual case where there is no ScrollPane
  2587. repaint(drawRect);
  2588. }
  2589. //
  2590. // Implementing TableColumnModelListener interface
  2591. //
  2592. /**
  2593. * Invoked when a column is added to the table column model.
  2594. * <p>
  2595. * Application code will not use these methods explicitly, they
  2596. * are used internally by JTable.
  2597. *
  2598. * @see TableColumnModelListener
  2599. */
  2600. public void columnAdded(TableColumnModelEvent e) {
  2601. // If I'm currently editing, then I should stop editing
  2602. if (isEditing()) {
  2603. removeEditor();
  2604. }
  2605. resizeAndRepaint();
  2606. }
  2607. /**
  2608. * Invoked when a column is removed from the table column model.
  2609. * <p>
  2610. * Application code will not use these methods explicitly, they
  2611. * are used internally by JTable.
  2612. *
  2613. * @see TableColumnModelListener
  2614. */
  2615. public void columnRemoved(TableColumnModelEvent e) {
  2616. // If I'm currently editing, then I should stop editing
  2617. if (isEditing()) {
  2618. removeEditor();
  2619. }
  2620. resizeAndRepaint();
  2621. }
  2622. /**
  2623. * Invoked when a column is repositioned. If a cell is being
  2624. * edited, then editing is stopped and the cell is redrawn.
  2625. * <p>
  2626. * Application code will not use these methods explicitly, they
  2627. * are used internally by JTable.
  2628. *
  2629. * @param e the event received
  2630. * @see TableColumnModelListener
  2631. */
  2632. public void columnMoved(TableColumnModelEvent e) {
  2633. // If I'm currently editing, then I should stop editing
  2634. if (isEditing()) {
  2635. removeEditor();
  2636. }
  2637. repaint();
  2638. }
  2639. /**
  2640. * Invoked when a column is moved due to a margin change.
  2641. * If a cell is being edited, then editing is stopped and the cell
  2642. * is redrawn.
  2643. * <p>
  2644. * Application code will not use these methods explicitly, they
  2645. * are used internally by JTable.
  2646. *
  2647. * @param e the event received
  2648. * @see TableColumnModelListener
  2649. */
  2650. public void columnMarginChanged(ChangeEvent e) {
  2651. if (reentrantCall) {
  2652. return;
  2653. }
  2654. reentrantCall = true;
  2655. if (isEditing()) {
  2656. removeEditor();
  2657. }
  2658. TableColumn resizingColumn = null;
  2659. if (tableHeader != null) {
  2660. resizingColumn = tableHeader.getResizingColumn();
  2661. }
  2662. if (resizingColumn != null) {
  2663. if (autoResizeMode == AUTO_RESIZE_OFF) {
  2664. resizingColumn.setPreferredWidth(resizingColumn.getWidth());
  2665. }
  2666. else {
  2667. int columnIndex = viewIndexForColumn(resizingColumn);
  2668. int delta = getWidth() - getColumnModel().getTotalColumnWidth();
  2669. accommodateDelta(columnIndex, delta);
  2670. repaint();
  2671. reentrantCall = false;
  2672. return;
  2673. }
  2674. }
  2675. resizeAndRepaint();
  2676. reentrantCall = false;
  2677. }
  2678. private int limit(int i, int a, int b) {
  2679. return Math.min(b, Math.max(i, a));
  2680. }
  2681. /**
  2682. * Invoked when the selection model of the <code>TableColumnModel</code>
  2683. * is changed.
  2684. * <p>
  2685. * Application code will not use these methods explicitly, they
  2686. * are used internally by JTable.
  2687. *
  2688. * @param e the event received
  2689. * @see TableColumnModelListener
  2690. */
  2691. public void columnSelectionChanged(ListSelectionEvent e) {
  2692. // The getCellRect() call will fail unless there is at least one row.
  2693. if (getRowCount() <= 0 || getColumnCount() <= 0) {
  2694. return;
  2695. }
  2696. int firstIndex = limit(e.getFirstIndex(), 0, getColumnCount()-1);
  2697. int lastIndex = limit(e.getLastIndex(), 0, getColumnCount()-1);
  2698. Rectangle firstColumnRect = getCellRect(0, firstIndex, false);
  2699. Rectangle lastColumnRect = getCellRect(getRowCount()-1, lastIndex, false);
  2700. Rectangle dirtyRegion = firstColumnRect.union(lastColumnRect);
  2701. repaint(dirtyRegion);
  2702. }
  2703. //
  2704. // Implementing ListSelectionListener interface
  2705. //
  2706. /**
  2707. * Invoked when the row selection changes -- repaints to show the new
  2708. * selection.
  2709. * <p>
  2710. * Application code will not use these methods explicitly, they
  2711. * are used internally by JTable.
  2712. *
  2713. * @param e the event received
  2714. * @see ListSelectionListener
  2715. */
  2716. public void valueChanged(ListSelectionEvent e) {
  2717. // The getCellRect() calls will fail unless there is at least one column.
  2718. if (getRowCount() <= 0 || getColumnCount() <= 0) {
  2719. return;
  2720. }
  2721. int firstIndex = limit(e.getFirstIndex(), 0, getRowCount()-1);
  2722. int lastIndex = limit(e.getLastIndex(), 0, getRowCount()-1);
  2723. Rectangle firstRowRect = getCellRect(firstIndex, 0, false);
  2724. Rectangle lastRowRect = getCellRect(lastIndex, getColumnCount()-1, false);
  2725. Rectangle dirtyRegion = firstRowRect.union(lastRowRect);
  2726. repaint(dirtyRegion);
  2727. }
  2728. //
  2729. // Implementing the CellEditorListener interface
  2730. //
  2731. /**
  2732. * Invoked when editing is finished. The changes are saved and the
  2733. * editor is discarded.
  2734. * <p>
  2735. * Application code will not use these methods explicitly, they
  2736. * are used internally by JTable.
  2737. *
  2738. * @param e the event received
  2739. * @see CellEditorListener
  2740. */
  2741. public void editingStopped(ChangeEvent e) {
  2742. // Take in the new value
  2743. TableCellEditor editor = getCellEditor();
  2744. if (editor != null) {
  2745. Object value = editor.getCellEditorValue();
  2746. setValueAt(value, editingRow, editingColumn);
  2747. removeEditor();
  2748. }
  2749. }
  2750. /**
  2751. * Invoked when editing is canceled. The editor object is discarded
  2752. * and the cell is rendered once again.
  2753. * <p>
  2754. * Application code will not use these methods explicitly, they
  2755. * are used internally by JTable.
  2756. *
  2757. * @param e the event received
  2758. * @see CellEditorListener
  2759. */
  2760. public void editingCanceled(ChangeEvent e) {
  2761. removeEditor();
  2762. }
  2763. //
  2764. // Implementing the Scrollable interface
  2765. //
  2766. /**
  2767. * Sets the preferred size of the viewport for this table.
  2768. *
  2769. * @param size a <code>Dimension</code> object specifying the <code>preferredSize</code> of a
  2770. * <code>JViewport</code> whose view is this table
  2771. * @see Scrollable#getPreferredScrollableViewportSize
  2772. * @beaninfo
  2773. * description: The preferred size of the viewport.
  2774. */
  2775. public void setPreferredScrollableViewportSize(Dimension size) {
  2776. preferredViewportSize = size;
  2777. }
  2778. /**
  2779. * Returns the preferred size of the viewport for this table.
  2780. *
  2781. * @return a <code>Dimension</code> object containing the <code>preferredSize</code> of the <code>JViewport</code>
  2782. * which displays this table
  2783. * @see Scrollable#getPreferredScrollableViewportSize
  2784. */
  2785. public Dimension getPreferredScrollableViewportSize() {
  2786. return preferredViewportSize;
  2787. }
  2788. /**
  2789. * Returns the scroll increment (in pixels) that completely exposes one new
  2790. * row or column (depending on the orientation).
  2791. * <p>
  2792. * This method is called each time the user requests a unit scroll.
  2793. *
  2794. * @param visibleRect the view area visible within the viewport
  2795. * @param orientation either <code>SwingConstants.VERTICAL</code>
  2796. * or <code>SwingConstants.HORIZONTAL</code>
  2797. * @param direction less than zero to scroll up/left,
  2798. * greater than zero for down/right
  2799. * @return the "unit" increment for scrolling in the specified direction
  2800. * @see Scrollable#getScrollableUnitIncrement
  2801. */
  2802. public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
  2803. int direction) {
  2804. // PENDING(alan): do something smarter
  2805. if (orientation == SwingConstants.HORIZONTAL) {
  2806. return 100;
  2807. }
  2808. return getRowHeight();
  2809. }
  2810. /**
  2811. * Returns <code>visibleRect.height</code> or
  2812. * <code>visibleRect.width</code>,
  2813. * depending on this table's orientation. Note that as of Swing 1.1.1
  2814. * (Java 2 v 1.2.2) the value
  2815. * returned will ensure that the viewport is cleanly aligned on
  2816. * a row boundary.
  2817. *
  2818. * @return <code>visibleRect.height</code> or
  2819. * <code>visibleRect.width</code>
  2820. * per the orientation
  2821. * @see Scrollable#getScrollableBlockIncrement
  2822. */
  2823. public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation,
  2824. int direction) {
  2825. if (orientation == SwingConstants.VERTICAL) {
  2826. int rh = getRowHeight();
  2827. return (rh > 0) ? Math.max(rh, (visibleRect.height / rh) * rh) : visibleRect.height;
  2828. }
  2829. else {
  2830. return visibleRect.width;
  2831. }
  2832. }
  2833. /**
  2834. * Returns false to indicate that the width of the viewport does not
  2835. * determine the width of the table.
  2836. *
  2837. * @return false
  2838. * @see Scrollable#getScrollableTracksViewportWidth
  2839. */
  2840. public boolean getScrollableTracksViewportWidth() {
  2841. return !(autoResizeMode == AUTO_RESIZE_OFF);
  2842. }
  2843. /**
  2844. * Returns false to indicate that the height of the viewport does not
  2845. * determine the height of the table.
  2846. *
  2847. * @return false
  2848. * @see Scrollable#getScrollableTracksViewportHeight
  2849. */
  2850. public boolean getScrollableTracksViewportHeight() {
  2851. return false;
  2852. }
  2853. //
  2854. // Protected Methods
  2855. //
  2856. protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
  2857. int condition, boolean pressed) {
  2858. boolean retValue = super.processKeyBinding(ks, e, condition, pressed);
  2859. if (!retValue && condition == WHEN_ANCESTOR_OF_FOCUSED_COMPONENT &&
  2860. hasFocus()) {
  2861. // We do not have a binding for the event.
  2862. Component editorComponent = getEditorComponent();
  2863. if (editorComponent == null) {
  2864. // Only attempt to install the editor on a KEY_PRESSED,
  2865. if (e == null || e.getID() != KeyEvent.KEY_PRESSED) {
  2866. return false;
  2867. }
  2868. // Don't start when just a modifier is pressed
  2869. int code = e.getKeyCode();
  2870. if (code == KeyEvent.VK_SHIFT || code == KeyEvent.VK_CONTROL ||
  2871. code == KeyEvent.VK_ALT) {
  2872. return false;
  2873. }
  2874. // Try to install the editor
  2875. int anchorRow = getSelectionModel().getAnchorSelectionIndex();
  2876. int anchorColumn = getColumnModel().getSelectionModel().
  2877. getAnchorSelectionIndex();
  2878. if (anchorRow != -1 && anchorColumn != -1 && !isEditing()) {
  2879. if (!editCellAt(anchorRow, anchorColumn)) {
  2880. return false;
  2881. }
  2882. }
  2883. editorComponent = getEditorComponent();
  2884. if (editorComponent == null) {
  2885. return false;
  2886. }
  2887. }
  2888. // If the editorComponent is a JComponent, pass the event to it.
  2889. if (editorComponent instanceof JComponent) {
  2890. retValue = ((JComponent)editorComponent).processKeyBinding
  2891. (ks, e, WHEN_FOCUSED, pressed);
  2892. }
  2893. }
  2894. return retValue;
  2895. }
  2896. private void setLazyValue(Hashtable h, Class c, String s) {
  2897. h.put(c, new UIDefaults.ProxyLazyValue(s));
  2898. }
  2899. private void setLazyRenderer(Class c, String s) {
  2900. setLazyValue(defaultRenderersByColumnClass, c, s);
  2901. }
  2902. /**
  2903. * Creates default cell renderers for objects, numbers, doubles, dates,
  2904. * booleans, and icons.
  2905. * @see javax.swing.table.DefaultTableCellRenderer
  2906. *
  2907. */
  2908. protected void createDefaultRenderers() {
  2909. defaultRenderersByColumnClass = new UIDefaults();
  2910. // Objects
  2911. setLazyRenderer(Object.class, "javax.swing.table.DefaultTableCellRenderer");
  2912. // Numbers
  2913. setLazyRenderer(Number.class, "javax.swing.JTable$NumberRenderer");
  2914. // Doubles and Floats
  2915. setLazyRenderer(Float.class, "javax.swing.JTable$DoubleRenderer");
  2916. setLazyRenderer(Double.class, "javax.swing.JTable$DoubleRenderer");
  2917. // Dates
  2918. setLazyRenderer(Date.class, "javax.swing.JTable$DateRenderer");
  2919. // Icons and ImageIcons
  2920. setLazyRenderer(Icon.class, "javax.swing.JTable$IconRenderer");
  2921. setLazyRenderer(ImageIcon.class, "javax.swing.JTable$IconRenderer");
  2922. // Booleans
  2923. setLazyRenderer(Boolean.class, "javax.swing.JTable$BooleanRenderer");
  2924. }
  2925. /**
  2926. * Default Renderers
  2927. **/
  2928. static class NumberRenderer extends DefaultTableCellRenderer {
  2929. public NumberRenderer() {
  2930. super();
  2931. setHorizontalAlignment(JLabel.RIGHT);
  2932. }
  2933. }
  2934. static class DoubleRenderer extends NumberRenderer {
  2935. NumberFormat formatter;
  2936. public DoubleRenderer() { super(); }
  2937. public void setValue(Object value) {
  2938. if (formatter == null) {
  2939. formatter = NumberFormat.getInstance();
  2940. }
  2941. setText((value == null) ? "" : formatter.format(value));
  2942. }
  2943. }
  2944. static class DateRenderer extends DefaultTableCellRenderer {
  2945. DateFormat formatter;
  2946. public DateRenderer() { super(); }
  2947. public void setValue(Object value) {
  2948. if (formatter==null) {
  2949. formatter = DateFormat.getDateInstance();
  2950. }
  2951. setText((value == null) ? "" : formatter.format(value));
  2952. }
  2953. }
  2954. static class IconRenderer extends DefaultTableCellRenderer {
  2955. public IconRenderer() {
  2956. super();
  2957. setHorizontalAlignment(JLabel.CENTER);
  2958. }
  2959. public void setValue(Object value) { setIcon((value instanceof Icon) ? (Icon)value : null); }
  2960. }
  2961. static class BooleanRenderer extends JCheckBox implements TableCellRenderer
  2962. {
  2963. public BooleanRenderer() {
  2964. super();
  2965. setHorizontalAlignment(JLabel.CENTER);
  2966. }
  2967. public Component getTableCellRendererComponent(JTable table, Object value,
  2968. boolean isSelected, boolean hasFocus, int row, int column) {
  2969. if (isSelected) {
  2970. setForeground(table.getSelectionForeground());
  2971. super.setBackground(table.getSelectionBackground());
  2972. }
  2973. else {
  2974. setForeground(table.getForeground());
  2975. setBackground(table.getBackground());
  2976. }
  2977. setSelected((value != null && ((Boolean)value).booleanValue()));
  2978. return this;
  2979. }
  2980. }
  2981. private void setLazyEditor(Class c, String s) {
  2982. setLazyValue(defaultEditorsByColumnClass, c, s);
  2983. }
  2984. /**
  2985. * Creates default cell editors for objects, numbers, and boolean values.
  2986. * @see DefaultCellEditor
  2987. */
  2988. protected void createDefaultEditors() {
  2989. defaultEditorsByColumnClass = new UIDefaults();
  2990. // Objects
  2991. setLazyEditor(Object.class, "javax.swing.JTable$GenericEditor");
  2992. // Numbers
  2993. setLazyEditor(Number.class, "javax.swing.JTable$NumberEditor");
  2994. // Booleans
  2995. setLazyEditor(Boolean.class, "javax.swing.JTable$BooleanEditor");
  2996. }
  2997. /**
  2998. * Default Editors
  2999. */
  3000. static class GenericEditor extends DefaultCellEditor {
  3001. Class[] argTypes = new Class[]{String.class};
  3002. java.lang.reflect.Constructor constructor;
  3003. Object value;
  3004. public GenericEditor() { super(new JTextField()); }
  3005. public boolean stopCellEditing() {
  3006. String s = (String)super.getCellEditorValue();
  3007. // Here we are dealing with the case where a user
  3008. // has deleted the string value in a cell, possibly
  3009. // after a failed validation. Return null, so that
  3010. // they have the option to replace the value with
  3011. // null or use escape to restore the original.
  3012. // For Strings, return "" for backward compatibility.
  3013. if ("".equals(s)) {
  3014. if (constructor.getDeclaringClass() == String.class) {
  3015. value = s;
  3016. }
  3017. super.stopCellEditing();
  3018. }
  3019. try {
  3020. value = constructor.newInstance(new Object[]{s});
  3021. }
  3022. catch (Exception e) {
  3023. ((JComponent)getComponent()).setBorder(new LineBorder(Color.red));
  3024. return false;
  3025. }
  3026. return super.stopCellEditing();
  3027. }
  3028. public Component getTableCellEditorComponent(JTable table, Object value,
  3029. boolean isSelected,
  3030. int row, int column) {
  3031. this.value = null;
  3032. ((JComponent)getComponent()).setBorder(new LineBorder(Color.black));
  3033. try {
  3034. Class type = table.getColumnClass(column);
  3035. // Since our obligation is to produce a value which is
  3036. // assignable for the required type it is OK to use the
  3037. // String constructor for columns which are declared
  3038. // to contain Objects. A String is an Object.
  3039. if (type == Object.class) {
  3040. type = String.class;
  3041. }
  3042. constructor = type.getConstructor(argTypes);
  3043. }
  3044. catch (Exception e) {
  3045. return null;
  3046. }
  3047. return super.getTableCellEditorComponent(table, value, isSelected, row, column);
  3048. }
  3049. public Object getCellEditorValue() {
  3050. return value;
  3051. }
  3052. }
  3053. static class NumberEditor extends GenericEditor {
  3054. public NumberEditor() {
  3055. ((JTextField)getComponent()).setHorizontalAlignment(JTextField.RIGHT);
  3056. }
  3057. }
  3058. static class BooleanEditor extends DefaultCellEditor {
  3059. public BooleanEditor() {
  3060. super(new JCheckBox());
  3061. JCheckBox checkBox = (JCheckBox)getComponent();
  3062. checkBox.setHorizontalAlignment(JCheckBox.CENTER);
  3063. }
  3064. }
  3065. /**
  3066. * Initializes table properties to their default values.
  3067. */
  3068. protected void initializeLocalVars() {
  3069. getSelectionModel().setAnchorSelectionIndex(0);
  3070. setOpaque(true);
  3071. createDefaultRenderers();
  3072. createDefaultEditors();
  3073. setTableHeader(createDefaultTableHeader());
  3074. setShowGrid(true);
  3075. setAutoResizeMode(AUTO_RESIZE_SUBSEQUENT_COLUMNS);
  3076. setRowHeight(16);
  3077. setRowMargin(1);
  3078. setRowSelectionAllowed(true);
  3079. setCellEditor(null);
  3080. setEditingColumn(-1);
  3081. setEditingRow(-1);
  3082. setPreferredScrollableViewportSize(new Dimension(450, 400));
  3083. // I'm registered to do tool tips so we can draw tips for the renderers
  3084. ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
  3085. toolTipManager.registerComponent(this);
  3086. setAutoscrolls(true);
  3087. }
  3088. /**
  3089. * Returns the default table model object, which is
  3090. * a <code>DefaultTableModel</code>. A subclass can override this
  3091. * method to return a different table model object.
  3092. *
  3093. * @return the default table model object
  3094. * @see javax.swing.table.DefaultTableModel
  3095. */
  3096. protected TableModel createDefaultDataModel() {
  3097. return new DefaultTableModel();
  3098. }
  3099. /**
  3100. * Returns the default column model object, which is
  3101. * a <code>DefaultTableColumnModel</code>. A subclass can override this
  3102. * method to return a different column model object.
  3103. *
  3104. * @return the default column model object
  3105. * @see javax.swing.table.DefaultTableColumnModel
  3106. */
  3107. protected TableColumnModel createDefaultColumnModel() {
  3108. return new DefaultTableColumnModel();
  3109. }
  3110. /**
  3111. * Returns the default selection model object, which is
  3112. * a <code>DefaultListSelectionModel</code>. A subclass can override this
  3113. * method to return a different selection model object.
  3114. *
  3115. * @return the default selection model object
  3116. * @see javax.swing.DefaultListSelectionModel
  3117. */
  3118. protected ListSelectionModel createDefaultSelectionModel() {
  3119. return new DefaultListSelectionModel();
  3120. }
  3121. /**
  3122. * Returns the default table header object, which is
  3123. * a <code>JTableHeader</code>. A subclass can override this
  3124. * method to return a different table header object.
  3125. *
  3126. * @return the default table header object
  3127. * @see javax.swing.table.JTableHeader
  3128. */
  3129. protected JTableHeader createDefaultTableHeader() {
  3130. return new JTableHeader(columnModel);
  3131. }
  3132. /**
  3133. * Equivalent to <code>revalidate</code> followed by <code>repaint</code>.
  3134. */
  3135. protected void resizeAndRepaint() {
  3136. revalidate();
  3137. repaint();
  3138. }
  3139. /**
  3140. * Returns the cell editor.
  3141. *
  3142. * @return the <code>TableCellEditor</code> that does the editing
  3143. * @see #cellEditor
  3144. */
  3145. public TableCellEditor getCellEditor() {
  3146. return cellEditor;
  3147. }
  3148. /**
  3149. * Sets the <code>cellEditor</code> variable.
  3150. *
  3151. * @param anEditor the TableCellEditor that does the editing
  3152. * @see #cellEditor
  3153. * @beaninfo
  3154. * bound: true
  3155. * description: The table's active cell editor, if one exists.
  3156. */
  3157. public void setCellEditor(TableCellEditor anEditor) {
  3158. TableCellEditor oldEditor = cellEditor;
  3159. cellEditor = anEditor;
  3160. firePropertyChange("tableCellEditor", oldEditor, anEditor);
  3161. }
  3162. /**
  3163. * Sets the <code>editingColumn</code> variable.
  3164. * @param aColumn the column of the cell to be edited
  3165. *
  3166. * @see #editingColumn
  3167. */
  3168. public void setEditingColumn(int aColumn) {
  3169. editingColumn = aColumn;
  3170. }
  3171. /**
  3172. * Sets the <code>editingRow</code> variable.
  3173. * @param aRow the row of the cell to be edited
  3174. *
  3175. * @see #editingRow
  3176. */
  3177. public void setEditingRow(int aRow) {
  3178. editingRow = aRow;
  3179. }
  3180. /**
  3181. * Returns an appropriate renderer for the cell specified by this row and
  3182. * column. If the <code>TableColumn</code> for this column has a non-null
  3183. * renderer, returns that. If not, finds the class of the data in
  3184. * this column (using <code>getColumnClass</code>)
  3185. * and returns the default renderer for this type of data.
  3186. * <p>
  3187. * <b>Note:</b>
  3188. * Throughout the table package, the internal implementations always
  3189. * use this method to provide renderers so that this default behavior
  3190. * can be safely overridden by a subclass.
  3191. *
  3192. * @param row the row of the cell to render, where 0 is the first row
  3193. * @param column the column of the cell to render,
  3194. * where 0 is the first column
  3195. * @return the assigned renderer; if <code>null</code>
  3196. * returns the default renderer
  3197. * for this type of object
  3198. * @see javax.swing.table.DefaultTableCellRenderer
  3199. * @see javax.swing.table.TableColumn#setCellRenderer
  3200. * @see #setDefaultRenderer
  3201. */
  3202. public TableCellRenderer getCellRenderer(int row, int column) {
  3203. TableColumn tableColumn = getColumnModel().getColumn(column);
  3204. TableCellRenderer renderer = tableColumn.getCellRenderer();
  3205. if (renderer == null) {
  3206. renderer = getDefaultRenderer(getColumnClass(column));
  3207. }
  3208. return renderer;
  3209. }
  3210. /**
  3211. * Prepares the renderer by querying the data model for the
  3212. * value and selection state
  3213. * of the cell at <code>row</code>, <code>column</code>.
  3214. * <p>
  3215. * <b>Note:</b>
  3216. * Throughout the table package, the internal implementations always
  3217. * use this method to prepare renderers so that this default behavior
  3218. * can be safely overridden by a subclass.
  3219. *
  3220. * @param renderer the <code>TableCellRenderer</code> to prepare
  3221. * @param row the row of the cell to render, where 0 is the first row
  3222. * @param column the column of the cell to render,
  3223. * where 0 is the first column
  3224. */
  3225. public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
  3226. Object value = getValueAt(row, column);
  3227. boolean isSelected = isCellSelected(row, column);
  3228. boolean rowIsAnchor = (selectionModel.getAnchorSelectionIndex() == row);
  3229. boolean colIsAnchor =
  3230. (columnModel.getSelectionModel().getAnchorSelectionIndex() == column);
  3231. boolean hasFocus = (rowIsAnchor && colIsAnchor) && hasFocus();
  3232. return renderer.getTableCellRendererComponent(this, value,
  3233. isSelected, hasFocus,
  3234. row, column);
  3235. }
  3236. /**
  3237. * Returns an appropriate editor for the cell specified by
  3238. * <code>row</code> and <code>column</code>. If the
  3239. * <code>TableColumn</code> for this column has a non-null editor,
  3240. * returns that. If not, finds the class of the data in this
  3241. * column (using <code>getColumnClass</code>)
  3242. * and returns the default editor for this type of data.
  3243. * <p>
  3244. * <b>Note:</b>
  3245. * Throughout the table package, the internal implementations always
  3246. * use this method to provide editors so that this default behavior
  3247. * can be safely overridden by a subclass.
  3248. *
  3249. * @param row the row of the cell to edit, where 0 is the first row
  3250. * @param column the column of the cell to edit,
  3251. * where 0 is the first column
  3252. * @return the editor for this cell;
  3253. * if <code>null</code> return the default editor for
  3254. * this type of cell
  3255. * @see DefaultCellEditor
  3256. */
  3257. public TableCellEditor getCellEditor(int row, int column) {
  3258. TableColumn tableColumn = getColumnModel().getColumn(column);
  3259. TableCellEditor editor = tableColumn.getCellEditor();
  3260. if (editor == null) {
  3261. editor = getDefaultEditor(getColumnClass(column));
  3262. }
  3263. return editor;
  3264. }
  3265. /**
  3266. * Prepares the editor by querying the data model for the value and
  3267. * selection state of the cell at <code>row</code>, <code>column</code>.
  3268. * <p>
  3269. * <b>Note:</b>
  3270. * Throughout the table package, the internal implementations always
  3271. * use this method to prepare editors so that this default behavior
  3272. * can be safely overridden by a subclass.
  3273. *
  3274. * @param editor the <code>TableCellEditor</code> to set up
  3275. * @param row the row of the cell to edit,
  3276. * where 0 is the first row
  3277. * @param column the column of the cell to edit,
  3278. * where 0 is the first column
  3279. * @return the <code>Component</code> being edited
  3280. */
  3281. public Component prepareEditor(TableCellEditor editor, int row, int column) {
  3282. Object value = getValueAt(row, column);
  3283. boolean isSelected = isCellSelected(row, column);
  3284. Component comp = editor.getTableCellEditorComponent(this, value, isSelected,
  3285. row, column);
  3286. if (comp instanceof JComponent) {
  3287. ((JComponent)comp).setNextFocusableComponent(this);
  3288. }
  3289. return comp;
  3290. }
  3291. /**
  3292. * Discards the editor object and frees the real estate it used for
  3293. * cell rendering.
  3294. */
  3295. public void removeEditor() {
  3296. TableCellEditor editor = getCellEditor();
  3297. if(editor != null) {
  3298. editor.removeCellEditorListener(this);
  3299. requestFocus();
  3300. if (editorComp != null) {
  3301. remove(editorComp);
  3302. }
  3303. Rectangle cellRect = getCellRect(editingRow, editingColumn, false);
  3304. setCellEditor(null);
  3305. setEditingColumn(-1);
  3306. setEditingRow(-1);
  3307. editorComp = null;
  3308. repaint(cellRect);
  3309. }
  3310. }
  3311. //
  3312. // Serialization
  3313. //
  3314. /**
  3315. * See readObject() and writeObject() in JComponent for more
  3316. * information about serialization in Swing.
  3317. */
  3318. private void writeObject(ObjectOutputStream s) throws IOException {
  3319. s.defaultWriteObject();
  3320. if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  3321. ui.installUI(this);
  3322. }
  3323. }
  3324. private void readObject(ObjectInputStream s)
  3325. throws IOException, ClassNotFoundException
  3326. {
  3327. s.defaultReadObject();
  3328. if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  3329. ui.installUI(this);
  3330. }
  3331. createDefaultRenderers();
  3332. createDefaultEditors();
  3333. // If ToolTipText != null, then the tooltip has already been
  3334. // registered by JComponent.readObject() and we don't want
  3335. // to re-register here
  3336. if (getToolTipText() == null) {
  3337. ToolTipManager.sharedInstance().registerComponent(this);
  3338. }
  3339. }
  3340. /* Called from the JComponent's EnableSerializationFocusListener to
  3341. * do any Swing-specific pre-serialization configuration.
  3342. */
  3343. void compWriteObjectNotify() {
  3344. super.compWriteObjectNotify();
  3345. // If ToolTipText != null, then the tooltip has already been
  3346. // unregistered by JComponent.compWriteObjectNotify()
  3347. if (getToolTipText() == null) {
  3348. ToolTipManager.sharedInstance().unregisterComponent(this);
  3349. }
  3350. }
  3351. /**
  3352. * Returns a string representation of this table. This method
  3353. * is intended to be used only for debugging purposes, and the
  3354. * content and format of the returned string may vary between
  3355. * implementations. The returned string may be empty but may not
  3356. * be <code>null</code>.
  3357. *
  3358. * @return a string representation of this table
  3359. */
  3360. protected String paramString() {
  3361. String gridColorString = (gridColor != null ?
  3362. gridColor.toString() : "");
  3363. String showHorizontalLinesString = (showHorizontalLines ?
  3364. "true" : "false");
  3365. String showVerticalLinesString = (showVerticalLines ?
  3366. "true" : "false");
  3367. String autoResizeModeString;
  3368. if (autoResizeMode == AUTO_RESIZE_OFF) {
  3369. autoResizeModeString = "AUTO_RESIZE_OFF";
  3370. } else if (autoResizeMode == AUTO_RESIZE_NEXT_COLUMN) {
  3371. autoResizeModeString = "AUTO_RESIZE_NEXT_COLUMN";
  3372. } else if (autoResizeMode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) {
  3373. autoResizeModeString = "AUTO_RESIZE_SUBSEQUENT_COLUMNS";
  3374. } else if (autoResizeMode == AUTO_RESIZE_LAST_COLUMN) {
  3375. autoResizeModeString = "AUTO_RESIZE_LAST_COLUMN";
  3376. } else if (autoResizeMode == AUTO_RESIZE_ALL_COLUMNS) {
  3377. autoResizeModeString = "AUTO_RESIZE_ALL_COLUMNS";
  3378. } else autoResizeModeString = "";
  3379. String autoCreateColumnsFromModelString = (autoCreateColumnsFromModel ?
  3380. "true" : "false");
  3381. String preferredViewportSizeString = (preferredViewportSize != null ?
  3382. preferredViewportSize.toString()
  3383. : "");
  3384. String rowSelectionAllowedString = (rowSelectionAllowed ?
  3385. "true" : "false");
  3386. String cellSelectionEnabledString = (cellSelectionEnabled ?
  3387. "true" : "false");
  3388. String selectionForegroundString = (selectionForeground != null ?
  3389. selectionForeground.toString() :
  3390. "");
  3391. String selectionBackgroundString = (selectionBackground != null ?
  3392. selectionBackground.toString() :
  3393. "");
  3394. return super.paramString() +
  3395. ",autoCreateColumnsFromModel=" + autoCreateColumnsFromModelString +
  3396. ",autoResizeMode=" + autoResizeModeString +
  3397. ",cellSelectionEnabled=" + cellSelectionEnabledString +
  3398. ",editingColumn=" + editingColumn +
  3399. ",editingRow=" + editingRow +
  3400. ",gridColor=" + gridColorString +
  3401. ",preferredViewportSize=" + preferredViewportSizeString +
  3402. ",rowHeight=" + rowHeight +
  3403. ",rowMargin=" + rowMargin +
  3404. ",rowSelectionAllowed=" + rowSelectionAllowedString +
  3405. ",selectionBackground=" + selectionBackgroundString +
  3406. ",selectionForeground=" + selectionForegroundString +
  3407. ",showHorizontalLines=" + showHorizontalLinesString +
  3408. ",showVerticalLines=" + showVerticalLinesString;
  3409. }
  3410. /**
  3411. * We override this method, whose implementation in <code>JComponent</code>
  3412. * returns false, to return true. This allows us to give a special
  3413. * meaning to TAB and SHIFT-TAB in the <code>JTable</code>.
  3414. * @return true
  3415. */
  3416. public boolean isManagingFocus() {
  3417. return true;
  3418. }
  3419. /**
  3420. * We override this method, whose implementation in <code>JComponent</code>
  3421. * returns false, to return true. This indicates that the <code>JTable</code>
  3422. * is a component that should be part of a (tabbing) focus cycle
  3423. * by default.
  3424. * @return true
  3425. */
  3426. public boolean isFocusTraversable() {
  3427. return true;
  3428. }
  3429. /////////////////
  3430. // Accessibility support
  3431. ////////////////
  3432. /**
  3433. * Gets the AccessibleContext associated with this JTable.
  3434. * For tables, the AccessibleContext takes the form of an
  3435. * AccessibleJTable.
  3436. * A new AccessibleJTable instance is created if necessary.
  3437. *
  3438. * @return an AccessibleJTable that serves as the
  3439. * AccessibleContext of this JTable
  3440. */
  3441. public AccessibleContext getAccessibleContext() {
  3442. if (accessibleContext == null) {
  3443. accessibleContext = new AccessibleJTable();
  3444. }
  3445. return accessibleContext;
  3446. }
  3447. //
  3448. // *** should also implement AccessibleSelection?
  3449. // *** and what's up with keyboard navigation/manipulation?
  3450. //
  3451. /**
  3452. * This class implements accessibility support for the
  3453. * <code>JTable</code> class. It provides an implementation of the
  3454. * Java Accessibility API appropriate to table user-interface elements.
  3455. * <p>
  3456. * <strong>Warning:</strong>
  3457. * Serialized objects of this class will not be compatible with
  3458. * future Swing releases. The current serialization support is appropriate
  3459. * for short term storage or RMI between applications running the same
  3460. * version of Swing. A future release of Swing will provide support for
  3461. * long term persistence.
  3462. */
  3463. protected class AccessibleJTable extends AccessibleJComponent
  3464. implements AccessibleSelection, ListSelectionListener, TableModelListener,
  3465. TableColumnModelListener, CellEditorListener, PropertyChangeListener,
  3466. AccessibleTable {
  3467. int lastSelectedRow;
  3468. int lastSelectedCol;
  3469. AccessibleJTable() {
  3470. super();
  3471. JTable.this.addPropertyChangeListener(this);
  3472. JTable.this.getSelectionModel().addListSelectionListener(this);
  3473. TableColumnModel tcm = JTable.this.getColumnModel();
  3474. tcm.addColumnModelListener(this);
  3475. tcm.getSelectionModel().addListSelectionListener(this);
  3476. JTable.this.getModel().addTableModelListener(this);
  3477. lastSelectedRow = JTable.this.getSelectedRow();
  3478. lastSelectedCol = JTable.this.getSelectedColumn();
  3479. }
  3480. // Listeners to track model, etc. changes to as to re-place the other
  3481. // listeners
  3482. /**
  3483. * Track changes to selection model, column model, etc. so as to
  3484. * be able to re-place listeners on those in order to pass on
  3485. * information to the Accessibility PropertyChange mechanism
  3486. */
  3487. public void propertyChange(PropertyChangeEvent e) {
  3488. String name = e.getPropertyName();
  3489. Object oldValue = e.getOldValue();
  3490. Object newValue = e.getNewValue();
  3491. // re-set tableModel listeners
  3492. if (name.compareTo("model") == 0) {
  3493. if (oldValue != null && oldValue instanceof TableModel) {
  3494. ((TableModel) oldValue).removeTableModelListener(this);
  3495. }
  3496. if (newValue != null && newValue instanceof TableModel) {
  3497. ((TableModel) newValue).addTableModelListener(this);
  3498. }
  3499. // re-set selectionModel listeners
  3500. } else if (name.compareTo("selectionModel") == 0) {
  3501. Object source = e.getSource();
  3502. if (source == JTable.this) { // row selection model
  3503. if (oldValue != null &&
  3504. oldValue instanceof ListSelectionModel) {
  3505. ((ListSelectionModel) oldValue).removeListSelectionListener(this);
  3506. }
  3507. if (newValue != null &&
  3508. newValue instanceof ListSelectionModel) {
  3509. ((ListSelectionModel) newValue).addListSelectionListener(this);
  3510. }
  3511. } else if (source == JTable.this.getColumnModel()) {
  3512. if (oldValue != null &&
  3513. oldValue instanceof ListSelectionModel) {
  3514. ((ListSelectionModel) oldValue).removeListSelectionListener(this);
  3515. }
  3516. if (newValue != null &&
  3517. newValue instanceof ListSelectionModel) {
  3518. ((ListSelectionModel) newValue).addListSelectionListener(this);
  3519. }
  3520. } else {
  3521. // System.out.println("!!! Bug in source of selectionModel propertyChangeEvent");
  3522. }
  3523. // re-set columnModel listeners
  3524. // and column's selection property listener as well
  3525. } else if (name.compareTo("columnModel") == 0) {
  3526. if (oldValue != null && oldValue instanceof TableColumnModel) {
  3527. TableColumnModel tcm = (TableColumnModel) oldValue;
  3528. tcm.removeColumnModelListener(this);
  3529. tcm.getSelectionModel().removeListSelectionListener(this);
  3530. }
  3531. if (newValue != null && newValue instanceof TableColumnModel) {
  3532. TableColumnModel tcm = (TableColumnModel) oldValue;
  3533. tcm.addColumnModelListener(this);
  3534. tcm.getSelectionModel().addListSelectionListener(this);
  3535. }
  3536. // re-se cellEditor listeners
  3537. } else if (name.compareTo("tableCellEditor") == 0) {
  3538. if (oldValue != null && oldValue instanceof TableCellEditor) {
  3539. ((TableCellEditor) oldValue).removeCellEditorListener((CellEditorListener) this);
  3540. }
  3541. if (newValue != null && newValue instanceof TableCellEditor) {
  3542. ((TableCellEditor) newValue).addCellEditorListener((CellEditorListener) this);
  3543. }
  3544. }
  3545. }
  3546. // Listeners to echo changes to the AccessiblePropertyChange mechanism
  3547. /*
  3548. * Describes a change in the accessible table model.
  3549. */
  3550. protected class AccessibleJTableModelChange
  3551. implements AccessibleTableModelChange {
  3552. protected int type;
  3553. protected int firstRow;
  3554. protected int lastRow;
  3555. protected int firstColumn;
  3556. protected int lastColumn;
  3557. protected AccessibleJTableModelChange(int type, int firstRow,
  3558. int lastRow, int firstColumn,
  3559. int lastColumn) {
  3560. this.type = type;
  3561. this.firstRow = firstRow;
  3562. this.lastRow = lastRow;
  3563. this.firstColumn = firstColumn;
  3564. this.lastColumn = lastColumn;
  3565. }
  3566. public int getType() {
  3567. return type;
  3568. }
  3569. public int getFirstRow() {
  3570. return firstRow;
  3571. }
  3572. public int getLastRow() {
  3573. return lastRow;
  3574. }
  3575. public int getFirstColumn() {
  3576. return firstColumn;
  3577. }
  3578. public int getLastColumn() {
  3579. return lastColumn;
  3580. }
  3581. }
  3582. /**
  3583. * Track changes to the table contents
  3584. */
  3585. public void tableChanged(TableModelEvent e) {
  3586. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3587. null, null);
  3588. int firstColumn = e.getColumn();
  3589. int lastColumn = e.getColumn();
  3590. if (firstColumn == TableModelEvent.ALL_COLUMNS) {
  3591. firstColumn = 0;
  3592. lastColumn = getColumnCount() - 1;
  3593. }
  3594. // Fire a property change event indicating the table model
  3595. // has changed.
  3596. AccessibleJTableModelChange change =
  3597. new AccessibleJTableModelChange(e.getType(),
  3598. e.getFirstRow(),
  3599. e.getLastRow(),
  3600. firstColumn,
  3601. lastColumn);
  3602. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  3603. null, change);
  3604. }
  3605. /**
  3606. * Track changes to the table contents (row insertions)
  3607. */
  3608. public void tableRowsInserted(TableModelEvent e) {
  3609. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3610. null, null);
  3611. // Fire a property change event indicating the table model
  3612. // has changed.
  3613. int firstColumn = e.getColumn();
  3614. int lastColumn = e.getColumn();
  3615. if (firstColumn == TableModelEvent.ALL_COLUMNS) {
  3616. firstColumn = 0;
  3617. lastColumn = getColumnCount() - 1;
  3618. }
  3619. AccessibleJTableModelChange change =
  3620. new AccessibleJTableModelChange(e.getType(),
  3621. e.getFirstRow(),
  3622. e.getLastRow(),
  3623. firstColumn,
  3624. lastColumn);
  3625. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  3626. null, change);
  3627. }
  3628. /**
  3629. * Track changes to the table contents (row deletions)
  3630. */
  3631. public void tableRowsDeleted(TableModelEvent e) {
  3632. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3633. null, null);
  3634. // Fire a property change event indicating the table model
  3635. // has changed.
  3636. int firstColumn = e.getColumn();
  3637. int lastColumn = e.getColumn();
  3638. if (firstColumn == TableModelEvent.ALL_COLUMNS) {
  3639. firstColumn = 0;
  3640. lastColumn = getColumnCount() - 1;
  3641. }
  3642. AccessibleJTableModelChange change =
  3643. new AccessibleJTableModelChange(e.getType(),
  3644. e.getFirstRow(),
  3645. e.getLastRow(),
  3646. firstColumn,
  3647. lastColumn);
  3648. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  3649. null, change);
  3650. }
  3651. /**
  3652. * Track changes to the table contents (column insertions)
  3653. */
  3654. public void columnAdded(TableColumnModelEvent e) {
  3655. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3656. null, null);
  3657. // Fire a property change event indicating the table model
  3658. // has changed.
  3659. int type = AccessibleTableModelChange.INSERT;
  3660. AccessibleJTableModelChange change =
  3661. new AccessibleJTableModelChange(type,
  3662. 0,
  3663. 0,
  3664. e.getFromIndex(),
  3665. e.getToIndex());
  3666. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  3667. null, change);
  3668. }
  3669. /**
  3670. * Track changes to the table contents (column deletions)
  3671. */
  3672. public void columnRemoved(TableColumnModelEvent e) {
  3673. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3674. null, null);
  3675. // Fire a property change event indicating the table model
  3676. // has changed.
  3677. int type = AccessibleTableModelChange.DELETE;
  3678. AccessibleJTableModelChange change =
  3679. new AccessibleJTableModelChange(type,
  3680. 0,
  3681. 0,
  3682. e.getFromIndex(),
  3683. e.getToIndex());
  3684. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  3685. null, change);
  3686. }
  3687. /**
  3688. * Track changes of a column repositioning.
  3689. *
  3690. * @see TableColumnModelListener
  3691. */
  3692. public void columnMoved(TableColumnModelEvent e) {
  3693. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3694. null, null);
  3695. // Fire property change events indicating the table model
  3696. // has changed.
  3697. int type = AccessibleTableModelChange.DELETE;
  3698. AccessibleJTableModelChange change =
  3699. new AccessibleJTableModelChange(type,
  3700. 0,
  3701. 0,
  3702. e.getFromIndex(),
  3703. e.getFromIndex());
  3704. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  3705. null, change);
  3706. int type2 = AccessibleTableModelChange.INSERT;
  3707. AccessibleJTableModelChange change2 =
  3708. new AccessibleJTableModelChange(type2,
  3709. 0,
  3710. 0,
  3711. e.getToIndex(),
  3712. e.getToIndex());
  3713. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  3714. null, change2);
  3715. }
  3716. /**
  3717. * Track changes of a column moving due to margin changes.
  3718. *
  3719. * @see TableColumnModelListener
  3720. */
  3721. public void columnMarginChanged(ChangeEvent e) {
  3722. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3723. null, null);
  3724. }
  3725. /**
  3726. * Track that the selection model of the TableColumnModel changed.
  3727. *
  3728. * @see TableColumnModelListener
  3729. */
  3730. public void columnSelectionChanged(ListSelectionEvent e) {
  3731. // we should now re-place our TableColumn listener
  3732. }
  3733. /**
  3734. * Track changes to a cell's contents.
  3735. *
  3736. * Invoked when editing is finished. The changes are saved, the
  3737. * editor object is discarded, and the cell is rendered once again.
  3738. *
  3739. * @see CellEditorListener
  3740. */
  3741. public void editingStopped(ChangeEvent e) {
  3742. // it'd be great if we could figure out which cell, and pass that
  3743. // somehow as a parameter
  3744. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3745. null, null);
  3746. }
  3747. /**
  3748. * Invoked when editing is canceled. The editor object is discarded
  3749. * and the cell is rendered once again.
  3750. *
  3751. * @see CellEditorListener
  3752. */
  3753. public void editingCanceled(ChangeEvent e) {
  3754. // nothing to report, 'cause nothing changed
  3755. }
  3756. /**
  3757. * Track changes to table cell selections
  3758. */
  3759. public void valueChanged(ListSelectionEvent e) {
  3760. firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
  3761. new Boolean(false), new Boolean(true));
  3762. int selectedRow = JTable.this.getSelectedRow();
  3763. int selectedCol = JTable.this.getSelectedColumn();
  3764. if (selectedRow != lastSelectedRow ||
  3765. selectedCol != lastSelectedCol) {
  3766. Accessible oldA = getAccessibleAt(lastSelectedRow,
  3767. lastSelectedCol);
  3768. Accessible newA = getAccessibleAt(selectedRow, selectedCol);
  3769. firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
  3770. oldA, newA);
  3771. lastSelectedRow = selectedRow;
  3772. lastSelectedCol = selectedCol;
  3773. }
  3774. }
  3775. // AccessibleContext support
  3776. /**
  3777. * Get the AccessibleSelection associated with this object. In the
  3778. * implementation of the Java Accessibility API for this class,
  3779. * return this object, which is responsible for implementing the
  3780. * AccessibleSelection interface on behalf of itself.
  3781. *
  3782. * @return this object
  3783. */
  3784. public AccessibleSelection getAccessibleSelection() {
  3785. return this;
  3786. }
  3787. /**
  3788. * Gets the role of this object.
  3789. *
  3790. * @return an instance of AccessibleRole describing the role of the
  3791. * object
  3792. * @see AccessibleRole
  3793. */
  3794. public AccessibleRole getAccessibleRole() {
  3795. return AccessibleRole.TABLE;
  3796. }
  3797. /**
  3798. * Returns the Accessible child, if one exists, contained at the local
  3799. * coordinate Point.
  3800. *
  3801. * @param p the point defining the top-left corner of the Accessible,
  3802. * given in the coordinate space of the object's parent.
  3803. * @return the Accessible, if it exists, at the specified location;
  3804. * else null
  3805. */
  3806. public Accessible getAccessibleAt(Point p) {
  3807. int column = columnAtPoint(p);
  3808. int row = rowAtPoint(p);
  3809. if ((column != -1) && (row != -1)) {
  3810. TableColumn aColumn = getColumnModel().getColumn(column);
  3811. TableCellRenderer renderer = aColumn.getCellRenderer();
  3812. if (renderer == null) {
  3813. Class columnClass = getColumnClass(column);
  3814. renderer = getDefaultRenderer(columnClass);
  3815. }
  3816. Component component = renderer.getTableCellRendererComponent(
  3817. JTable.this, null, false, false,
  3818. row, column);
  3819. return new AccessibleJTableCell(JTable.this, row, column,
  3820. getAccessibleIndexAt(row, column));
  3821. }
  3822. return null;
  3823. }
  3824. /**
  3825. * Returns the number of accessible children in the object. If all
  3826. * of the children of this object implement Accessible, than this
  3827. * method should return the number of children of this object.
  3828. *
  3829. * @return the number of accessible children in the object.
  3830. */
  3831. public int getAccessibleChildrenCount() {
  3832. return (JTable.this.getColumnCount() * JTable.this.getRowCount());
  3833. }
  3834. /**
  3835. * Return the nth Accessible child of the object.
  3836. *
  3837. * @param i zero-based index of child
  3838. * @return the nth Accessible child of the object
  3839. */
  3840. public Accessible getAccessibleChild(int i) {
  3841. if (i < 0 || i >= getAccessibleChildrenCount()) {
  3842. return null;
  3843. } else {
  3844. // children increase across, and then down, for tables
  3845. // (arbitrary decision)
  3846. int column = getAccessibleColumnAtIndex(i);
  3847. int row = getAccessibleRowAtIndex(i);
  3848. TableColumn aColumn = getColumnModel().getColumn(column);
  3849. TableCellRenderer renderer = aColumn.getCellRenderer();
  3850. if (renderer == null) {
  3851. Class columnClass = getColumnClass(column);
  3852. renderer = getDefaultRenderer(columnClass);
  3853. }
  3854. Component component = renderer.getTableCellRendererComponent(
  3855. JTable.this, null, false, false,
  3856. row, column);
  3857. return new AccessibleJTableCell(JTable.this, row, column,
  3858. getAccessibleIndexAt(row, column));
  3859. }
  3860. }
  3861. // AccessibleSelection support
  3862. /**
  3863. * Returns the number of Accessible children currently selected.
  3864. * If no children are selected, the return value will be 0.
  3865. *
  3866. * @return the number of items currently selected.
  3867. */
  3868. public int getAccessibleSelectionCount() {
  3869. int rowsSel = JTable.this.getSelectedRowCount();
  3870. int colsSel = JTable.this.getSelectedColumnCount();
  3871. if (JTable.this.cellSelectionEnabled) { // a contiguous block
  3872. return rowsSel * colsSel;
  3873. } else {
  3874. // a column swath and a row swath, with a shared block
  3875. if (JTable.this.getRowSelectionAllowed() &&
  3876. JTable.this.getColumnSelectionAllowed()) {
  3877. return rowsSel * JTable.this.getColumnCount() +
  3878. colsSel * JTable.this.getRowCount() -
  3879. rowsSel * colsSel;
  3880. // just one or more rows in selection
  3881. } else if (JTable.this.getRowSelectionAllowed()) {
  3882. return rowsSel * JTable.this.getColumnCount();
  3883. // just one or more rows in selection
  3884. } else if (JTable.this.getColumnSelectionAllowed()) {
  3885. return colsSel * JTable.this.getRowCount();
  3886. } else {
  3887. return 0; // JTable doesn't allow selections
  3888. }
  3889. }
  3890. }
  3891. /**
  3892. * Returns an Accessible representing the specified selected child
  3893. * in the object. If there isn't a selection, or there are
  3894. * fewer children selected than the integer passed in, the return
  3895. * value will be null.
  3896. * <p>Note that the index represents the i-th selected child, which
  3897. * is different from the i-th child.
  3898. *
  3899. * @param i the zero-based index of selected children
  3900. * @return the i-th selected child
  3901. * @see #getAccessibleSelectionCount
  3902. */
  3903. public Accessible getAccessibleSelection(int i) {
  3904. if (i < 0 || i > getAccessibleSelectionCount()) {
  3905. return (Accessible) null;
  3906. }
  3907. int rowsSel = JTable.this.getSelectedRowCount();
  3908. int colsSel = JTable.this.getSelectedColumnCount();
  3909. int rowIndicies[] = getSelectedRows();
  3910. int colIndicies[] = getSelectedColumns();
  3911. int ttlCols = JTable.this.getColumnCount();
  3912. int ttlRows = JTable.this.getRowCount();
  3913. int r;
  3914. int c;
  3915. if (JTable.this.cellSelectionEnabled) { // a contiguous block
  3916. r = rowIndicies[i / colsSel];
  3917. c = colIndicies[i % colsSel];
  3918. return getAccessibleChild((r * ttlCols) + c);
  3919. } else {
  3920. // a column swath and a row swath, with a shared block
  3921. if (JTable.this.getRowSelectionAllowed() &&
  3922. JTable.this.getColumnSelectionAllowed()) {
  3923. // Situation:
  3924. // We have a table, like the 6x3 table below,
  3925. // wherein three colums and one row selected
  3926. // (selected cells marked with "*", unselected "0"):
  3927. //
  3928. // 0 * 0 * * 0
  3929. // * * * * * *
  3930. // 0 * 0 * * 0
  3931. //
  3932. // State machine below walks through the array of
  3933. // selected rows in two states: in a selected row,
  3934. // and not in one; continuing until we are in a row
  3935. // in which the ith selection exists. Then we return
  3936. // the appropriate cell. In the state machine, we
  3937. // always do rows above the "current" selected row first,
  3938. // then the cells in the selected row. If we're done
  3939. // with the state machine before finding the requested
  3940. // selected child, we handle the rows below the last
  3941. // selected row at the end.
  3942. //
  3943. int curIndex = i;
  3944. final int IN_ROW = 0;
  3945. final int NOT_IN_ROW = 1;
  3946. int state = (rowIndicies[0] == 0 ? IN_ROW : NOT_IN_ROW);
  3947. int j = 0;
  3948. int prevRow = -1;
  3949. while (j < rowIndicies.length) {
  3950. switch (state) {
  3951. case IN_ROW: // on individual row full of selections
  3952. if (curIndex < ttlCols) { // it's here!
  3953. c = curIndex % ttlCols;
  3954. r = rowIndicies[j];
  3955. return getAccessibleChild((r * ttlCols) + c);
  3956. } else { // not here
  3957. curIndex -= ttlCols;
  3958. }
  3959. // is the next row in table selected or not?
  3960. if (j + 1 == rowIndicies.length ||
  3961. rowIndicies[j] != rowIndicies[j+1] - 1) {
  3962. state = NOT_IN_ROW;
  3963. prevRow = rowIndicies[j];
  3964. }
  3965. j++; // we didn't return earlier, so go to next row
  3966. break;
  3967. case NOT_IN_ROW: // sparse bunch of rows of selections
  3968. if (curIndex <
  3969. (colsSel * (rowIndicies[j] -
  3970. (prevRow == -1 ? 0 : (prevRow + 1))))) {
  3971. // it's here!
  3972. c = colIndicies[curIndex % colsSel];
  3973. r = (j > 0 ? rowIndicies[j-1] + 1 : 0)
  3974. + curIndex / colsSel;
  3975. return getAccessibleChild((r * ttlCols) + c);
  3976. } else { // not here
  3977. curIndex -= colsSel * (rowIndicies[j] -
  3978. (prevRow == -1 ? 0 : (prevRow + 1)));
  3979. }
  3980. state = IN_ROW;
  3981. break;
  3982. }
  3983. }
  3984. // we got here, so we didn't find it yet; find it in
  3985. // the last sparse bunch of rows
  3986. if (curIndex <
  3987. (colsSel * (ttlRows -
  3988. (prevRow == -1 ? 0 : (prevRow + 1))))) { // it's here!
  3989. c = colIndicies[curIndex % colsSel];
  3990. r = rowIndicies[j-1] + curIndex / colsSel + 1;
  3991. return getAccessibleChild((r * ttlCols) + c);
  3992. } else { // not here
  3993. // we shouldn't get to this spot in the code!
  3994. // System.out.println("Bug in AccessibleJTable.getAccessibleSelection()");
  3995. }
  3996. // one or more rows selected
  3997. } else if (JTable.this.getRowSelectionAllowed()) {
  3998. c = i % ttlCols;
  3999. r = rowIndicies[i / ttlCols];
  4000. return getAccessibleChild((r * ttlCols) + c);
  4001. // one or more columns selected
  4002. } else if (JTable.this.getColumnSelectionAllowed()) {
  4003. c = colIndicies[i % colsSel];
  4004. r = i / colsSel;
  4005. return getAccessibleChild((r * ttlCols) + c);
  4006. }
  4007. }
  4008. return (Accessible) null;
  4009. }
  4010. /**
  4011. * Determines if the current child of this object is selected.
  4012. *
  4013. * @return true if the current child of this object is selected
  4014. * @param i the zero-based index of the child in this Accessible object.
  4015. * @see AccessibleContext#getAccessibleChild
  4016. */
  4017. public boolean isAccessibleChildSelected(int i) {
  4018. int column = getAccessibleColumnAtIndex(i);
  4019. int row = getAccessibleRowAtIndex(i);
  4020. return JTable.this.isCellSelected(row, column);
  4021. }
  4022. /**
  4023. * Adds the specified Accessible child of the object to the object's
  4024. * selection. If the object supports multiple selections,
  4025. * the specified child is added to any existing selection, otherwise
  4026. * it replaces any existing selection in the object. If the
  4027. * specified child is already selected, this method has no effect.
  4028. *
  4029. * This method only works on JTables which have individual cell
  4030. * selection enabled.
  4031. *
  4032. * @param i the zero-based index of the child
  4033. * @see AccessibleContext#getAccessibleChild
  4034. */
  4035. public void addAccessibleSelection(int i) {
  4036. if (JTable.this.cellSelectionEnabled) {
  4037. int column = getAccessibleColumnAtIndex(i);
  4038. int row = getAccessibleRowAtIndex(i);
  4039. JTable.this.addRowSelectionInterval(row, row);
  4040. JTable.this.addColumnSelectionInterval(column, column);
  4041. }
  4042. }
  4043. /**
  4044. * Removes the specified child of the object from the object's
  4045. * selection. If the specified item isn't currently selected, this
  4046. * method has no effect.
  4047. *
  4048. * This method only works on JTables which have individual cell
  4049. * selection enabled.
  4050. *
  4051. * @param i the zero-based index of the child
  4052. * @see AccessibleContext#getAccessibleChild
  4053. */
  4054. public void removeAccessibleSelection(int i) {
  4055. if (JTable.this.cellSelectionEnabled) {
  4056. int column = getAccessibleColumnAtIndex(i);
  4057. int row = getAccessibleRowAtIndex(i);
  4058. JTable.this.removeRowSelectionInterval(row, row);
  4059. JTable.this.removeColumnSelectionInterval(column, column);
  4060. }
  4061. }
  4062. /**
  4063. * Clears the selection in the object, so that no children in the
  4064. * object are selected.
  4065. */
  4066. public void clearAccessibleSelection() {
  4067. JTable.this.clearSelection();
  4068. }
  4069. /**
  4070. * Causes every child of the object to be selected, but only
  4071. * if the JTable supports multiple selections, and if individual
  4072. * cell selection is enabled.
  4073. */
  4074. public void selectAllAccessibleSelection() {
  4075. if (JTable.this.cellSelectionEnabled) {
  4076. JTable.this.selectAll();
  4077. }
  4078. }
  4079. // start of AccessibleTable implementation ------------------
  4080. private Accessible caption;
  4081. private Accessible summary;
  4082. private Accessible [] rowDescription;
  4083. private Accessible [] columnDescription;
  4084. /**
  4085. * Get the AccessibleTable associated with this object. In the
  4086. * implementation of the Java Accessibility API for this class,
  4087. * return this object, which is responsible for implementing the
  4088. * AccessibleTable interface on behalf of itself.
  4089. *
  4090. * @return this object
  4091. */
  4092. public AccessibleTable getAccessibleTable() {
  4093. return this;
  4094. }
  4095. /**
  4096. * Returns the caption for the table.
  4097. *
  4098. * @return the caption for the table
  4099. */
  4100. public Accessible getAccessibleCaption() {
  4101. return this.caption;
  4102. }
  4103. /**
  4104. * Sets the caption for the table.
  4105. *
  4106. * @param a the caption for the table
  4107. */
  4108. public void setAccessibleCaption(Accessible a) {
  4109. Accessible oldCaption = caption;
  4110. this.caption = a;
  4111. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_CAPTION_CHANGED,
  4112. oldCaption, this.caption);
  4113. }
  4114. /**
  4115. * Returns the summary description of the table.
  4116. *
  4117. * @return the summary description of the table
  4118. */
  4119. public Accessible getAccessibleSummary() {
  4120. return this.summary;
  4121. }
  4122. /**
  4123. * Sets the summary description of the table.
  4124. *
  4125. * @param a the summary description of the table
  4126. */
  4127. public void setAccessibleSummary(Accessible a) {
  4128. Accessible oldSummary = summary;
  4129. this.summary = a;
  4130. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_SUMMARY_CHANGED,
  4131. oldSummary, this.summary);
  4132. }
  4133. /*
  4134. * Returns the total number of rows in this table.
  4135. *
  4136. * @return the total number of rows in this table
  4137. */
  4138. public int getAccessibleRowCount() {
  4139. return JTable.this.getRowCount();
  4140. }
  4141. /*
  4142. * Returns the total number of columns in the table.
  4143. *
  4144. * @return the total number of columns in the table
  4145. */
  4146. public int getAccessibleColumnCount() {
  4147. return JTable.this.getColumnCount();
  4148. }
  4149. /*
  4150. * Returns the Accessible at a specified row and column
  4151. * in the table.
  4152. *
  4153. * @param r zero-based row of the table
  4154. * @param c zero-based column of the table
  4155. * @return the Accessible at the specified row and column
  4156. * in the table.
  4157. */
  4158. public Accessible getAccessibleAt(int r, int c) {
  4159. return getAccessibleChild((r * getAccessibleColumnCount()) + c);
  4160. }
  4161. /**
  4162. * Returns the number of rows occupied by the Accessible at a
  4163. * specified row and column in the table.
  4164. *
  4165. * @return the number of rows occupied by the Accessible at a
  4166. * specified row and column in the table.
  4167. */
  4168. public int getAccessibleRowExtentAt(int r, int c) {
  4169. return 1;
  4170. }
  4171. /**
  4172. * Returns the number of columns occupied by the Accessible at a
  4173. * given (row, column)
  4174. *
  4175. * @return the number of columns occupied by the Accessible at a
  4176. * specified row and column in the table.
  4177. */
  4178. public int getAccessibleColumnExtentAt(int r, int c) {
  4179. return 1;
  4180. }
  4181. /**
  4182. * Return the row headers as an AccessibleTable.
  4183. *
  4184. * @return an AccessibleTable representing the row
  4185. * headers
  4186. */
  4187. public AccessibleTable getAccessibleRowHeader() {
  4188. // row headers are not supported
  4189. return null;
  4190. }
  4191. /**
  4192. * Return the row headers as an AccessibleTable.
  4193. *
  4194. * @return an AccessibleTable representing the row
  4195. * headers
  4196. */
  4197. public void setAccessibleRowHeader(AccessibleTable a) {
  4198. // row headers are not supported
  4199. }
  4200. /**
  4201. * Return the column headers as an AccessibleTable.
  4202. *
  4203. * @return an AccessibleTable representing the column
  4204. * headers
  4205. */
  4206. public AccessibleTable getAccessibleColumnHeader() {
  4207. JTableHeader header = JTable.this.getTableHeader();
  4208. final AccessibleContext ac = header.getAccessibleContext();
  4209. if (ac != null) {
  4210. TableModel dataModel = new AbstractTableModel() {
  4211. public int getColumnCount() {
  4212. return ac.getAccessibleChildrenCount();
  4213. }
  4214. public int getRowCount() {
  4215. return 1;
  4216. }
  4217. public Object getValueAt(int row, int col) {
  4218. return ac.getAccessibleChild(col);
  4219. }
  4220. };
  4221. JTable table = new JTable(dataModel);
  4222. AccessibleContext ac2 = table.getAccessibleContext();
  4223. if (ac2 != null) {
  4224. return ac2.getAccessibleTable();
  4225. } else {
  4226. return null;
  4227. }
  4228. } else {
  4229. return null;
  4230. }
  4231. }
  4232. /**
  4233. * Return the column headers as an AccessibleTable.
  4234. *
  4235. * @return an AccessibleTable representing the column
  4236. * headers
  4237. */
  4238. public void setAccessibleColumnHeader(AccessibleTable a) {
  4239. // XXX not implemented
  4240. }
  4241. /**
  4242. * Return the description of the specified row in the table.
  4243. *
  4244. * @param r zero-based row of the table
  4245. * @return the description of the row
  4246. */
  4247. public Accessible getAccessibleRowDescription(int r) {
  4248. if (r < 0 || r >= getAccessibleRowCount()) {
  4249. throw new IllegalArgumentException(new Integer(r).toString());
  4250. }
  4251. if (rowDescription == null) {
  4252. return null;
  4253. } else {
  4254. return rowDescription[r];
  4255. }
  4256. }
  4257. /**
  4258. * Sets the description text of the specified row of the table.
  4259. *
  4260. * @param r zero-based row of the table
  4261. * @param a the description of the row
  4262. */
  4263. public void setAccessibleRowDescription(int r, Accessible a) {
  4264. if (r < 0 || r >= getAccessibleRowCount()) {
  4265. throw new IllegalArgumentException(new Integer(r).toString());
  4266. }
  4267. if (rowDescription == null) {
  4268. int numRows = getAccessibleRowCount();
  4269. rowDescription = new Accessible[numRows];
  4270. }
  4271. rowDescription[r] = a;
  4272. }
  4273. /**
  4274. * Return the description of the specified column in the table.
  4275. *
  4276. * @param c zero-based column of the table
  4277. * @return the description of the column
  4278. */
  4279. public Accessible getAccessibleColumnDescription(int c) {
  4280. if (c < 0 || c >= getAccessibleColumnCount()) {
  4281. throw new IllegalArgumentException(new Integer(c).toString());
  4282. }
  4283. if (columnDescription == null) {
  4284. return null;
  4285. } else {
  4286. return columnDescription[c];
  4287. }
  4288. }
  4289. /**
  4290. * Sets the description text of the specified column of the table.
  4291. *
  4292. * @param c zero-based column of the table
  4293. * @param a the description of the column
  4294. */
  4295. public void setAccessibleColumnDescription(int c, Accessible a) {
  4296. if (c < 0 || c >= getAccessibleColumnCount()) {
  4297. throw new IllegalArgumentException(new Integer(c).toString());
  4298. }
  4299. if (columnDescription == null) {
  4300. int numColumns = getAccessibleColumnCount();
  4301. columnDescription = new Accessible[numColumns];
  4302. }
  4303. columnDescription[c] = a;
  4304. }
  4305. /**
  4306. * Returns a boolean value indicating whether the accessible at a
  4307. * given (row, column) is selected
  4308. *
  4309. * @param r zero-based row of the table
  4310. * @param c zero-based column of the table
  4311. * @return the boolean value true if the accessible at (row, column)
  4312. * is selected. Otherwise, the boolean value false
  4313. */
  4314. public boolean isAccessibleSelected(int r, int c) {
  4315. return JTable.this.isCellSelected(r, c);
  4316. }
  4317. /**
  4318. * Returns a boolean value indicating whether the specified row
  4319. * is selected
  4320. *
  4321. * @param r zero-based row of the table
  4322. * @return the boolean value true if the specified row is selected.
  4323. * Otherwise, false.
  4324. */
  4325. public boolean isAccessibleRowSelected(int r) {
  4326. return JTable.this.isRowSelected(r);
  4327. }
  4328. /**
  4329. * Returns a boolean value indicating whether the specified column
  4330. * is selected
  4331. *
  4332. * @param r zero-based column of the table
  4333. * @return the boolean value true if the specified column is selected.
  4334. * Otherwise, false.
  4335. */
  4336. public boolean isAccessibleColumnSelected(int c) {
  4337. return JTable.this.isColumnSelected(c);
  4338. }
  4339. /**
  4340. * Returns the selected rows in a table.
  4341. *
  4342. * @return an array of selected rows where each element is a
  4343. * zero-based row of the table
  4344. */
  4345. public int [] getSelectedAccessibleRows() {
  4346. return JTable.this.getSelectedRows();
  4347. }
  4348. /**
  4349. * Returns the selected columns in a table.
  4350. *
  4351. * @return an array of selected columns where each element is a
  4352. * zero-based column of the table
  4353. */
  4354. public int [] getSelectedAccessibleColumns() {
  4355. return JTable.this.getSelectedColumns();
  4356. }
  4357. /*
  4358. * Returns the row at a given index into the table
  4359. *
  4360. * @param i zero-based index into the table
  4361. * @return the row at a given index
  4362. */
  4363. public int getAccessibleRowAtIndex(int i) {
  4364. return (i / getAccessibleColumnCount());
  4365. }
  4366. /*
  4367. * Returns the column at a given index into the table
  4368. *
  4369. * @param i zero-based index into the table
  4370. * @return the column at a given index
  4371. */
  4372. public int getAccessibleColumnAtIndex(int i) {
  4373. return (i % getAccessibleColumnCount());
  4374. }
  4375. /**
  4376. * Returns the index at a given (row, column) in the table
  4377. *
  4378. * @param r zero-based row of the table
  4379. * @param c zero-based column of the table
  4380. * @return the index into the table
  4381. */
  4382. public int getAccessibleIndexAt(int r, int c) {
  4383. return ((r * getAccessibleColumnCount()) + c);
  4384. }
  4385. // end of AccessibleTable implementation --------------------
  4386. /**
  4387. * The class provides an implementation of the Java Accessibility
  4388. * API appropriate to table cells.
  4389. */
  4390. protected class AccessibleJTableCell extends AccessibleContext
  4391. implements Accessible, AccessibleComponent {
  4392. private JTable parent;
  4393. private int row;
  4394. private int column;
  4395. private int index;
  4396. /**
  4397. * Constructs an AccessibleJTableHeaderEntry
  4398. */
  4399. public AccessibleJTableCell(JTable t, int r, int c, int i) {
  4400. parent = t;
  4401. row = r;
  4402. column = c;
  4403. index = i;
  4404. this.setAccessibleParent(parent);
  4405. }
  4406. /**
  4407. * Gets the <code>AccessibleContext</code> associated with this
  4408. * component. In the implementation of the Java Accessibility
  4409. * API for this class, return this object, which is its own
  4410. * AccessibleContext.
  4411. *
  4412. * @return this object
  4413. */
  4414. public AccessibleContext getAccessibleContext() {
  4415. return this;
  4416. }
  4417. private AccessibleContext getCurrentAccessibleContext() {
  4418. TableColumn aColumn = getColumnModel().getColumn(column);
  4419. TableCellRenderer renderer = aColumn.getCellRenderer();
  4420. if (renderer == null) {
  4421. Class columnClass = getColumnClass(column);
  4422. renderer = getDefaultRenderer(columnClass);
  4423. }
  4424. Component component = renderer.getTableCellRendererComponent(
  4425. JTable.this, getValueAt(row, column),
  4426. false, false, row, column);
  4427. if (component instanceof Accessible) {
  4428. return ((Accessible) component).getAccessibleContext();
  4429. } else {
  4430. return null;
  4431. }
  4432. }
  4433. private Component getCurrentComponent() {
  4434. TableColumn aColumn = getColumnModel().getColumn(column);
  4435. TableCellRenderer renderer = aColumn.getCellRenderer();
  4436. if (renderer == null) {
  4437. Class columnClass = getColumnClass(column);
  4438. renderer = getDefaultRenderer(columnClass);
  4439. }
  4440. return renderer.getTableCellRendererComponent(
  4441. JTable.this, null, false, false,
  4442. row, column);
  4443. }
  4444. // AccessibleContext methods
  4445. /**
  4446. * Gets the accessible name of this object.
  4447. *
  4448. * @return the localized name of the object; null if this
  4449. * object does not have a name
  4450. */
  4451. public String getAccessibleName() {
  4452. AccessibleContext ac = getCurrentAccessibleContext();
  4453. if (ac != null) {
  4454. String name = ac.getAccessibleName();
  4455. if ((name != null) && (name != "")) {
  4456. return ac.getAccessibleName();
  4457. }
  4458. }
  4459. if ((accessibleName != null) && (accessibleName != "")) {
  4460. return accessibleName;
  4461. } else {
  4462. return null;
  4463. }
  4464. }
  4465. /**
  4466. * Sets the localized accessible name of this object.
  4467. *
  4468. * @param s the new localized name of the object.
  4469. */
  4470. public void setAccessibleName(String s) {
  4471. AccessibleContext ac = getCurrentAccessibleContext();
  4472. if (ac != null) {
  4473. ac.setAccessibleName(s);
  4474. } else {
  4475. super.setAccessibleName(s);
  4476. }
  4477. }
  4478. //
  4479. // *** should check toolip text for desc. (needs MouseEvent)
  4480. //
  4481. /**
  4482. * Gets the accessible description of this object.
  4483. *
  4484. * @return the localized description of the object; null if
  4485. * this object does not have a description
  4486. */
  4487. public String getAccessibleDescription() {
  4488. AccessibleContext ac = getCurrentAccessibleContext();
  4489. if (ac != null) {
  4490. return ac.getAccessibleDescription();
  4491. } else {
  4492. return super.getAccessibleDescription();
  4493. }
  4494. }
  4495. /**
  4496. * Sets the accessible description of this object.
  4497. *
  4498. * @param s the new localized description of the object
  4499. */
  4500. public void setAccessibleDescription(String s) {
  4501. AccessibleContext ac = getCurrentAccessibleContext();
  4502. if (ac != null) {
  4503. ac.setAccessibleDescription(s);
  4504. } else {
  4505. super.setAccessibleDescription(s);
  4506. }
  4507. }
  4508. /**
  4509. * Gets the role of this object.
  4510. *
  4511. * @return an instance of AccessibleRole describing the role of the object
  4512. * @see AccessibleRole
  4513. */
  4514. public AccessibleRole getAccessibleRole() {
  4515. AccessibleContext ac = getCurrentAccessibleContext();
  4516. if (ac != null) {
  4517. return ac.getAccessibleRole();
  4518. } else {
  4519. return AccessibleRole.UNKNOWN;
  4520. }
  4521. }
  4522. /**
  4523. * Gets the state set of this object.
  4524. *
  4525. * @return an instance of AccessibleStateSet containing the
  4526. * current state set of the object
  4527. * @see AccessibleState
  4528. */
  4529. public AccessibleStateSet getAccessibleStateSet() {
  4530. AccessibleContext ac = getCurrentAccessibleContext();
  4531. AccessibleStateSet as = null;
  4532. if (ac != null) {
  4533. as = ac.getAccessibleStateSet();
  4534. }
  4535. if (as == null) {
  4536. as = new AccessibleStateSet();
  4537. }
  4538. Rectangle rjt = JTable.this.getVisibleRect();
  4539. Rectangle rcell = JTable.this.getCellRect(row, column, false);
  4540. if (rjt.intersects(rcell)) {
  4541. as.add(AccessibleState.SHOWING);
  4542. } else {
  4543. if (as.contains(AccessibleState.SHOWING)) {
  4544. as.remove(AccessibleState.SHOWING);
  4545. }
  4546. }
  4547. if (parent.isCellSelected(row, column)) {
  4548. as.add(AccessibleState.SELECTED);
  4549. } else if (as.contains(AccessibleState.SELECTED)) {
  4550. as.remove(AccessibleState.SELECTED);
  4551. }
  4552. if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
  4553. as.add(AccessibleState.ACTIVE);
  4554. }
  4555. as.add(AccessibleState.TRANSIENT);
  4556. return as;
  4557. }
  4558. /**
  4559. * Gets the Accessible parent of this object.
  4560. *
  4561. * @return the Accessible parent of this object; null if this
  4562. * object does not have an Accessible parent
  4563. */
  4564. public Accessible getAccessibleParent() {
  4565. return parent;
  4566. }
  4567. /**
  4568. * Gets the index of this object in its accessible parent.
  4569. *
  4570. * @return the index of this object in its parent; -1 if this
  4571. * object does not have an accessible parent.
  4572. * @see #getAccessibleParent
  4573. */
  4574. public int getAccessibleIndexInParent() {
  4575. return index;
  4576. }
  4577. /**
  4578. * Returns the number of accessible children in the object.
  4579. *
  4580. * @return the number of accessible children in the object.
  4581. */
  4582. public int getAccessibleChildrenCount() {
  4583. AccessibleContext ac = getCurrentAccessibleContext();
  4584. if (ac != null) {
  4585. return ac.getAccessibleChildrenCount();
  4586. } else {
  4587. return 0;
  4588. }
  4589. }
  4590. /**
  4591. * Return the specified Accessible child of the object.
  4592. *
  4593. * @param i zero-based index of child
  4594. * @return the Accessible child of the object
  4595. */
  4596. public Accessible getAccessibleChild(int i) {
  4597. AccessibleContext ac = getCurrentAccessibleContext();
  4598. if (ac != null) {
  4599. Accessible accessibleChild = ac.getAccessibleChild(i);
  4600. ac.setAccessibleParent(this);
  4601. return accessibleChild;
  4602. } else {
  4603. return null;
  4604. }
  4605. }
  4606. /**
  4607. * Gets the locale of the component. If the component does not have a
  4608. * locale, then the locale of its parent is returned.
  4609. *
  4610. * @return this component's locale; if this component does not have a locale, the locale of its parent is returned
  4611. * @exception IllegalComponentStateException
  4612. * if the Component does not have its own locale and has not yet been added to a containment hierarchy such that the locale can be
  4613. * determined from the containing parent
  4614. * @see #setLocale
  4615. */
  4616. public Locale getLocale() {
  4617. AccessibleContext ac = getCurrentAccessibleContext();
  4618. if (ac != null) {
  4619. return ac.getLocale();
  4620. } else {
  4621. return null;
  4622. }
  4623. }
  4624. /**
  4625. * Add a PropertyChangeListener to the listener list.
  4626. * The listener is registered for all properties.
  4627. *
  4628. * @param listener The PropertyChangeListener to be added
  4629. */
  4630. public void addPropertyChangeListener(PropertyChangeListener l) {
  4631. AccessibleContext ac = getCurrentAccessibleContext();
  4632. if (ac != null) {
  4633. ac.addPropertyChangeListener(l);
  4634. } else {
  4635. super.addPropertyChangeListener(l);
  4636. }
  4637. }
  4638. /**
  4639. * Remove a PropertyChangeListener from the listener list.
  4640. * This removes a PropertyChangeListener that was registered
  4641. * for all properties.
  4642. *
  4643. * @param listener The PropertyChangeListener to be removed
  4644. */
  4645. public void removePropertyChangeListener(PropertyChangeListener l) {
  4646. AccessibleContext ac = getCurrentAccessibleContext();
  4647. if (ac != null) {
  4648. ac.removePropertyChangeListener(l);
  4649. } else {
  4650. super.removePropertyChangeListener(l);
  4651. }
  4652. }
  4653. /**
  4654. * Gets the AccessibleAction associated with this object if one
  4655. * exists. Otherwise returns null.
  4656. *
  4657. * @return the AccessibleAction, or null
  4658. */
  4659. public AccessibleAction getAccessibleAction() {
  4660. return getCurrentAccessibleContext().getAccessibleAction();
  4661. }
  4662. /**
  4663. * Gets the AccessibleComponent associated with this object if one
  4664. * exists. Otherwise returns null.
  4665. *
  4666. * @return the AccessibleComponent, or null
  4667. */
  4668. public AccessibleComponent getAccessibleComponent() {
  4669. return this; // to override getBounds()
  4670. }
  4671. /**
  4672. * Gets the AccessibleSelection associated with this object if one
  4673. * exists. Otherwise returns null.
  4674. *
  4675. * @return the AccessibleSelection, or null
  4676. */
  4677. public AccessibleSelection getAccessibleSelection() {
  4678. return getCurrentAccessibleContext().getAccessibleSelection();
  4679. }
  4680. /**
  4681. * Gets the AccessibleText associated with this object if one
  4682. * exists. Otherwise returns null.
  4683. *
  4684. * @return the AccessibleText, or null
  4685. */
  4686. public AccessibleText getAccessibleText() {
  4687. return getCurrentAccessibleContext().getAccessibleText();
  4688. }
  4689. /**
  4690. * Gets the AccessibleValue associated with this object if one
  4691. * exists. Otherwise returns null.
  4692. *
  4693. * @return the AccessibleValue, or null
  4694. */
  4695. public AccessibleValue getAccessibleValue() {
  4696. return getCurrentAccessibleContext().getAccessibleValue();
  4697. }
  4698. // AccessibleComponent methods
  4699. /**
  4700. * Gets the background color of this object.
  4701. *
  4702. * @return the background color, if supported, of the object;
  4703. * otherwise, null.
  4704. */
  4705. public Color getBackground() {
  4706. AccessibleContext ac = getCurrentAccessibleContext();
  4707. if (ac instanceof AccessibleComponent) {
  4708. return ((AccessibleComponent) ac).getBackground();
  4709. } else {
  4710. Component c = getCurrentComponent();
  4711. if (c != null) {
  4712. return c.getBackground();
  4713. } else {
  4714. return null;
  4715. }
  4716. }
  4717. }
  4718. /**
  4719. * Sets the background color of this object.
  4720. *
  4721. * @param c the new Color for the background
  4722. */
  4723. public void setBackground(Color c) {
  4724. AccessibleContext ac = getCurrentAccessibleContext();
  4725. if (ac instanceof AccessibleComponent) {
  4726. ((AccessibleComponent) ac).setBackground(c);
  4727. } else {
  4728. Component cp = getCurrentComponent();
  4729. if (cp != null) {
  4730. cp.setBackground(c);
  4731. }
  4732. }
  4733. }
  4734. /**
  4735. * Gets the foreground color of this object.
  4736. *
  4737. * @return the foreground color, if supported, of the object;
  4738. * otherwise, null
  4739. */
  4740. public Color getForeground() {
  4741. AccessibleContext ac = getCurrentAccessibleContext();
  4742. if (ac instanceof AccessibleComponent) {
  4743. return ((AccessibleComponent) ac).getForeground();
  4744. } else {
  4745. Component c = getCurrentComponent();
  4746. if (c != null) {
  4747. return c.getForeground();
  4748. } else {
  4749. return null;
  4750. }
  4751. }
  4752. }
  4753. /**
  4754. * Sets the foreground color of this object.
  4755. *
  4756. * @param c the new Color for the foreground
  4757. */
  4758. public void setForeground(Color c) {
  4759. AccessibleContext ac = getCurrentAccessibleContext();
  4760. if (ac instanceof AccessibleComponent) {
  4761. ((AccessibleComponent) ac).setForeground(c);
  4762. } else {
  4763. Component cp = getCurrentComponent();
  4764. if (cp != null) {
  4765. cp.setForeground(c);
  4766. }
  4767. }
  4768. }
  4769. /**
  4770. * Gets the Cursor of this object.
  4771. *
  4772. * @return the Cursor, if supported, of the object; otherwise, null
  4773. */
  4774. public Cursor getCursor() {
  4775. AccessibleContext ac = getCurrentAccessibleContext();
  4776. if (ac instanceof AccessibleComponent) {
  4777. return ((AccessibleComponent) ac).getCursor();
  4778. } else {
  4779. Component c = getCurrentComponent();
  4780. if (c != null) {
  4781. return c.getCursor();
  4782. } else {
  4783. Accessible ap = getAccessibleParent();
  4784. if (ap instanceof AccessibleComponent) {
  4785. return ((AccessibleComponent) ap).getCursor();
  4786. } else {
  4787. return null;
  4788. }
  4789. }
  4790. }
  4791. }
  4792. /**
  4793. * Sets the Cursor of this object.
  4794. *
  4795. * @param c the new Cursor for the object
  4796. */
  4797. public void setCursor(Cursor c) {
  4798. AccessibleContext ac = getCurrentAccessibleContext();
  4799. if (ac instanceof AccessibleComponent) {
  4800. ((AccessibleComponent) ac).setCursor(c);
  4801. } else {
  4802. Component cp = getCurrentComponent();
  4803. if (cp != null) {
  4804. cp.setCursor(c);
  4805. }
  4806. }
  4807. }
  4808. /**
  4809. * Gets the Font of this object.
  4810. *
  4811. * @return the Font,if supported, for the object; otherwise, null
  4812. */
  4813. public Font getFont() {
  4814. AccessibleContext ac = getCurrentAccessibleContext();
  4815. if (ac instanceof AccessibleComponent) {
  4816. return ((AccessibleComponent) ac).getFont();
  4817. } else {
  4818. Component c = getCurrentComponent();
  4819. if (c != null) {
  4820. return c.getFont();
  4821. } else {
  4822. return null;
  4823. }
  4824. }
  4825. }
  4826. /**
  4827. * Sets the Font of this object.
  4828. *
  4829. * @param f the new Font for the object
  4830. */
  4831. public void setFont(Font f) {
  4832. AccessibleContext ac = getCurrentAccessibleContext();
  4833. if (ac instanceof AccessibleComponent) {
  4834. ((AccessibleComponent) ac).setFont(f);
  4835. } else {
  4836. Component c = getCurrentComponent();
  4837. if (c != null) {
  4838. c.setFont(f);
  4839. }
  4840. }
  4841. }
  4842. /**
  4843. * Gets the FontMetrics of this object.
  4844. *
  4845. * @param f the Font
  4846. * @return the FontMetrics, if supported, the object; otherwise, null
  4847. * @see #getFont
  4848. */
  4849. public FontMetrics getFontMetrics(Font f) {
  4850. AccessibleContext ac = getCurrentAccessibleContext();
  4851. if (ac instanceof AccessibleComponent) {
  4852. return ((AccessibleComponent) ac).getFontMetrics(f);
  4853. } else {
  4854. Component c = getCurrentComponent();
  4855. if (c != null) {
  4856. return c.getFontMetrics(f);
  4857. } else {
  4858. return null;
  4859. }
  4860. }
  4861. }
  4862. /**
  4863. * Determines if the object is enabled.
  4864. *
  4865. * @return true if object is enabled; otherwise, false
  4866. */
  4867. public boolean isEnabled() {
  4868. AccessibleContext ac = getCurrentAccessibleContext();
  4869. if (ac instanceof AccessibleComponent) {
  4870. return ((AccessibleComponent) ac).isEnabled();
  4871. } else {
  4872. Component c = getCurrentComponent();
  4873. if (c != null) {
  4874. return c.isEnabled();
  4875. } else {
  4876. return false;
  4877. }
  4878. }
  4879. }
  4880. /**
  4881. * Sets the enabled state of the object.
  4882. *
  4883. * @param b if true, enables this object; otherwise, disables it
  4884. */
  4885. public void setEnabled(boolean b) {
  4886. AccessibleContext ac = getCurrentAccessibleContext();
  4887. if (ac instanceof AccessibleComponent) {
  4888. ((AccessibleComponent) ac).setEnabled(b);
  4889. } else {
  4890. Component c = getCurrentComponent();
  4891. if (c != null) {
  4892. c.setEnabled(b);
  4893. }
  4894. }
  4895. }
  4896. /**
  4897. * Determines if this object is visible. Note: this means that the
  4898. * object intends to be visible; however, it may not in fact be
  4899. * showing on the screen because one of the objects that this object
  4900. * is contained by is not visible. To determine if an object is
  4901. * showing on the screen, use isShowing().
  4902. *
  4903. * @return true if object is visible; otherwise, false
  4904. */
  4905. public boolean isVisible() {
  4906. AccessibleContext ac = getCurrentAccessibleContext();
  4907. if (ac instanceof AccessibleComponent) {
  4908. return ((AccessibleComponent) ac).isVisible();
  4909. } else {
  4910. Component c = getCurrentComponent();
  4911. if (c != null) {
  4912. return c.isVisible();
  4913. } else {
  4914. return false;
  4915. }
  4916. }
  4917. }
  4918. /**
  4919. * Sets the visible state of the object.
  4920. *
  4921. * @param b if true, shows this object; otherwise, hides it
  4922. */
  4923. public void setVisible(boolean b) {
  4924. AccessibleContext ac = getCurrentAccessibleContext();
  4925. if (ac instanceof AccessibleComponent) {
  4926. ((AccessibleComponent) ac).setVisible(b);
  4927. } else {
  4928. Component c = getCurrentComponent();
  4929. if (c != null) {
  4930. c.setVisible(b);
  4931. }
  4932. }
  4933. }
  4934. /**
  4935. * Determines if the object is showing. This is determined by checking
  4936. * the visibility of the object and ancestors of the object. Note: this
  4937. * will return true even if the object is obscured by another (for example,
  4938. * it happens to be underneath a menu that was pulled down).
  4939. *
  4940. * @return true if the object is showing; otherwise, false
  4941. */
  4942. public boolean isShowing() {
  4943. AccessibleContext ac = getCurrentAccessibleContext();
  4944. if (ac instanceof AccessibleComponent) {
  4945. return ((AccessibleComponent) ac).isShowing();
  4946. } else {
  4947. Component c = getCurrentComponent();
  4948. if (c != null) {
  4949. return c.isShowing();
  4950. } else {
  4951. return false;
  4952. }
  4953. }
  4954. }
  4955. /**
  4956. * Checks whether the specified point is within this object's bounds,
  4957. * where the point's x and y coordinates are defined to be relative to the
  4958. * coordinate system of the object.
  4959. *
  4960. * @param p the Point relative to the coordinate system of the object
  4961. * @return true if object contains Point; otherwise false
  4962. */
  4963. public boolean contains(Point p) {
  4964. AccessibleContext ac = getCurrentAccessibleContext();
  4965. if (ac instanceof AccessibleComponent) {
  4966. Rectangle r = ((AccessibleComponent) ac).getBounds();
  4967. return r.contains(p);
  4968. } else {
  4969. Component c = getCurrentComponent();
  4970. if (c != null) {
  4971. Rectangle r = c.getBounds();
  4972. return r.contains(p);
  4973. } else {
  4974. return getBounds().contains(p);
  4975. }
  4976. }
  4977. }
  4978. /**
  4979. * Returns the location of the object on the screen.
  4980. *
  4981. * @return location of object on screen -- can be null if this object
  4982. * is not on the screen
  4983. */
  4984. public Point getLocationOnScreen() {
  4985. if (parent != null) {
  4986. Point parentLocation = parent.getLocationOnScreen();
  4987. Point componentLocation = getLocation();
  4988. componentLocation.translate(parentLocation.x, parentLocation.y);
  4989. return componentLocation;
  4990. } else {
  4991. return null;
  4992. }
  4993. }
  4994. /**
  4995. * Gets the location of the object relative to the parent in the form
  4996. * of a point specifying the object's top-left corner in the screen's
  4997. * coordinate space.
  4998. *
  4999. * @return an instance of Point representing the top-left corner of the
  5000. * object's bounds in the coordinate space of the screen; null if
  5001. * this object or its parent are not on the screen
  5002. */
  5003. public Point getLocation() {
  5004. if (parent != null) {
  5005. Rectangle r = parent.getCellRect(row, column, false);
  5006. if (r != null) {
  5007. return r.getLocation();
  5008. }
  5009. }
  5010. return null;
  5011. }
  5012. /**
  5013. * Sets the location of the object relative to the parent.
  5014. */
  5015. public void setLocation(Point p) {
  5016. // if ((parent != null) && (parent.contains(p))) {
  5017. // ensureIndexIsVisible(indexInParent);
  5018. // }
  5019. }
  5020. public Rectangle getBounds() {
  5021. if (parent != null) {
  5022. return parent.getCellRect(row, column, false);
  5023. } else {
  5024. return null;
  5025. }
  5026. }
  5027. public void setBounds(Rectangle r) {
  5028. AccessibleContext ac = getCurrentAccessibleContext();
  5029. if (ac instanceof AccessibleComponent) {
  5030. ((AccessibleComponent) ac).setBounds(r);
  5031. } else {
  5032. Component c = getCurrentComponent();
  5033. if (c != null) {
  5034. c.setBounds(r);
  5035. }
  5036. }
  5037. }
  5038. public Dimension getSize() {
  5039. if (parent != null) {
  5040. Rectangle r = parent.getCellRect(row, column, false);
  5041. if (r != null) {
  5042. return r.getSize();
  5043. }
  5044. }
  5045. return null;
  5046. }
  5047. public void setSize (Dimension d) {
  5048. AccessibleContext ac = getCurrentAccessibleContext();
  5049. if (ac instanceof AccessibleComponent) {
  5050. ((AccessibleComponent) ac).setSize(d);
  5051. } else {
  5052. Component c = getCurrentComponent();
  5053. if (c != null) {
  5054. c.setSize(d);
  5055. }
  5056. }
  5057. }
  5058. public Accessible getAccessibleAt(Point p) {
  5059. AccessibleContext ac = getCurrentAccessibleContext();
  5060. if (ac instanceof AccessibleComponent) {
  5061. return ((AccessibleComponent) ac).getAccessibleAt(p);
  5062. } else {
  5063. return null;
  5064. }
  5065. }
  5066. public boolean isFocusTraversable() {
  5067. AccessibleContext ac = getCurrentAccessibleContext();
  5068. if (ac instanceof AccessibleComponent) {
  5069. return ((AccessibleComponent) ac).isFocusTraversable();
  5070. } else {
  5071. Component c = getCurrentComponent();
  5072. if (c != null) {
  5073. return c.isFocusTraversable();
  5074. } else {
  5075. return false;
  5076. }
  5077. }
  5078. }
  5079. public void requestFocus() {
  5080. AccessibleContext ac = getCurrentAccessibleContext();
  5081. if (ac instanceof AccessibleComponent) {
  5082. ((AccessibleComponent) ac).requestFocus();
  5083. } else {
  5084. Component c = getCurrentComponent();
  5085. if (c != null) {
  5086. c.requestFocus();
  5087. }
  5088. }
  5089. }
  5090. public void addFocusListener(FocusListener l) {
  5091. AccessibleContext ac = getCurrentAccessibleContext();
  5092. if (ac instanceof AccessibleComponent) {
  5093. ((AccessibleComponent) ac).addFocusListener(l);
  5094. } else {
  5095. Component c = getCurrentComponent();
  5096. if (c != null) {
  5097. c.addFocusListener(l);
  5098. }
  5099. }
  5100. }
  5101. public void removeFocusListener(FocusListener l) {
  5102. AccessibleContext ac = getCurrentAccessibleContext();
  5103. if (ac instanceof AccessibleComponent) {
  5104. ((AccessibleComponent) ac).removeFocusListener(l);
  5105. } else {
  5106. Component c = getCurrentComponent();
  5107. if (c != null) {
  5108. c.removeFocusListener(l);
  5109. }
  5110. }
  5111. }
  5112. } // inner class AccessibleJTableCell
  5113. } // inner class AccessibleJTable
  5114. } // End of Class JTable