1. /*
  2. * @(#)JTable.java 1.208 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.util.*;
  9. import java.applet.Applet;
  10. import java.awt.*;
  11. import java.awt.event.*;
  12. import java.beans.*;
  13. import java.io.Serializable;
  14. import java.io.ObjectOutputStream;
  15. import java.io.ObjectInputStream;
  16. import java.io.IOException;
  17. import javax.accessibility.*;
  18. import javax.swing.event.*;
  19. import javax.swing.plaf.*;
  20. import javax.swing.table.*;
  21. import javax.swing.border.*;
  22. import java.text.NumberFormat;
  23. import java.text.DateFormat;
  24. /**
  25. * The <code>JTable</code> is used to display and edit regular two-dimensional tables
  26. * of cells.
  27. * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/table.html">How to Use Tables</a>
  28. * in <em>The Java Tutorial</em>
  29. * for task-oriented documentation and examples of using <code>JTable</code>.
  30. *
  31. * <p>
  32. * The <code>JTable</code> has many
  33. * facilities that make it possible to customize its rendering and editing
  34. * but provides defaults for these features so that simple tables can be
  35. * set up easily. For example, to set up a table with 10 rows and 10
  36. * columns of numbers:
  37. * <p>
  38. * <pre>
  39. * TableModel dataModel = new AbstractTableModel() {
  40. * public int getColumnCount() { return 10; }
  41. * public int getRowCount() { return 10;}
  42. * public Object getValueAt(int row, int col) { return new Integer(row*col); }
  43. * };
  44. * JTable table = new JTable(dataModel);
  45. * JScrollPane scrollpane = new JScrollPane(table);
  46. * </pre>
  47. * <p>
  48. * Note that if you wish to use a <code>JTable</code> in a standalone
  49. * view (outside of a <code>JScrollPane</code>) and want the header
  50. * displayed, you can get it using {@link #getTableHeader} and
  51. * display it separately.
  52. * <p>
  53. * When designing applications that use the <code>JTable</code> it is worth paying
  54. * close attention to the data structures that will represent the table's data.
  55. * The <code>DefaultTableModel</code> is a model implementation that
  56. * uses a <code>Vector</code> of <code>Vector</code>s of <code>Object</code>s to
  57. * store the cell values. As well as copying the data from an
  58. * application into the <code>DefaultTableModel</code>,
  59. * it is also possible to wrap the data in the methods of the
  60. * <code>TableModel</code> interface so that the data can be passed to the
  61. * <code>JTable</code> directly, as in the example above. This often results
  62. * in more efficient applications because the model is free to choose the
  63. * internal representation that best suits the data.
  64. * A good rule of thumb for deciding whether to use the <code>AbstractTableModel</code>
  65. * or the <code>DefaultTableModel</code> is to use the <code>AbstractTableModel</code>
  66. * as the base class for creating subclasses and the <code>DefaultTableModel</code>
  67. * when subclassing is not required.
  68. * <p>
  69. * The "TableExample" directory in the demo area of the source distribution
  70. * gives a number of complete examples of <code>JTable</code> usage,
  71. * covering how the <code>JTable</code> can be used to provide an
  72. * editable view of data taken from a database and how to modify
  73. * the columns in the display to use specialized renderers and editors.
  74. * <p>
  75. * The <code>JTable</code> uses integers exclusively to refer to both the rows and the columns
  76. * of the model that it displays. The <code>JTable</code> simply takes a tabular range of cells
  77. * and uses <code>getValueAt(int, int)</code> to retrieve the
  78. * values from the model during painting.
  79. * <p>
  80. * By default, columns may be rearranged in the <code>JTable</code> so that the
  81. * view's columns appear in a different order to the columns in the model.
  82. * This does not affect the implementation of the model at all: when the
  83. * columns are reordered, the <code>JTable</code> maintains the new order of the columns
  84. * internally and converts its column indices before querying the model.
  85. * <p>
  86. * So, when writing a <code>TableModel</code>, it is not necessary to listen for column
  87. * reordering events as the model will be queried in its own coordinate
  88. * system regardless of what is happening in the view.
  89. * In the examples area there is a demonstration of a sorting algorithm making
  90. * use of exactly this technique to interpose yet another coordinate system
  91. * where the order of the rows is changed, rather than the order of the columns.
  92. * <p>
  93. * As for all <code>JComponent</code> classes, you can use
  94. * {@link InputMap} and {@link ActionMap} to associate an
  95. * {@link Action} object with a {@link KeyStroke} and execute the
  96. * action under specified conditions.
  97. * <p>
  98. * For the keyboard keys used by this component in the standard Look and
  99. * Feel (L&F) renditions, see the
  100. * <a href="doc-files/Key-Index.html#JTable"><code>JTable</code> key assignments</a>.
  101. * <p>
  102. * <strong>Warning:</strong>
  103. * Serialized objects of this class will not be compatible with
  104. * future Swing releases. The current serialization support is
  105. * appropriate for short term storage or RMI between applications running
  106. * the same version of Swing. As of 1.4, support for long term storage
  107. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  108. * has been added to the <code>java.beans</code> package.
  109. * Please see {@link java.beans.XMLEncoder}.
  110. *
  111. *
  112. * @beaninfo
  113. * attribute: isContainer false
  114. * description: A component which displays data in a two dimensional grid.
  115. *
  116. * @version 1.208 01/23/03
  117. * @author Philip Milne
  118. */
  119. /* The first versions of the JTable, contained in Swing-0.1 through
  120. * Swing-0.4, were written by Alan Chung.
  121. */
  122. public class JTable extends JComponent implements TableModelListener, Scrollable,
  123. TableColumnModelListener, ListSelectionListener, CellEditorListener,
  124. Accessible
  125. {
  126. //
  127. // Static Constants
  128. //
  129. /**
  130. * @see #getUIClassID
  131. * @see #readObject
  132. */
  133. private static final String uiClassID = "TableUI";
  134. /** Do not adjust column widths automatically; use a scrollbar. */
  135. public static final int AUTO_RESIZE_OFF = 0;
  136. /** When a column is adjusted in the UI, adjust the next column the opposite way. */
  137. public static final int AUTO_RESIZE_NEXT_COLUMN = 1;
  138. /** During UI adjustment, change subsequent columns to preserve the total width;
  139. * this is the default behavior. */
  140. public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
  141. /** During all resize operations, apply adjustments to the last column only. */
  142. public static final int AUTO_RESIZE_LAST_COLUMN = 3;
  143. /** During all resize operations, proportionately resize all columns. */
  144. public static final int AUTO_RESIZE_ALL_COLUMNS = 4;
  145. //
  146. // Instance Variables
  147. //
  148. /** The <code>TableModel</code> of the table. */
  149. protected TableModel dataModel;
  150. /** The <code>TableColumnModel</code> of the table. */
  151. protected TableColumnModel columnModel;
  152. /** The <code>ListSelectionModel</code> of the table, used to keep track of row selections. */
  153. protected ListSelectionModel selectionModel;
  154. /** The <code>TableHeader</code> working with the table. */
  155. protected JTableHeader tableHeader;
  156. /** The height in pixels of each row in the table. */
  157. protected int rowHeight;
  158. /** The height in pixels of the margin between the cells in each row. */
  159. protected int rowMargin;
  160. /** The color of the grid. */
  161. protected Color gridColor;
  162. /** The table draws horizontal lines between cells if <code>showHorizontalLines</code> is true. */
  163. protected boolean showHorizontalLines;
  164. /** The table draws vertical lines between cells if <code>showVerticalLines</code> is true. */
  165. protected boolean showVerticalLines;
  166. /**
  167. * Determines if the table automatically resizes the
  168. * width of the table's columns to take up the entire width of the
  169. * table, and how it does the resizing.
  170. */
  171. protected int autoResizeMode;
  172. /**
  173. * The table will query the <code>TableModel</code> to build the default
  174. * set of columns if this is true.
  175. */
  176. protected boolean autoCreateColumnsFromModel;
  177. /** Used by the <code>Scrollable</code> interface to determine the initial visible area. */
  178. protected Dimension preferredViewportSize;
  179. /** True if row selection is allowed in this table. */
  180. protected boolean rowSelectionAllowed;
  181. /**
  182. * Obsolete as of Java 2 platform v1.3. Please use the
  183. * <code>rowSelectionAllowed</code> property and the
  184. * <code>columnSelectionAllowed</code> property of the
  185. * <code>columnModel</code> instead. Or use the
  186. * method <code>getCellSelectionEnabled</code>.
  187. */
  188. /*
  189. * If true, both a row selection and a column selection
  190. * can be non-empty at the same time, the selected cells are the
  191. * the cells whose row and column are both selected.
  192. */
  193. protected boolean cellSelectionEnabled;
  194. /** If editing, the <code>Component</code> that is handling the editing. */
  195. transient protected Component editorComp;
  196. /**
  197. * The object that overwrites the screen real estate occupied by the
  198. * current cell and allows the user to change its contents.
  199. */
  200. transient protected TableCellEditor cellEditor;
  201. /** Identifies the column of the cell being edited. */
  202. transient protected int editingColumn;
  203. /** Identifies the row of the cell being edited. */
  204. transient protected int editingRow;
  205. /**
  206. * A table of objects that display the contents of a cell,
  207. * indexed by class as declared in <code>getColumnClass</code>
  208. * in the <code>TableModel</code> interface.
  209. */
  210. transient protected Hashtable defaultRenderersByColumnClass;
  211. /**
  212. * A table of objects that display and edit the contents of a cell,
  213. * indexed by class as declared in <code>getColumnClass</code>
  214. * in the <code>TableModel</code> interface.
  215. */
  216. transient protected Hashtable defaultEditorsByColumnClass;
  217. /** The foreground color of selected cells. */
  218. protected Color selectionForeground;
  219. /** The background color of selected cells. */
  220. protected Color selectionBackground;
  221. //
  222. // Private state
  223. //
  224. private SizeSequence rowModel;
  225. private boolean dragEnabled;
  226. private boolean surrendersFocusOnKeystroke;
  227. private PropertyChangeListener editorRemover = null;
  228. /**
  229. * The last value of getValueIsAdjusting from the column selection models
  230. * columnSelectionChanged notification. Used to test if a repaint is
  231. * needed.
  232. */
  233. private boolean columnSelectionAdjusting;
  234. /**
  235. * The last value of getValueIsAdjusting from the row selection models
  236. * valueChanged notification. Used to test if a repaint is needed.
  237. */
  238. private boolean rowSelectionAdjusting;
  239. //
  240. // Constructors
  241. //
  242. /**
  243. * Constructs a default <code>JTable</code> that is initialized with a default
  244. * data model, a default column model, and a default selection
  245. * model.
  246. *
  247. * @see #createDefaultDataModel
  248. * @see #createDefaultColumnModel
  249. * @see #createDefaultSelectionModel
  250. */
  251. public JTable() {
  252. this(null, null, null);
  253. }
  254. /**
  255. * Constructs a <code>JTable</code> that is initialized with
  256. * <code>dm</code> as the data model, a default column model,
  257. * and a default selection model.
  258. *
  259. * @param dm the data model for the table
  260. * @see #createDefaultColumnModel
  261. * @see #createDefaultSelectionModel
  262. */
  263. public JTable(TableModel dm) {
  264. this(dm, null, null);
  265. }
  266. /**
  267. * Constructs a <code>JTable</code> that is initialized with
  268. * <code>dm</code> as the data model, <code>cm</code>
  269. * as the column model, and a default selection model.
  270. *
  271. * @param dm the data model for the table
  272. * @param cm the column model for the table
  273. * @see #createDefaultSelectionModel
  274. */
  275. public JTable(TableModel dm, TableColumnModel cm) {
  276. this(dm, cm, null);
  277. }
  278. /**
  279. * Constructs a <code>JTable</code> that is initialized with
  280. * <code>dm</code> as the data model, <code>cm</code> as the
  281. * column model, and <code>sm</code> as the selection model.
  282. * If any of the parameters are <code>null</code> this method
  283. * will initialize the table with the corresponding default model.
  284. * The <code>autoCreateColumnsFromModel</code> flag is set to false
  285. * if <code>cm</code> is non-null, otherwise it is set to true
  286. * and the column model is populated with suitable
  287. * <code>TableColumns</code> for the columns in <code>dm</code>.
  288. *
  289. * @param dm the data model for the table
  290. * @param cm the column model for the table
  291. * @param sm the row selection model for the table
  292. * @see #createDefaultDataModel
  293. * @see #createDefaultColumnModel
  294. * @see #createDefaultSelectionModel
  295. */
  296. public JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
  297. super();
  298. setLayout(null);
  299. setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
  300. JComponent.getManagingFocusForwardTraversalKeys());
  301. setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
  302. JComponent.getManagingFocusBackwardTraversalKeys());
  303. if (cm == null) {
  304. cm = createDefaultColumnModel();
  305. autoCreateColumnsFromModel = true;
  306. }
  307. setColumnModel(cm);
  308. if (sm == null) {
  309. sm = createDefaultSelectionModel();
  310. }
  311. setSelectionModel(sm);
  312. // Set the model last, that way if the autoCreatColumnsFromModel has
  313. // been set above, we will automatically populate an empty columnModel
  314. // with suitable columns for the new model.
  315. if (dm == null) {
  316. dm = createDefaultDataModel();
  317. }
  318. setModel(dm);
  319. initializeLocalVars();
  320. updateUI();
  321. }
  322. /**
  323. * Constructs a <code>JTable</code> with <code>numRows</code>
  324. * and <code>numColumns</code> of empty cells using
  325. * <code>DefaultTableModel</code>. The columns will have
  326. * names of the form "A", "B", "C", etc.
  327. *
  328. * @param numRows the number of rows the table holds
  329. * @param numColumns the number of columns the table holds
  330. * @see javax.swing.table.DefaultTableModel
  331. */
  332. public JTable(int numRows, int numColumns) {
  333. this(new DefaultTableModel(numRows, numColumns));
  334. }
  335. /**
  336. * Constructs a <code>JTable</code> to display the values in the
  337. * <code>Vector</code> of <code>Vectors</code>, <code>rowData</code>,
  338. * with column names, <code>columnNames</code>. The
  339. * <code>Vectors</code> contained in <code>rowData</code>
  340. * should contain the values for that row. In other words,
  341. * the value of the cell at row 1, column 5 can be obtained
  342. * with the following code:
  343. * <p>
  344. * <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
  345. * <p>
  346. * @param rowData the data for the new table
  347. * @param columnNames names of each column
  348. */
  349. public JTable(Vector rowData, Vector columnNames) {
  350. this(new DefaultTableModel(rowData, columnNames));
  351. }
  352. /**
  353. * Constructs a <code>JTable</code> to display the values in the two dimensional array,
  354. * <code>rowData</code>, with column names, <code>columnNames</code>.
  355. * <code>rowData</code> is an array of rows, so the value of the cell at row 1,
  356. * column 5 can be obtained with the following code:
  357. * <p>
  358. * <pre> rowData[1][5]; </pre>
  359. * <p>
  360. * All rows must be of the same length as <code>columnNames</code>.
  361. * <p>
  362. * @param rowData the data for the new table
  363. * @param columnNames names of each column
  364. */
  365. public JTable(final Object[][] rowData, final Object[] columnNames) {
  366. this(new AbstractTableModel() {
  367. public String getColumnName(int column) { return columnNames[column].toString(); }
  368. public int getRowCount() { return rowData.length; }
  369. public int getColumnCount() { return columnNames.length; }
  370. public Object getValueAt(int row, int col) { return rowData[row][col]; }
  371. public boolean isCellEditable(int row, int column) { return true; }
  372. public void setValueAt(Object value, int row, int col) {
  373. rowData[row][col] = value;
  374. fireTableCellUpdated(row, col);
  375. }
  376. });
  377. }
  378. /**
  379. * Calls the <code>configureEnclosingScrollPane</code> method.
  380. *
  381. * @see #configureEnclosingScrollPane
  382. */
  383. public void addNotify() {
  384. super.addNotify();
  385. configureEnclosingScrollPane();
  386. }
  387. /**
  388. * If this <code>JTable</code> is the <code>viewportView</code> of an enclosing <code>JScrollPane</code>
  389. * (the usual situation), configure this <code>ScrollPane</code> by, amongst other things,
  390. * installing the table's <code>tableHeader</code> as the <code>columnHeaderView</code> of the scroll pane.
  391. * When a <code>JTable</code> is added to a <code>JScrollPane</code> in the usual way,
  392. * using <code>new JScrollPane(myTable)</code>, <code>addNotify</code> is
  393. * called in the <code>JTable</code> (when the table is added to the viewport).
  394. * <code>JTable</code>'s <code>addNotify</code> method in turn calls this method,
  395. * which is protected so that this default installation procedure can
  396. * be overridden by a subclass.
  397. *
  398. * @see #addNotify
  399. */
  400. protected void configureEnclosingScrollPane() {
  401. Container p = getParent();
  402. if (p instanceof JViewport) {
  403. Container gp = p.getParent();
  404. if (gp instanceof JScrollPane) {
  405. JScrollPane scrollPane = (JScrollPane)gp;
  406. // Make certain we are the viewPort's view and not, for
  407. // example, the rowHeaderView of the scrollPane -
  408. // an implementor of fixed columns might do this.
  409. JViewport viewport = scrollPane.getViewport();
  410. if (viewport == null || viewport.getView() != this) {
  411. return;
  412. }
  413. scrollPane.setColumnHeaderView(getTableHeader());
  414. // scrollPane.getViewport().setBackingStoreEnabled(true);
  415. Border border = scrollPane.getBorder();
  416. if (border == null || border instanceof UIResource) {
  417. scrollPane.setBorder(UIManager.getBorder("Table.scrollPaneBorder"));
  418. }
  419. }
  420. }
  421. }
  422. /**
  423. * Calls the <code>unconfigureEnclosingScrollPane</code> method.
  424. *
  425. * @see #unconfigureEnclosingScrollPane
  426. */
  427. public void removeNotify() {
  428. KeyboardFocusManager.getCurrentKeyboardFocusManager().
  429. removePropertyChangeListener("permanentFocusOwner", editorRemover);
  430. editorRemover = null;
  431. unconfigureEnclosingScrollPane();
  432. super.removeNotify();
  433. }
  434. /**
  435. * Reverses the effect of <code>configureEnclosingScrollPane</code>
  436. * by replacing the <code>columnHeaderView</code> of the enclosing
  437. * scroll pane with <code>null</code>. <code>JTable</code>'s
  438. * <code>removeNotify</code> method calls
  439. * this method, which is protected so that this default uninstallation
  440. * procedure can be overridden by a subclass.
  441. *
  442. * @see #removeNotify
  443. * @see #configureEnclosingScrollPane
  444. */
  445. protected void unconfigureEnclosingScrollPane() {
  446. Container p = getParent();
  447. if (p instanceof JViewport) {
  448. Container gp = p.getParent();
  449. if (gp instanceof JScrollPane) {
  450. JScrollPane scrollPane = (JScrollPane)gp;
  451. // Make certain we are the viewPort's view and not, for
  452. // example, the rowHeaderView of the scrollPane -
  453. // an implementor of fixed columns might do this.
  454. JViewport viewport = scrollPane.getViewport();
  455. if (viewport == null || viewport.getView() != this) {
  456. return;
  457. }
  458. scrollPane.setColumnHeaderView(null);
  459. }
  460. }
  461. }
  462. //
  463. // Static Methods
  464. //
  465. /**
  466. * Equivalent to <code>new JScrollPane(aTable)</code>.
  467. *
  468. * @deprecated As of Swing version 1.0.2,
  469. * replaced by <code>new JScrollPane(aTable)</code>.
  470. */
  471. static public JScrollPane createScrollPaneForTable(JTable aTable) {
  472. return new JScrollPane(aTable);
  473. }
  474. //
  475. // Table Attributes
  476. //
  477. /**
  478. * Sets the <code>tableHeader</code> working with this <code>JTable</code> to <code>newHeader</code>.
  479. * It is legal to have a <code>null</code> <code>tableHeader</code>.
  480. *
  481. * @param tableHeader new tableHeader
  482. * @see #getTableHeader
  483. * @beaninfo
  484. * bound: true
  485. * description: The JTableHeader instance which renders the column headers.
  486. */
  487. public void setTableHeader(JTableHeader tableHeader) {
  488. if (this.tableHeader != tableHeader) {
  489. JTableHeader old = this.tableHeader;
  490. // Release the old header
  491. if (old != null) {
  492. old.setTable(null);
  493. }
  494. this.tableHeader = tableHeader;
  495. if (tableHeader != null) {
  496. tableHeader.setTable(this);
  497. }
  498. firePropertyChange("tableHeader", old, tableHeader);
  499. }
  500. }
  501. /**
  502. * Returns the <code>tableHeader</code> used by this <code>JTable</code>.
  503. *
  504. * @return the <code>tableHeader</code> used by this table
  505. * @see #setTableHeader
  506. */
  507. public JTableHeader getTableHeader() {
  508. return tableHeader;
  509. }
  510. /**
  511. * Sets the height, in pixels, of all cells to <code>rowHeight</code>,
  512. * revalidates, and repaints.
  513. * The height of the cells will be equal to the row height minus
  514. * the row margin.
  515. *
  516. * @param rowHeight new row height
  517. * @exception IllegalArgumentException if <code>rowHeight</code> is
  518. * less than 1
  519. * @see #getRowHeight
  520. * @beaninfo
  521. * bound: true
  522. * description: The height of the specified row.
  523. */
  524. public void setRowHeight(int rowHeight) {
  525. if (rowHeight <= 0) {
  526. throw new IllegalArgumentException("New row height less than 1");
  527. }
  528. int old = this.rowHeight;
  529. this.rowHeight = rowHeight;
  530. rowModel = null;
  531. resizeAndRepaint();
  532. firePropertyChange("rowHeight", old, rowHeight);
  533. }
  534. /**
  535. * Returns the height of a table row, in pixels.
  536. * The default row height is 16.0.
  537. *
  538. * @return the height in pixels of a table row
  539. * @see #setRowHeight
  540. */
  541. public int getRowHeight() {
  542. return rowHeight;
  543. }
  544. private SizeSequence getRowModel() {
  545. if (rowModel == null) {
  546. rowModel = new SizeSequence(getRowCount(), getRowHeight());
  547. }
  548. return rowModel;
  549. }
  550. /**
  551. * Sets the height for <code>row</code> to <code>rowHeight</code>,
  552. * revalidates, and repaints. The height of the cells in this row
  553. * will be equal to the row height minus the row margin.
  554. *
  555. * @param row the row whose height is being
  556. changed
  557. * @param rowHeight new row height, in pixels
  558. * @exception IllegalArgumentException if <code>rowHeight</code> is
  559. * less than 1
  560. * @beaninfo
  561. * bound: true
  562. * description: The height in pixels of the cells in <code>row</code>
  563. */
  564. public void setRowHeight(int row, int rowHeight) {
  565. if (rowHeight <= 0) {
  566. throw new IllegalArgumentException("New row height less than 1");
  567. }
  568. getRowModel().setSize(row, rowHeight);
  569. resizeAndRepaint();
  570. }
  571. /**
  572. * Returns the height, in pixels, of the cells in <code>row</code>.
  573. * @param row the row whose height is to be returned
  574. * @return the height, in pixels, of the cells in the row
  575. */
  576. public int getRowHeight(int row) {
  577. return (rowModel == null) ? getRowHeight() : rowModel.getSize(row);
  578. }
  579. /**
  580. * Sets the amount of empty space between cells in adjacent rows.
  581. *
  582. * @param rowMargin the number of pixels between cells in a row
  583. * @see #getRowMargin
  584. * @beaninfo
  585. * bound: true
  586. * description: The amount of space between cells.
  587. */
  588. public void setRowMargin(int rowMargin) {
  589. int old = this.rowMargin;
  590. this.rowMargin = rowMargin;
  591. resizeAndRepaint();
  592. firePropertyChange("rowMargin", old, rowMargin);
  593. }
  594. /**
  595. * Gets the amount of empty space, in pixels, between cells. Equivalent to:
  596. * <code>getIntercellSpacing().height</code>.
  597. * @return the number of pixels between cells in a row
  598. *
  599. * @see #setRowMargin
  600. */
  601. public int getRowMargin() {
  602. return rowMargin;
  603. }
  604. /**
  605. * Sets the <code>rowMargin</code> and the <code>columnMargin</code> --
  606. * the height and width of the space between cells -- to
  607. * <code>intercellSpacing</code>.
  608. *
  609. * @param intercellSpacing a <code>Dimension</code>
  610. * specifying the new width
  611. * and height between cells
  612. * @see #getIntercellSpacing
  613. * @beaninfo
  614. * description: The spacing between the cells,
  615. * drawn in the background color of the JTable.
  616. */
  617. public void setIntercellSpacing(Dimension intercellSpacing) {
  618. // Set the rowMargin here and columnMargin in the TableColumnModel
  619. setRowMargin(intercellSpacing.height);
  620. getColumnModel().setColumnMargin(intercellSpacing.width);
  621. resizeAndRepaint();
  622. }
  623. /**
  624. * Returns the horizontal and vertical space between cells.
  625. * The default spacing is (1, 1), which provides room to draw the grid.
  626. *
  627. * @return the horizontal and vertical spacing between cells
  628. * @see #setIntercellSpacing
  629. */
  630. public Dimension getIntercellSpacing() {
  631. return new Dimension(getColumnModel().getColumnMargin(), rowMargin);
  632. }
  633. /**
  634. * Sets the color used to draw grid lines to <code>gridColor</code> and redisplays.
  635. * The default color is look and feel dependent.
  636. *
  637. * @param gridColor the new color of the grid lines
  638. * @exception IllegalArgumentException if <code>gridColor</code> is <code>null</code>
  639. * @see #getGridColor
  640. * @beaninfo
  641. * bound: true
  642. * description: The grid color.
  643. */
  644. public void setGridColor(Color gridColor) {
  645. if (gridColor == null) {
  646. throw new IllegalArgumentException("New color is null");
  647. }
  648. Color old = this.gridColor;
  649. this.gridColor = gridColor;
  650. firePropertyChange("gridColor", old, gridColor);
  651. // Redraw
  652. repaint();
  653. }
  654. /**
  655. * Returns the color used to draw grid lines.
  656. * The default color is look and feel dependent.
  657. *
  658. * @return the color used to draw grid lines
  659. * @see #setGridColor
  660. */
  661. public Color getGridColor() {
  662. return gridColor;
  663. }
  664. /**
  665. * Sets whether the table draws grid lines around cells.
  666. * If <code>showGrid</code> is true it does; if it is false it doesn't.
  667. * There is no <code>getShowGrid</code> method as this state is held
  668. * in two variables -- <code>showHorizontalLines</code> and <code>showVerticalLines</code> --
  669. * each of which can be queried independently.
  670. *
  671. * @param showGrid true if table view should draw grid lines
  672. *
  673. * @see #setShowVerticalLines
  674. * @see #setShowHorizontalLines
  675. * @beaninfo
  676. * description: The color used to draw the grid lines.
  677. */
  678. public void setShowGrid(boolean showGrid) {
  679. setShowHorizontalLines(showGrid);
  680. setShowVerticalLines(showGrid);
  681. // Redraw
  682. repaint();
  683. }
  684. /**
  685. * Sets whether the table draws horizontal lines between cells.
  686. * If <code>showHorizontalLines</code> is true it does; if it is false it doesn't.
  687. *
  688. * @param showHorizontalLines true if table view should draw horizontal lines
  689. * @see #getShowHorizontalLines
  690. * @see #setShowGrid
  691. * @see #setShowVerticalLines
  692. * @beaninfo
  693. * bound: true
  694. * description: Whether horizontal lines should be drawn in between the cells.
  695. */
  696. public void setShowHorizontalLines(boolean showHorizontalLines) {
  697. boolean old = this.showHorizontalLines;
  698. this.showHorizontalLines = showHorizontalLines;
  699. firePropertyChange("showHorizontalLines", old, showHorizontalLines);
  700. // Redraw
  701. repaint();
  702. }
  703. /**
  704. * Sets whether the table draws vertical lines between cells.
  705. * If <code>showVerticalLines</code> is true it does; if it is false it doesn't.
  706. *
  707. * @param showVerticalLines true if table view should draw vertical lines
  708. * @see #getShowVerticalLines
  709. * @see #setShowGrid
  710. * @see #setShowHorizontalLines
  711. * @beaninfo
  712. * bound: true
  713. * description: Whether vertical lines should be drawn in between the cells.
  714. */
  715. public void setShowVerticalLines(boolean showVerticalLines) {
  716. boolean old = this.showVerticalLines;
  717. this.showVerticalLines = showVerticalLines;
  718. firePropertyChange("showVerticalLines", old, showVerticalLines);
  719. // Redraw
  720. repaint();
  721. }
  722. /**
  723. * Returns true if the table draws horizontal lines between cells, false if it
  724. * doesn't. The default is true.
  725. *
  726. * @return true if the table draws horizontal lines between cells, false if it
  727. * doesn't
  728. * @see #setShowHorizontalLines
  729. */
  730. public boolean getShowHorizontalLines() {
  731. return showHorizontalLines;
  732. }
  733. /**
  734. * Returns true if the table draws vertical lines between cells, false if it
  735. * doesn't. The default is true.
  736. *
  737. * @return true if the table draws vertical lines between cells, false if it
  738. * doesn't
  739. * @see #setShowVerticalLines
  740. */
  741. public boolean getShowVerticalLines() {
  742. return showVerticalLines;
  743. }
  744. /**
  745. * Sets the table's auto resize mode when the table is resized.
  746. *
  747. * @param mode One of 5 legal values:
  748. * AUTO_RESIZE_OFF,
  749. * AUTO_RESIZE_NEXT_COLUMN,
  750. * AUTO_RESIZE_SUBSEQUENT_COLUMNS,
  751. * AUTO_RESIZE_LAST_COLUMN,
  752. * AUTO_RESIZE_ALL_COLUMNS
  753. *
  754. * @see #getAutoResizeMode
  755. * @see #doLayout
  756. * @beaninfo
  757. * bound: true
  758. * description: Whether the columns should adjust themselves automatically.
  759. * enum: AUTO_RESIZE_OFF JTable.AUTO_RESIZE_OFF
  760. * AUTO_RESIZE_NEXT_COLUMN JTable.AUTO_RESIZE_NEXT_COLUMN
  761. * AUTO_RESIZE_SUBSEQUENT_COLUMNS JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS
  762. * AUTO_RESIZE_LAST_COLUMN JTable.AUTO_RESIZE_LAST_COLUMN
  763. * AUTO_RESIZE_ALL_COLUMNS JTable.AUTO_RESIZE_ALL_COLUMNS
  764. */
  765. public void setAutoResizeMode(int mode) {
  766. if ((mode == AUTO_RESIZE_OFF) ||
  767. (mode == AUTO_RESIZE_NEXT_COLUMN) ||
  768. (mode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) ||
  769. (mode == AUTO_RESIZE_LAST_COLUMN) ||
  770. (mode == AUTO_RESIZE_ALL_COLUMNS)) {
  771. int old = autoResizeMode;
  772. autoResizeMode = mode;
  773. resizeAndRepaint();
  774. if (tableHeader != null) {
  775. tableHeader.resizeAndRepaint();
  776. }
  777. firePropertyChange("autoResizeMode", old, autoResizeMode);
  778. }
  779. }
  780. /**
  781. * Returns the auto resize mode of the table. The default mode
  782. * is AUTO_RESIZE_SUBSEQUENT_COLUMNS.
  783. *
  784. * @return the autoResizeMode of the table
  785. *
  786. * @see #setAutoResizeMode
  787. * @see #doLayout
  788. */
  789. public int getAutoResizeMode() {
  790. return autoResizeMode;
  791. }
  792. /**
  793. * Sets this table's <code>autoCreateColumnsFromModel</code> flag.
  794. * This method calls <code>createDefaultColumnsFromModel</code> if
  795. * <code>autoCreateColumnsFromModel</code> changes from false to true.
  796. *
  797. * @param autoCreateColumnsFromModel true if <code>JTable</code> should automatically create columns
  798. * @see #getAutoCreateColumnsFromModel
  799. * @see #createDefaultColumnsFromModel
  800. * @beaninfo
  801. * bound: true
  802. * description: Automatically populates the columnModel when a new TableModel is submitted.
  803. */
  804. public void setAutoCreateColumnsFromModel(boolean autoCreateColumnsFromModel) {
  805. if (this.autoCreateColumnsFromModel != autoCreateColumnsFromModel) {
  806. boolean old = this.autoCreateColumnsFromModel;
  807. this.autoCreateColumnsFromModel = autoCreateColumnsFromModel;
  808. if (autoCreateColumnsFromModel) {
  809. createDefaultColumnsFromModel();
  810. }
  811. firePropertyChange("autoCreateColumnsFromModel", old, autoCreateColumnsFromModel);
  812. }
  813. }
  814. /**
  815. * Determines whether the table will create default columns from the model.
  816. * If true, <code>setModel</code> will clear any existing columns and
  817. * create new columns from the new model. Also, if the event in
  818. * the <code>tableChanged</code> notification specifies that the
  819. * entire table changed, then the columns will be rebuilt.
  820. * The default is true.
  821. *
  822. * @return the autoCreateColumnsFromModel of the table
  823. * @see #setAutoCreateColumnsFromModel
  824. * @see #createDefaultColumnsFromModel
  825. */
  826. public boolean getAutoCreateColumnsFromModel() {
  827. return autoCreateColumnsFromModel;
  828. }
  829. /**
  830. * Creates default columns for the table from
  831. * the data model using the <code>getColumnCount</code> method
  832. * defined in the <code>TableModel</code> interface.
  833. * <p>
  834. * Clears any existing columns before creating the
  835. * new columns based on information from the model.
  836. *
  837. * @see #getAutoCreateColumnsFromModel
  838. */
  839. public void createDefaultColumnsFromModel() {
  840. TableModel m = getModel();
  841. if (m != null) {
  842. // Remove any current columns
  843. TableColumnModel cm = getColumnModel();
  844. while (cm.getColumnCount() > 0) {
  845. cm.removeColumn(cm.getColumn(0));
  846. }
  847. // Create new columns from the data model info
  848. for (int i = 0; i < m.getColumnCount(); i++) {
  849. TableColumn newColumn = new TableColumn(i);
  850. addColumn(newColumn);
  851. }
  852. }
  853. }
  854. /**
  855. * Sets a default cell renderer to be used if no renderer has been set in
  856. * a <code>TableColumn</code>. If renderer is <code>null</code>,
  857. * removes the default renderer for this column class.
  858. *
  859. * @param columnClass set the default cell renderer for this columnClass
  860. * @param renderer default cell renderer to be used for this
  861. * columnClass
  862. * @see #getDefaultRenderer
  863. * @see #setDefaultEditor
  864. */
  865. public void setDefaultRenderer(Class columnClass, TableCellRenderer renderer) {
  866. if (renderer != null) {
  867. defaultRenderersByColumnClass.put(columnClass, renderer);
  868. }
  869. else {
  870. defaultRenderersByColumnClass.remove(columnClass);
  871. }
  872. }
  873. /**
  874. * Returns the cell renderer to be used when no renderer has been set in
  875. * a <code>TableColumn</code>. During the rendering of cells the renderer is fetched from
  876. * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
  877. * there is no entry for this <code>columnClass</code> the method returns
  878. * the entry for the most specific superclass. The <code>JTable</code> installs entries
  879. * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
  880. * or replaced.
  881. *
  882. * @param columnClass return the default cell renderer
  883. * for this columnClass
  884. * @return the renderer for this columnClass
  885. * @see #setDefaultRenderer
  886. * @see #getColumnClass
  887. */
  888. public TableCellRenderer getDefaultRenderer(Class columnClass) {
  889. if (columnClass == null) {
  890. return null;
  891. }
  892. else {
  893. Object renderer = defaultRenderersByColumnClass.get(columnClass);
  894. if (renderer != null) {
  895. return (TableCellRenderer)renderer;
  896. }
  897. else {
  898. return getDefaultRenderer(columnClass.getSuperclass());
  899. }
  900. }
  901. }
  902. /**
  903. * Sets a default cell editor to be used if no editor has been set in
  904. * a <code>TableColumn</code>. If no editing is required in a table, or a
  905. * particular column in a table, uses the <code>isCellEditable</code>
  906. * method in the <code>TableModel</code> interface to ensure that this
  907. * <code>JTable</code> will not start an editor in these columns.
  908. * If editor is <code>null</code>, removes the default editor for this
  909. * column class.
  910. *
  911. * @param columnClass set the default cell editor for this columnClass
  912. * @param editor default cell editor to be used for this columnClass
  913. * @see TableModel#isCellEditable
  914. * @see #getDefaultEditor
  915. * @see #setDefaultRenderer
  916. */
  917. public void setDefaultEditor(Class columnClass, TableCellEditor editor) {
  918. if (editor != null) {
  919. defaultEditorsByColumnClass.put(columnClass, editor);
  920. }
  921. else {
  922. defaultEditorsByColumnClass.remove(columnClass);
  923. }
  924. }
  925. /**
  926. * Returns the editor to be used when no editor has been set in
  927. * a <code>TableColumn</code>. During the editing of cells the editor is fetched from
  928. * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
  929. * there is no entry for this <code>columnClass</code> the method returns
  930. * the entry for the most specific superclass. The <code>JTable</code> installs entries
  931. * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
  932. * or replaced.
  933. *
  934. * @param columnClass return the default cell editor for this columnClass
  935. * @return the default cell editor to be used for this columnClass
  936. * @see #setDefaultEditor
  937. * @see #getColumnClass
  938. */
  939. public TableCellEditor getDefaultEditor(Class columnClass) {
  940. if (columnClass == null) {
  941. return null;
  942. }
  943. else {
  944. Object editor = defaultEditorsByColumnClass.get(columnClass);
  945. if (editor != null) {
  946. return (TableCellEditor)editor;
  947. }
  948. else {
  949. return getDefaultEditor(columnClass.getSuperclass());
  950. }
  951. }
  952. }
  953. /**
  954. * Sets the <code>dragEnabled</code> property,
  955. * which must be <code>true</code> to enable
  956. * automatic drag handling (the first part of drag and drop)
  957. * on this component.
  958. * The <code>transferHandler</code> property needs to be set
  959. * to a non-<code>null</code> value for the drag to do
  960. * anything. The default value of the <code>dragEnabled</code
  961. * property
  962. * is <code>false</code>.
  963. *
  964. * <p>
  965. *
  966. * When automatic drag handling is enabled,
  967. * most look and feels begin a drag-and-drop operation
  968. * whenever the user presses the mouse button over a selection
  969. * and then moves the mouse a few pixels.
  970. * Setting this property to <code>true</code>
  971. * can therefore have a subtle effect on
  972. * how selections behave.
  973. *
  974. * <p>
  975. *
  976. * Some look and feels might not support automatic drag and drop;
  977. * they will ignore this property. You can work around such
  978. * look and feels by modifying the component
  979. * to directly call the <code>exportAsDrag</code> method of a
  980. * <code>TransferHandler</code>.
  981. *
  982. * @param b the value to set the <code>dragEnabled</code> property to
  983. * @exception HeadlessException if
  984. * <code>b</code> is <code>true</code> and
  985. * <code>GraphicsEnvironment.isHeadless()</code>
  986. * returns <code>true</code>
  987. * @see java.awt.GraphicsEnvironment#isHeadless
  988. * @see #getDragEnabled
  989. * @see #setTransferHandler
  990. * @see TransferHandler
  991. * @since 1.4
  992. *
  993. * @beaninfo
  994. * description: determines whether automatic drag handling is enabled
  995. * bound: false
  996. */
  997. public void setDragEnabled(boolean b) {
  998. if (b && GraphicsEnvironment.isHeadless()) {
  999. throw new HeadlessException();
  1000. }
  1001. dragEnabled = b;
  1002. }
  1003. /**
  1004. * Gets the value of the <code>dragEnabled</code> property.
  1005. *
  1006. * @return the value of the <code>dragEnabled</code> property
  1007. * @see #setDragEnabled
  1008. * @since 1.4
  1009. */
  1010. public boolean getDragEnabled() {
  1011. return dragEnabled;
  1012. }
  1013. //
  1014. // Selection methods
  1015. //
  1016. /**
  1017. * Sets the table's selection mode to allow only single selections, a single
  1018. * contiguous interval, or multiple intervals.
  1019. * <P>
  1020. * <bold>Note:</bold>
  1021. * <code>JTable</code> provides all the methods for handling
  1022. * column and row selection. When setting states,
  1023. * such as <code>setSelectionMode</code>, it not only
  1024. * updates the mode for the row selection model but also sets similar
  1025. * values in the selection model of the <code>columnModel</code>.
  1026. * If you want to have the row and column selection models operating
  1027. * in different modes, set them both directly.
  1028. * <p>
  1029. * Both the row and column selection models for <code>JTable</code>
  1030. * default to using a <code>DefaultListSelectionModel</code>
  1031. * so that <code>JTable</code> works the same way as the
  1032. * <code>JList</code>. See the <code>setSelectionMode</code> method
  1033. * in <code>JList</code> for details about the modes.
  1034. *
  1035. * @see JList#setSelectionMode
  1036. * @beaninfo
  1037. * description: The selection mode used by the row and column selection models.
  1038. * enum: SINGLE_SELECTION ListSelectionModel.SINGLE_SELECTION
  1039. * SINGLE_INTERVAL_SELECTION ListSelectionModel.SINGLE_INTERVAL_SELECTION
  1040. * MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
  1041. */
  1042. public void setSelectionMode(int selectionMode) {
  1043. clearSelection();
  1044. getSelectionModel().setSelectionMode(selectionMode);
  1045. getColumnModel().getSelectionModel().setSelectionMode(selectionMode);
  1046. }
  1047. /**
  1048. * Sets whether the rows in this model can be selected.
  1049. *
  1050. * @param rowSelectionAllowed true if this model will allow row selection
  1051. * @see #getRowSelectionAllowed
  1052. * @beaninfo
  1053. * bound: true
  1054. * attribute: visualUpdate true
  1055. * description: If true, an entire row is selected for each selected cell.
  1056. */
  1057. public void setRowSelectionAllowed(boolean rowSelectionAllowed) {
  1058. boolean old = this.rowSelectionAllowed;
  1059. this.rowSelectionAllowed = rowSelectionAllowed;
  1060. if (old != rowSelectionAllowed) {
  1061. repaint();
  1062. }
  1063. firePropertyChange("rowSelectionAllowed", old, rowSelectionAllowed);
  1064. }
  1065. /**
  1066. * Returns true if rows can be selected.
  1067. *
  1068. * @return true if rows can be selected, otherwise false
  1069. * @see #setRowSelectionAllowed
  1070. */
  1071. public boolean getRowSelectionAllowed() {
  1072. return rowSelectionAllowed;
  1073. }
  1074. /**
  1075. * Sets whether the columns in this model can be selected.
  1076. *
  1077. * @param columnSelectionAllowed true if this model will allow column selection
  1078. * @see #getColumnSelectionAllowed
  1079. * @beaninfo
  1080. * bound: true
  1081. * attribute: visualUpdate true
  1082. * description: If true, an entire column is selected for each selected cell.
  1083. */
  1084. public void setColumnSelectionAllowed(boolean columnSelectionAllowed) {
  1085. boolean old = columnModel.getColumnSelectionAllowed();
  1086. columnModel.setColumnSelectionAllowed(columnSelectionAllowed);
  1087. if (old != columnSelectionAllowed) {
  1088. repaint();
  1089. }
  1090. firePropertyChange("columnSelectionAllowed", old, columnSelectionAllowed);
  1091. }
  1092. /**
  1093. * Returns true if columns can be selected.
  1094. *
  1095. * @return true if columns can be selected, otherwise false
  1096. * @see #setColumnSelectionAllowed
  1097. */
  1098. public boolean getColumnSelectionAllowed() {
  1099. return columnModel.getColumnSelectionAllowed();
  1100. }
  1101. /**
  1102. * Sets whether this table allows both a column selection and a
  1103. * row selection to exist simultaneously. When set,
  1104. * the table treats the intersection of the row and column selection
  1105. * models as the selected cells. Override <code>isCellSelected</code> to
  1106. * change this default behavior. This method is equivalent to setting
  1107. * both the <code>rowSelectionAllowed</code> property and
  1108. * <code>columnSelectionAllowed</code> property of the
  1109. * <code>columnModel</code> to the supplied value.
  1110. *
  1111. * @param cellSelectionEnabled true if simultaneous row and column
  1112. * selection is allowed
  1113. * @see #getCellSelectionEnabled
  1114. * @see #isCellSelected
  1115. * @beaninfo
  1116. * bound: true
  1117. * attribute: visualUpdate true
  1118. * description: Select a rectangular region of cells rather than
  1119. * rows or columns.
  1120. */
  1121. public void setCellSelectionEnabled(boolean cellSelectionEnabled) {
  1122. setRowSelectionAllowed(cellSelectionEnabled);
  1123. setColumnSelectionAllowed(cellSelectionEnabled);
  1124. boolean old = this.cellSelectionEnabled;
  1125. this.cellSelectionEnabled = cellSelectionEnabled;
  1126. firePropertyChange("cellSelectionEnabled", old, cellSelectionEnabled);
  1127. }
  1128. /**
  1129. * Returns true if both row and column selection models are enabled.
  1130. * Equivalent to <code>getRowSelectionAllowed() &&
  1131. * getColumnSelectionAllowed()</code>.
  1132. *
  1133. * @return true if both row and column selection models are enabled
  1134. *
  1135. * @see #setCellSelectionEnabled
  1136. */
  1137. public boolean getCellSelectionEnabled() {
  1138. return getRowSelectionAllowed() && getColumnSelectionAllowed();
  1139. }
  1140. /**
  1141. * Selects all rows, columns, and cells in the table.
  1142. */
  1143. public void selectAll() {
  1144. // If I'm currently editing, then I should stop editing
  1145. if (isEditing()) {
  1146. removeEditor();
  1147. }
  1148. if (getRowCount() > 0 && getColumnCount() > 0) {
  1149. setRowSelectionInterval(0, getRowCount()-1);
  1150. setColumnSelectionInterval(0, getColumnCount()-1);
  1151. }
  1152. }
  1153. /**
  1154. * Deselects all selected columns and rows.
  1155. */
  1156. public void clearSelection() {
  1157. columnModel.getSelectionModel().clearSelection();
  1158. selectionModel.clearSelection();
  1159. }
  1160. private int boundRow(int row) throws IllegalArgumentException {
  1161. if (row < 0 || row >= getRowCount()) {
  1162. throw new IllegalArgumentException("Row index out of range");
  1163. }
  1164. return row;
  1165. }
  1166. private int boundColumn(int col) {
  1167. if (col< 0 || col >= getColumnCount()) {
  1168. throw new IllegalArgumentException("Column index out of range");
  1169. }
  1170. return col;
  1171. }
  1172. /**
  1173. * Selects the rows from <code>index0</code> to <code>index1</code>,
  1174. * inclusive.
  1175. *
  1176. * @exception IllegalArgumentException if <code>index0</code> or
  1177. * <code>index1</code> lie outside
  1178. * [0, <code>getRowCount()</code>-1]
  1179. * @param index0 one end of the interval
  1180. * @param index1 the other end of the interval
  1181. */
  1182. public void setRowSelectionInterval(int index0, int index1) {
  1183. selectionModel.setSelectionInterval(boundRow(index0), boundRow(index1));
  1184. }
  1185. /**
  1186. * Selects the columns from <code>index0</code> to <code>index1</code>,
  1187. * inclusive.
  1188. *
  1189. * @exception IllegalArgumentException if <code>index0</code> or
  1190. * <code>index1</code> lie outside
  1191. * [0, <code>getColumnCount()</code>-1]
  1192. * @param index0 one end of the interval
  1193. * @param index1 the other end of the interval
  1194. */
  1195. public void setColumnSelectionInterval(int index0, int index1) {
  1196. columnModel.getSelectionModel().setSelectionInterval(boundColumn(index0), boundColumn(index1));
  1197. }
  1198. /**
  1199. * Adds the rows from <code>index0</code> to <code>index1</code>, inclusive, to
  1200. * the current selection.
  1201. *
  1202. * @exception IllegalArgumentException if <code>index0</code> or <code>index1</code>
  1203. * lie outside [0, <code>getRowCount()</code>-1]
  1204. * @param index0 one end of the interval
  1205. * @param index1 the other end of the interval
  1206. */
  1207. public void addRowSelectionInterval(int index0, int index1) {
  1208. selectionModel.addSelectionInterval(boundRow(index0), boundRow(index1));
  1209. }
  1210. /**
  1211. * Adds the columns from <code>index0</code> to <code>index1</code>,
  1212. * inclusive, to the current selection.
  1213. *
  1214. * @exception IllegalArgumentException if <code>index0</code> or
  1215. * <code>index1</code> lie outside
  1216. * [0, <code>getColumnCount()</code>-1]
  1217. * @param index0 one end of the interval
  1218. * @param index1 the other end of the interval
  1219. */
  1220. public void addColumnSelectionInterval(int index0, int index1) {
  1221. columnModel.getSelectionModel().addSelectionInterval(boundColumn(index0), boundColumn(index1));
  1222. }
  1223. /**
  1224. * Deselects the rows from <code>index0</code> to <code>index1</code>, inclusive.
  1225. *
  1226. * @exception IllegalArgumentException if <code>index0</code> or
  1227. * <code>index1</code> lie outside
  1228. * [0, <code>getRowCount()</code>-1]
  1229. * @param index0 one end of the interval
  1230. * @param index1 the other end of the interval
  1231. */
  1232. public void removeRowSelectionInterval(int index0, int index1) {
  1233. selectionModel.removeSelectionInterval(boundRow(index0), boundRow(index1));
  1234. }
  1235. /**
  1236. * Deselects the columns from <code>index0</code> to <code>index1</code>, inclusive.
  1237. *
  1238. * @exception IllegalArgumentException if <code>index0</code> or
  1239. * <code>index1</code> lie outside
  1240. * [0, <code>getColumnCount()</code>-1]
  1241. * @param index0 one end of the interval
  1242. * @param index1 the other end of the interval
  1243. */
  1244. public void removeColumnSelectionInterval(int index0, int index1) {
  1245. columnModel.getSelectionModel().removeSelectionInterval(boundColumn(index0), boundColumn(index1));
  1246. }
  1247. /**
  1248. * Returns the index of the first selected row, -1 if no row is selected.
  1249. * @return the index of the first selected row
  1250. */
  1251. public int getSelectedRow() {
  1252. return selectionModel.getMinSelectionIndex();
  1253. }
  1254. /**
  1255. * Returns the index of the first selected column,
  1256. * -1 if no column is selected.
  1257. * @return the index of the first selected column
  1258. */
  1259. public int getSelectedColumn() {
  1260. return columnModel.getSelectionModel().getMinSelectionIndex();
  1261. }
  1262. /**
  1263. * Returns the indices of all selected rows.
  1264. *
  1265. * @return an array of integers containing the indices of all selected rows,
  1266. * or an empty array if no row is selected
  1267. * @see #getSelectedRow
  1268. */
  1269. public int[] getSelectedRows() {
  1270. int iMin = selectionModel.getMinSelectionIndex();
  1271. int iMax = selectionModel.getMaxSelectionIndex();
  1272. if ((iMin == -1) || (iMax == -1)) {
  1273. return new int[0];
  1274. }
  1275. int[] rvTmp = new int[1+ (iMax - iMin)];
  1276. int n = 0;
  1277. for(int i = iMin; i <= iMax; i++) {
  1278. if (selectionModel.isSelectedIndex(i)) {
  1279. rvTmp[n++] = i;
  1280. }
  1281. }
  1282. int[] rv = new int[n];
  1283. System.arraycopy(rvTmp, 0, rv, 0, n);
  1284. return rv;
  1285. }
  1286. /**
  1287. * Returns the indices of all selected columns.
  1288. *
  1289. * @return an array of integers containing the indices of all selected columns,
  1290. * or an empty array if no column is selected
  1291. * @see #getSelectedColumn
  1292. */
  1293. public int[] getSelectedColumns() {
  1294. return columnModel.getSelectedColumns();
  1295. }
  1296. /**
  1297. * Returns the number of selected rows.
  1298. *
  1299. * @return the number of selected rows, 0 if no rows are selected
  1300. */
  1301. public int getSelectedRowCount() {
  1302. int iMin = selectionModel.getMinSelectionIndex();
  1303. int iMax = selectionModel.getMaxSelectionIndex();
  1304. int count = 0;
  1305. for(int i = iMin; i <= iMax; i++) {
  1306. if (selectionModel.isSelectedIndex(i)) {
  1307. count++;
  1308. }
  1309. }
  1310. return count;
  1311. }
  1312. /**
  1313. * Returns the number of selected columns.
  1314. *
  1315. * @return the number of selected columns, 0 if no columns are selected
  1316. */
  1317. public int getSelectedColumnCount() {
  1318. return columnModel.getSelectedColumnCount();
  1319. }
  1320. /**
  1321. * Returns true if the row at the specified index is selected.
  1322. *
  1323. * @return true if the row at index <code>row</code> is selected, where 0 is the
  1324. * first row
  1325. * @exception IllegalArgumentException if <code>row</code> is not in the
  1326. * valid range
  1327. */
  1328. public boolean isRowSelected(int row) {
  1329. return selectionModel.isSelectedIndex(row);
  1330. }
  1331. /**
  1332. * Returns true if the column at the specified index is selected.
  1333. *
  1334. * @param column the column in the column model
  1335. * @return true if the column at index <code>column</code> is selected, where
  1336. * 0 is the first column
  1337. * @exception IllegalArgumentException if <code>column</code> is not in the
  1338. * valid range
  1339. */
  1340. public boolean isColumnSelected(int column) {
  1341. return columnModel.getSelectionModel().isSelectedIndex(column);
  1342. }
  1343. /**
  1344. * Returns true if the cell at the specified position is selected.
  1345. * @param row the row being queried
  1346. * @param column the column being queried
  1347. *
  1348. * @return true if the cell at index <code>(row, column)</code> is selected,
  1349. * where the first row and first column are at index 0
  1350. * @exception IllegalArgumentException if <code>row</code> or <code>column</code>
  1351. * are not in the valid range
  1352. */
  1353. public boolean isCellSelected(int row, int column) {
  1354. if (!getRowSelectionAllowed() && !getColumnSelectionAllowed()) {
  1355. return false;
  1356. }
  1357. return (!getRowSelectionAllowed() || isRowSelected(row)) &&
  1358. (!getColumnSelectionAllowed() || isColumnSelected(column));
  1359. }
  1360. private void changeSelectionModel(ListSelectionModel sm, int index,
  1361. boolean toggle, boolean extend, boolean selected) {
  1362. if (extend) {
  1363. if (toggle) {
  1364. sm.setAnchorSelectionIndex(index);
  1365. }
  1366. else {
  1367. sm.setLeadSelectionIndex(index);
  1368. }
  1369. }
  1370. else {
  1371. if (toggle) {
  1372. if (selected) {
  1373. sm.removeSelectionInterval(index, index);
  1374. }
  1375. else {
  1376. sm.addSelectionInterval(index, index);
  1377. }
  1378. }
  1379. else {
  1380. sm.setSelectionInterval(index, index);
  1381. }
  1382. }
  1383. }
  1384. /**
  1385. * Updates the selection models of the table, depending on the state of the
  1386. * two flags: <code>toggle</code> and <code>extend</code>. All changes
  1387. * to the selection that are the result of keyboard or mouse events received
  1388. * by the UI are channeled through this method so that the behavior may be
  1389. * overridden by a subclass.
  1390. * <p>
  1391. * This implementation uses the following conventions:
  1392. * <ul>
  1393. * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>false</em>.
  1394. * Clear the previous selection and ensure the new cell is selected.
  1395. * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>true</em>.
  1396. * Extend the previous selection to include the specified cell.
  1397. * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>false</em>.
  1398. * If the specified cell is selected, deselect it. If it is not selected, select it.
  1399. * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>true</em>.
  1400. * Leave the selection state as it is, but move the anchor index to the specified location.
  1401. * </ul>
  1402. * @param rowIndex affects the selection at <code>row</code>
  1403. * @param columnIndex affects the selection at <code>column</code>
  1404. * @param toggle see description above
  1405. * @param extend if true, extend the current selection
  1406. *
  1407. */
  1408. public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
  1409. ListSelectionModel rsm = getSelectionModel();
  1410. ListSelectionModel csm = getColumnModel().getSelectionModel();
  1411. // Check the selection here rather than in each selection model.
  1412. // This is significant in cell selection mode if we are supposed
  1413. // to be toggling the selection. In this case it is better to
  1414. // ensure that the cell's selection state will indeed be changed.
  1415. // If this were done in the code for the selection model it
  1416. // might leave a cell in selection state if the row was
  1417. // selected but the column was not - as it would toggle them both.
  1418. boolean selected = isCellSelected(rowIndex, columnIndex);
  1419. changeSelectionModel(csm, columnIndex, toggle, extend, selected);
  1420. changeSelectionModel(rsm, rowIndex, toggle, extend, selected);
  1421. // Scroll after changing the selection as blit scrolling is immediate,
  1422. // so that if we cause the repaint after the scroll we end up painting
  1423. // everything!
  1424. if (getAutoscrolls()) {
  1425. Rectangle cellRect = getCellRect(rowIndex, columnIndex, false);
  1426. if (cellRect != null) {
  1427. scrollRectToVisible(cellRect);
  1428. }
  1429. }
  1430. }
  1431. /**
  1432. * Returns the foreground color for selected cells.
  1433. *
  1434. * @return the <code>Color</code> object for the foreground property
  1435. * @see #setSelectionForeground
  1436. * @see #setSelectionBackground
  1437. */
  1438. public Color getSelectionForeground() {
  1439. return selectionForeground;
  1440. }
  1441. /**
  1442. * Sets the foreground color for selected cells. Cell renderers
  1443. * can use this color to render text and graphics for selected
  1444. * cells.
  1445. * <p>
  1446. * The default value of this property is defined by the look
  1447. * and feel implementation.
  1448. * <p>
  1449. * This is a <a href="http://java.sun.com/docs/books/tutorial/javabeans/whatis/beanDefinition.html">JavaBeans</a> bound property.
  1450. *
  1451. * @param selectionForeground the <code>Color</code> to use in the foreground
  1452. * for selected list items
  1453. * @see #getSelectionForeground
  1454. * @see #setSelectionBackground
  1455. * @see #setForeground
  1456. * @see #setBackground
  1457. * @see #setFont
  1458. * @beaninfo
  1459. * bound: true
  1460. * description: A default foreground color for selected cells.
  1461. */
  1462. public void setSelectionForeground(Color selectionForeground) {
  1463. Color old = this.selectionForeground;
  1464. this.selectionForeground = selectionForeground;
  1465. firePropertyChange("selectionForeground", old, selectionForeground);
  1466. if ( !selectionForeground.equals(old) )
  1467. {
  1468. repaint();
  1469. }
  1470. }
  1471. /**
  1472. * Returns the background color for selected cells.
  1473. *
  1474. * @return the <code>Color</code> used for the background of selected list items
  1475. * @see #setSelectionBackground
  1476. * @see #setSelectionForeground
  1477. */
  1478. public Color getSelectionBackground() {
  1479. return selectionBackground;
  1480. }
  1481. /**
  1482. * Sets the background color for selected cells. Cell renderers
  1483. * can use this color to the fill selected cells.
  1484. * <p>
  1485. * The default value of this property is defined by the look
  1486. * and feel implementation.
  1487. * <p>
  1488. * This is a <a href="http://java.sun.com/docs/books/tutorial/javabeans/whatis/beanDefinition.html">JavaBeans</a> bound property.
  1489. *
  1490. * @param selectionBackground the <code>Color</code> to use for the background
  1491. * of selected cells
  1492. * @see #getSelectionBackground
  1493. * @see #setSelectionForeground
  1494. * @see #setForeground
  1495. * @see #setBackground
  1496. * @see #setFont
  1497. * @beaninfo
  1498. * bound: true
  1499. * description: A default background color for selected cells.
  1500. */
  1501. public void setSelectionBackground(Color selectionBackground) {
  1502. Color old = this.selectionBackground;
  1503. this.selectionBackground = selectionBackground;
  1504. firePropertyChange("selectionBackground", old, selectionBackground);
  1505. if ( !selectionBackground.equals(old) )
  1506. {
  1507. repaint();
  1508. }
  1509. }
  1510. /**
  1511. * Returns the <code>TableColumn</code> object for the column in the table
  1512. * whose identifier is equal to <code>identifier</code>, when compared using
  1513. * <code>equals</code>.
  1514. *
  1515. * @return the <code>TableColumn</code> object that matches the identifier
  1516. * @exception IllegalArgumentException if <code>identifier</code> is <code>null</code> or no <code>TableColumn</code> has this identifier
  1517. *
  1518. * @param identifier the identifier object
  1519. */
  1520. public TableColumn getColumn(Object identifier) {
  1521. TableColumnModel cm = getColumnModel();
  1522. int columnIndex = cm.getColumnIndex(identifier);
  1523. return cm.getColumn(columnIndex);
  1524. }
  1525. //
  1526. // Informally implement the TableModel interface.
  1527. //
  1528. /**
  1529. * Maps the index of the column in the view at
  1530. * <code>viewColumnIndex</code> to the index of the column
  1531. * in the table model. Returns the index of the corresponding
  1532. * column in the model. If <code>viewColumnIndex</code>
  1533. * is less than zero, returns <code>viewColumnIndex</code>.
  1534. *
  1535. * @param viewColumnIndex the index of the column in the view
  1536. * @return the index of the corresponding column in the model
  1537. *
  1538. * @see #convertColumnIndexToView
  1539. */
  1540. public int convertColumnIndexToModel(int viewColumnIndex) {
  1541. if (viewColumnIndex < 0) {
  1542. return viewColumnIndex;
  1543. }
  1544. return getColumnModel().getColumn(viewColumnIndex).getModelIndex();
  1545. }
  1546. /**
  1547. * Maps the index of the column in the table model at
  1548. * <code>modelColumnIndex</code> to the index of the column
  1549. * in the view. Returns the index of the
  1550. * corresponding column in the view; returns -1 if this column is not
  1551. * being displayed. If <code>modelColumnIndex</code> is less than zero,
  1552. * returns <code>modelColumnIndex</code>.
  1553. *
  1554. * @param modelColumnIndex the index of the column in the model
  1555. * @return the index of the corresponding column in the view
  1556. *
  1557. * @see #convertColumnIndexToModel
  1558. */
  1559. public int convertColumnIndexToView(int modelColumnIndex) {
  1560. if (modelColumnIndex < 0) {
  1561. return modelColumnIndex;
  1562. }
  1563. TableColumnModel cm = getColumnModel();
  1564. for (int column = 0; column < getColumnCount(); column++) {
  1565. if (cm.getColumn(column).getModelIndex() == modelColumnIndex) {
  1566. return column;
  1567. }
  1568. }
  1569. return -1;
  1570. }
  1571. /**
  1572. * Returns the number of rows in this table's model.
  1573. * @return the number of rows in this table's model
  1574. *
  1575. * @see #getColumnCount
  1576. */
  1577. public int getRowCount() {
  1578. return getModel().getRowCount();
  1579. }
  1580. /**
  1581. * Returns the number of columns in the column model. Note that this may
  1582. * be different from the number of columns in the table model.
  1583. *
  1584. * @return the number of columns in the table
  1585. * @see #getRowCount
  1586. * @see #removeColumn
  1587. */
  1588. public int getColumnCount() {
  1589. return getColumnModel().getColumnCount();
  1590. }
  1591. /**
  1592. * Returns the name of the column appearing in the view at
  1593. * column position <code>column</code>.
  1594. *
  1595. * @param column the column in the view being queried
  1596. * @return the name of the column at position <code>column</code>
  1597. in the view where the first column is column 0
  1598. */
  1599. public String getColumnName(int column) {
  1600. return getModel().getColumnName(convertColumnIndexToModel(column));
  1601. }
  1602. /**
  1603. * Returns the type of the column appearing in the view at
  1604. * column position <code>column</code>.
  1605. *
  1606. * @param column the column in the view being queried
  1607. * @return the type of the column at position <code>column</code>
  1608. * in the view where the first column is column 0
  1609. */
  1610. public Class getColumnClass(int column) {
  1611. return getModel().getColumnClass(convertColumnIndexToModel(column));
  1612. }
  1613. /**
  1614. * Returns the cell value at <code>row</code> and <code>column</code>.
  1615. * <p>
  1616. * <b>Note</b>: The column is specified in the table view's display
  1617. * order, and not in the <code>TableModel</code>'s column
  1618. * order. This is an important distinction because as the
  1619. * user rearranges the columns in the table,
  1620. * the column at a given index in the view will change.
  1621. * Meanwhile the user's actions never affect the model's
  1622. * column ordering.
  1623. *
  1624. * @param row the row whose value is to be queried
  1625. * @param column the column whose value is to be queried
  1626. * @return the Object at the specified cell
  1627. */
  1628. public Object getValueAt(int row, int column) {
  1629. return getModel().getValueAt(row, convertColumnIndexToModel(column));
  1630. }
  1631. /**
  1632. * Sets the value for the cell in the table model at <code>row</code>
  1633. * and <code>column</code>.
  1634. * <p>
  1635. * <b>Note</b>: The column is specified in the table view's display
  1636. * order, and not in the <code>TableModel</code>'s column
  1637. * order. This is an important distinction because as the
  1638. * user rearranges the columns in the table,
  1639. * the column at a given index in the view will change.
  1640. * Meanwhile the user's actions never affect the model's
  1641. * column ordering.
  1642. *
  1643. * <code>aValue</code> is the new value.
  1644. *
  1645. * @param aValue the new value
  1646. * @param row the row of the cell to be changed
  1647. * @param column the column of the cell to be changed
  1648. * @see #getValueAt
  1649. */
  1650. public void setValueAt(Object aValue, int row, int column) {
  1651. getModel().setValueAt(aValue, row, convertColumnIndexToModel(column));
  1652. }
  1653. /**
  1654. * Returns true if the cell at <code>row</code> and <code>column</code>
  1655. * is editable. Otherwise, invoking <code>setValueAt</code> on the cell
  1656. * will have no effect.
  1657. * <p>
  1658. * <b>Note</b>: The column is specified in the table view's display
  1659. * order, and not in the <code>TableModel</code>'s column
  1660. * order. This is an important distinction because as the
  1661. * user rearranges the columns in the table,
  1662. * the column at a given index in the view will change.
  1663. * Meanwhile the user's actions never affect the model's
  1664. * column ordering.
  1665. *
  1666. *
  1667. * @param row the row whose value is to be queried
  1668. * @param column the column whose value is to be queried
  1669. * @return true if the cell is editable
  1670. * @see #setValueAt
  1671. */
  1672. public boolean isCellEditable(int row, int column) {
  1673. return getModel().isCellEditable(row, convertColumnIndexToModel(column));
  1674. }
  1675. //
  1676. // Adding and removing columns in the view
  1677. //
  1678. /**
  1679. * Appends <code>aColumn</code> to the end of the array of columns held by
  1680. * this <code>JTable</code>'s column model.
  1681. * If the column name of <code>aColumn</code> is <code>null</code>,
  1682. * sets the column name of <code>aColumn</code> to the name
  1683. * returned by <code>getModel().getColumnName()</code>.
  1684. * <p>
  1685. * To add a column to this <code>JTable</code> to display the
  1686. * <code>modelColumn</code>'th column of data in the model with a
  1687. * given <code>width</code>, <code>cellRenderer</code>,
  1688. * and <code>cellEditor</code> you can use:
  1689. * <pre>
  1690. *
  1691. * addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
  1692. *
  1693. * </pre>
  1694. * [Any of the <code>TableColumn</code> constructors can be used
  1695. * instead of this one.]
  1696. * The model column number is stored inside the <code>TableColumn</code>
  1697. * and is used during rendering and editing to locate the appropriates
  1698. * data values in the model. The model column number does not change
  1699. * when columns are reordered in the view.
  1700. *
  1701. * @param aColumn the <code>TableColumn</code> to be added
  1702. * @see #removeColumn
  1703. */
  1704. public void addColumn(TableColumn aColumn) {
  1705. if (aColumn.getHeaderValue() == null) {
  1706. int modelColumn = aColumn.getModelIndex();
  1707. String columnName = getModel().getColumnName(modelColumn);
  1708. aColumn.setHeaderValue(columnName);
  1709. }
  1710. getColumnModel().addColumn(aColumn);
  1711. }
  1712. /**
  1713. * Removes <code>aColumn</code> from this <code>JTable</code>'s
  1714. * array of columns. Note: this method does not remove the column
  1715. * of data from the model; it just removes the <code>TableColumn</code>
  1716. * that was responsible for displaying it.
  1717. *
  1718. * @param aColumn the <code>TableColumn</code> to be removed
  1719. * @see #addColumn
  1720. */
  1721. public void removeColumn(TableColumn aColumn) {
  1722. getColumnModel().removeColumn(aColumn);
  1723. }
  1724. /**
  1725. * Moves the column <code>column</code> to the position currently
  1726. * occupied by the column <code>targetColumn</code> in the view.
  1727. * The old column at <code>targetColumn</code> is
  1728. * shifted left or right to make room.
  1729. *
  1730. * @param column the index of column to be moved
  1731. * @param targetColumn the new index of the column
  1732. */
  1733. public void moveColumn(int column, int targetColumn) {
  1734. getColumnModel().moveColumn(column, targetColumn);
  1735. }
  1736. //
  1737. // Cover methods for various models and helper methods
  1738. //
  1739. /**
  1740. * Returns the index of the column that <code>point</code> lies in,
  1741. * or -1 if the result is not in the range
  1742. * [0, <code>getColumnCount()</code>-1].
  1743. *
  1744. * @param point the location of interest
  1745. * @return the index of the column that <code>point</code> lies in,
  1746. * or -1 if the result is not in the range
  1747. * [0, <code>getColumnCount()</code>-1]
  1748. * @see #rowAtPoint
  1749. */
  1750. public int columnAtPoint(Point point) {
  1751. int x = point.x;
  1752. if( !getComponentOrientation().isLeftToRight() ) {
  1753. x = getWidth() - x;
  1754. }
  1755. return getColumnModel().getColumnIndexAtX(x);
  1756. }
  1757. /**
  1758. * Returns the index of the row that <code>point</code> lies in,
  1759. * or -1 if the result is not in the range
  1760. * [0, <code>getRowCount()</code>-1].
  1761. *
  1762. * @param point the location of interest
  1763. * @return the index of the row that <code>point</code> lies in,
  1764. * or -1 if the result is not in the range
  1765. * [0, <code>getRowCount()</code>-1]
  1766. * @see #columnAtPoint
  1767. */
  1768. public int rowAtPoint(Point point) {
  1769. int y = point.y;
  1770. int result = (rowModel == null) ? ygetRowHeight() : rowModel.getIndex(y);
  1771. if (result < 0) {
  1772. return -1;
  1773. }
  1774. else if (result >= getRowCount()) {
  1775. return -1;
  1776. }
  1777. else {
  1778. return result;
  1779. }
  1780. }
  1781. /**
  1782. * Returns a rectangle for the cell that lies at the intersection of
  1783. * <code>row</code> and <code>column</code>.
  1784. * If <code>includeSpacing</code> is true then the value returned
  1785. * has the full height and width of the row and column
  1786. * specified. If it is false, the returned rectangle is inset by the
  1787. * intercell spacing to return the true bounds of the rendering or
  1788. * editing component as it will be set during rendering.
  1789. * <p>
  1790. * If the column index is valid but the row index is less
  1791. * than zero the method returns a rectangle with the
  1792. * <code>y</code> and <code>height</code> values set appropriately
  1793. * and the <code>x</code> and <code>width</code> values both set
  1794. * to zero. In general, when either the row or column indices indicate a
  1795. * cell outside the appropriate range, the method returns a rectangle
  1796. * depicting the closest edge of the closest cell that is within
  1797. * the table's range. When both row and column indices are out
  1798. * of range the returned rectangle covers the closest
  1799. * point of the closest cell.
  1800. * <p>
  1801. * In all cases, calculations that use this method to calculate
  1802. * results along one axis will not fail because of anomalies in
  1803. * calculations along the other axis. When the cell is not valid
  1804. * the <code>includeSpacing</code> parameter is ignored.
  1805. *
  1806. * @param row the row index where the desired cell
  1807. * is located
  1808. * @param column the column index where the desired cell
  1809. * is located in the display; this is not
  1810. * necessarily the same as the column index
  1811. * in the data model for the table; the
  1812. * {@link #convertColumnIndexToView(int)}
  1813. * method may be used to convert a data
  1814. * model column index to a display
  1815. * column index
  1816. * @param includeSpacing if false, return the true cell bounds -
  1817. * computed by subtracting the intercell
  1818. * spacing from the height and widths of
  1819. * the column and row models
  1820. *
  1821. * @return the rectangle containing the cell at location
  1822. * <code>row</code>,<code>column</code>
  1823. */
  1824. public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
  1825. Rectangle r = new Rectangle();
  1826. boolean valid = true;
  1827. if (row < 0) {
  1828. // y = height = 0;
  1829. valid = false;
  1830. }
  1831. else if (row >= getRowCount()) {
  1832. r.y = getHeight();
  1833. valid = false;
  1834. }
  1835. else {
  1836. r.height = getRowHeight(row);
  1837. r.y = (rowModel == null) ? row * r.height : rowModel.getPosition(row);
  1838. }
  1839. if (column < 0) {
  1840. if( !getComponentOrientation().isLeftToRight() ) {
  1841. r.x = getWidth();
  1842. }
  1843. // otherwise, x = width = 0;
  1844. valid = false;
  1845. }
  1846. else if (column >= getColumnCount()) {
  1847. if( getComponentOrientation().isLeftToRight() ) {
  1848. r.x = getWidth();
  1849. }
  1850. // otherwise, x = width = 0;
  1851. valid = false;
  1852. }
  1853. else {
  1854. TableColumnModel cm = getColumnModel();
  1855. if( getComponentOrientation().isLeftToRight() ) {
  1856. for(int i = 0; i < column; i++) {
  1857. r.x += cm.getColumn(i).getWidth();
  1858. }
  1859. } else {
  1860. for(int i = cm.getColumnCount()-1; i > column; i--) {
  1861. r.x += cm.getColumn(i).getWidth();
  1862. }
  1863. }
  1864. r.width = cm.getColumn(column).getWidth();
  1865. }
  1866. if (valid && !includeSpacing) {
  1867. int rm = getRowMargin();
  1868. int cm = getColumnModel().getColumnMargin();
  1869. // This is not the same as grow(), it rounds differently.
  1870. r.setBounds(r.x + cm2, r.y + rm2, r.width - cm, r.height - rm);
  1871. }
  1872. return r;
  1873. }
  1874. private int viewIndexForColumn(TableColumn aColumn) {
  1875. TableColumnModel cm = getColumnModel();
  1876. for (int column = 0; column < cm.getColumnCount(); column++) {
  1877. if (cm.getColumn(column) == aColumn) {
  1878. return column;
  1879. }
  1880. }
  1881. return -1;
  1882. }
  1883. /**
  1884. * Causes this table to lay out its rows and columns. Overridden so
  1885. * that columns can be resized to accomodate a change in the size of
  1886. * a containing parent.
  1887. * Resizes one or more of the columns in the table
  1888. * so that the total width of all of this <code>JTable</code>'s
  1889. * columns is equal to the width of the table.
  1890. * <p>
  1891. * Before the layout begins the method gets the
  1892. * <code>resizingColumn</code> of the <code>tableHeader</code>.
  1893. * When the method is called as a result of the resizing of an enclosing window,
  1894. * the <code>resizingColumn</code> is <code>null</code>. This means that resizing
  1895. * has taken place "outside" the <code>JTable</code> and the change -
  1896. * or "delta" - should be distributed to all of the columns regardless
  1897. * of this <code>JTable</code>'s automatic resize mode.
  1898. * <p>
  1899. * If the <code>resizingColumn</code> is not <code>null</code>, it is one of
  1900. * the columns in the table that has changed size rather than
  1901. * the table itself. In this case the auto-resize modes govern
  1902. * the way the extra (or deficit) space is distributed
  1903. * amongst the available columns.
  1904. * <p>
  1905. * The modes are:
  1906. * <ul>
  1907. * <li> AUTO_RESIZE_OFF: Don't automatically adjust the column's
  1908. * widths at all. Use a horizontal scrollbar to accomodate the
  1909. * columns when their sum exceeds the width of the
  1910. * <code>Viewport</code>. If the <code>JTable</code> is not
  1911. * enclosed in a <code>JScrollPane</code> this may
  1912. * leave parts of the table invisible.
  1913. * <li> AUTO_RESIZE_NEXT_COLUMN: Use just the column after the
  1914. * resizing column. This results in the "boundary" or divider
  1915. * between adjacent cells being independently adjustable.
  1916. * <li> AUTO_RESIZE_SUBSEQUENT_COLUMNS: Use all columns after the
  1917. * one being adjusted to absorb the changes. This is the
  1918. * default behavior.
  1919. * <li> AUTO_RESIZE_LAST_COLUMN: Automatically adjust the
  1920. * size of the last column only. If the bounds of the last column
  1921. * prevent the desired size from being allocated, set the
  1922. * width of the last column to the appropriate limit and make
  1923. * no further adjustments.
  1924. * <li> AUTO_RESIZE_ALL_COLUMNS: Spread the delta amongst all the columns
  1925. * in the <code>JTable</code>, including the one that is being
  1926. * adjusted.
  1927. * </ul>
  1928. * <p>
  1929. * <bold>Note:</bold> When a <code>JTable</code> makes adjustments
  1930. * to the widths of the columns it respects their minimum and
  1931. * maximum values absolutely. It is therefore possible that,
  1932. * even after this method is called, the total width of the columns
  1933. * is still not equal to the width of the table. When this happens
  1934. * the <code>JTable</code> does not put itself
  1935. * in AUTO_RESIZE_OFF mode to bring up a scroll bar, or break other
  1936. * commitments of its current auto-resize mode -- instead it
  1937. * allows its bounds to be set larger (or smaller) than the total of the
  1938. * column minimum or maximum, meaning, either that there
  1939. * will not be enough room to display all of the columns, or that the
  1940. * columns will not fill the <code>JTable</code>'s bounds.
  1941. * These respectively, result in the clipping of some columns
  1942. * or an area being painted in the <code>JTable</code>'s
  1943. * background color during painting.
  1944. * <p>
  1945. * The mechanism for distributing the delta amongst the available
  1946. * columns is provided in a private method in the <code>JTable</code>
  1947. * class:
  1948. * <pre>
  1949. * adjustSizes(long targetSize, final Resizable3 r, boolean inverse)
  1950. * </pre>
  1951. * an explanation of which is provided in the following section.
  1952. * <code>Resizable3</code> is a private
  1953. * interface that allows any data structure containing a collection
  1954. * of elements with a size, preferred size, maximum size and minimum size
  1955. * to have its elements manipulated by the algorithm.
  1956. * <p>
  1957. * <H3> Distributing the delta </H3>
  1958. * <p>
  1959. * <H4> Overview </H4>
  1960. * <P>
  1961. * Call "DELTA" the difference between the target size and the
  1962. * sum of the preferred sizes of the elements in r. The individual
  1963. * sizes are calculated by taking the original preferred
  1964. * sizes and adding a share of the DELTA - that share being based on
  1965. * how far each preferred size is from its limiting bound (minimum or
  1966. * maximum).
  1967. * <p>
  1968. * <H4>Definition</H4>
  1969. * <P>
  1970. * Call the individual constraints min[i], max[i], and pref[i].
  1971. * <p>
  1972. * Call their respective sums: MIN, MAX, and PREF.
  1973. * <p>
  1974. * Each new size will be calculated using:
  1975. * <p>
  1976. * <pre>
  1977. * size[i] = pref[i] + delta[i]
  1978. * </pre>
  1979. * where each individual delta[i] is calculated according to:
  1980. * <p>
  1981. * If (DELTA < 0) we are in shrink mode where:
  1982. * <p>
  1983. * <PRE>
  1984. * DELTA
  1985. * delta[i] = ------------ * (pref[i] - min[i])
  1986. * (PREF - MIN)
  1987. * </PRE>
  1988. * If (DELTA > 0) we are in expand mode where:
  1989. * <p>
  1990. * <PRE>
  1991. * DELTA
  1992. * delta[i] = ------------ * (max[i] - pref[i])
  1993. * (MAX - PREF)
  1994. * </PRE>
  1995. * <P>
  1996. * The overall effect is that the total size moves that same percentage,
  1997. * k, towards the total minimum or maximum and that percentage guarantees
  1998. * accomodation of the required space, DELTA.
  1999. *
  2000. * <H4>Details</H4>
  2001. * <P>
  2002. * Naive evaluation of the formulae presented here would be subject to
  2003. * the aggregated rounding errors caused by doing this operation in finite
  2004. * precision (using ints). To deal with this, the multiplying factor above,
  2005. * is constantly recalculated and this takes account of the rounding
  2006. * errors in the previous iterations. The result is an algorithm that
  2007. * produces a set of integers whose values exactly sum to the supplied
  2008. * <code>targetSize</code>, and does so by spreading the rounding
  2009. * errors evenly over the given elements.
  2010. *
  2011. * <H4>When the MAX and MIN bounds are hit</H4>
  2012. * <P>
  2013. * When <code>targetSize</code> is outside the [MIN, MAX] range,
  2014. * the algorithm sets all sizes to their appropriate limiting value
  2015. * (maximum or minimum).
  2016. *
  2017. */
  2018. public void doLayout() {
  2019. TableColumn resizingColumn = getResizingColumn();
  2020. if (resizingColumn == null) {
  2021. setWidthsFromPreferredWidths(false);
  2022. }
  2023. else {
  2024. int columnIndex = viewIndexForColumn(resizingColumn);
  2025. int delta = getWidth() - getColumnModel().getTotalColumnWidth();
  2026. accommodateDelta(columnIndex, delta);
  2027. delta = getWidth() - getColumnModel().getTotalColumnWidth();
  2028. if (delta != 0) {
  2029. resizingColumn.setWidth(resizingColumn.getWidth() + delta);
  2030. }
  2031. }
  2032. super.doLayout();
  2033. }
  2034. private TableColumn getResizingColumn() {
  2035. return (tableHeader == null) ? null
  2036. : tableHeader.getResizingColumn();
  2037. }
  2038. /**
  2039. * Sizes the table columns to fit the available space.
  2040. * @deprecated As of Swing version 1.0.3,
  2041. * replaced by <code>doLayout()</code>.
  2042. * @see #doLayout
  2043. */
  2044. public void sizeColumnsToFit(boolean lastColumnOnly) {
  2045. int oldAutoResizeMode = autoResizeMode;
  2046. setAutoResizeMode(lastColumnOnly ? AUTO_RESIZE_LAST_COLUMN
  2047. : AUTO_RESIZE_ALL_COLUMNS);
  2048. sizeColumnsToFit(-1);
  2049. setAutoResizeMode(oldAutoResizeMode);
  2050. }
  2051. /**
  2052. * Obsolete as of Java 2 platform v1.4. Please use the
  2053. * <code>doLayout()</code> method instead.
  2054. * @param resizingColumn the column whose resizing made this adjustment
  2055. * necessary or -1 if there is no such column
  2056. * @see #doLayout
  2057. */
  2058. public void sizeColumnsToFit(int resizingColumn) {
  2059. if (resizingColumn == -1) {
  2060. setWidthsFromPreferredWidths(false);
  2061. }
  2062. else {
  2063. if (autoResizeMode == AUTO_RESIZE_OFF) {
  2064. TableColumn aColumn = getColumnModel().getColumn(resizingColumn);
  2065. aColumn.setPreferredWidth(aColumn.getWidth());
  2066. }
  2067. else {
  2068. int delta = getWidth() - getColumnModel().getTotalColumnWidth();
  2069. accommodateDelta(resizingColumn, delta);
  2070. }
  2071. }
  2072. }
  2073. private void setWidthsFromPreferredWidths(final boolean inverse) {
  2074. int totalWidth = getWidth();
  2075. int totalPreferred = getPreferredSize().width;
  2076. int target = !inverse ? totalWidth : totalPreferred;
  2077. final TableColumnModel cm = columnModel;
  2078. Resizable3 r = new Resizable3() {
  2079. public int getElementCount() { return cm.getColumnCount(); }
  2080. public int getLowerBoundAt(int i) { return cm.getColumn(i).getMinWidth(); }
  2081. public int getUpperBoundAt(int i) { return cm.getColumn(i).getMaxWidth(); }
  2082. public int getMidPointAt(int i) {
  2083. if (!inverse) {
  2084. return cm.getColumn(i).getPreferredWidth();
  2085. }
  2086. else {
  2087. return cm.getColumn(i).getWidth();
  2088. }
  2089. }
  2090. public void setSizeAt(int s, int i) {
  2091. if (!inverse) {
  2092. cm.getColumn(i).setWidth(s);
  2093. }
  2094. else {
  2095. cm.getColumn(i).setPreferredWidth(s);
  2096. }
  2097. }
  2098. };
  2099. adjustSizes(target, r, inverse);
  2100. }
  2101. // Distribute delta over columns, as indicated by the autoresize mode.
  2102. private void accommodateDelta(int resizingColumnIndex, int delta) {
  2103. int columnCount = getColumnCount();
  2104. int from = resizingColumnIndex;
  2105. int to = columnCount;
  2106. // Use the mode to determine how to absorb the changes.
  2107. switch(autoResizeMode) {
  2108. case AUTO_RESIZE_NEXT_COLUMN:
  2109. from = from + 1;
  2110. to = Math.min(from + 1, columnCount); break;
  2111. case AUTO_RESIZE_SUBSEQUENT_COLUMNS:
  2112. from = from + 1;
  2113. to = columnCount; break;
  2114. case AUTO_RESIZE_LAST_COLUMN:
  2115. from = columnCount - 1;
  2116. to = from + 1; break;
  2117. case AUTO_RESIZE_ALL_COLUMNS:
  2118. from = 0;
  2119. to = columnCount; break;
  2120. default:
  2121. return;
  2122. }
  2123. final int start = from;
  2124. final int end = to;
  2125. final TableColumnModel cm = columnModel;
  2126. Resizable3 r = new Resizable3() {
  2127. public int getElementCount() { return end-start; }
  2128. public int getLowerBoundAt(int i) { return cm.getColumn(i+start).getMinWidth(); }
  2129. public int getUpperBoundAt(int i) { return cm.getColumn(i+start).getMaxWidth(); }
  2130. public int getMidPointAt(int i) { return cm.getColumn(i+start).getWidth(); }
  2131. public void setSizeAt(int s, int i) { cm.getColumn(i+start).setWidth(s); }
  2132. };
  2133. int totalWidth = 0;
  2134. for(int i = from; i < to; i++) {
  2135. TableColumn aColumn = columnModel.getColumn(i);
  2136. int input = aColumn.getWidth();
  2137. totalWidth = totalWidth + input;
  2138. }
  2139. adjustSizes(totalWidth + delta, r, false);
  2140. setWidthsFromPreferredWidths(true);
  2141. // setWidthsFromPreferredWidths(false);
  2142. return;
  2143. }
  2144. private interface Resizable2 {
  2145. public int getElementCount();
  2146. public int getLowerBoundAt(int i);
  2147. public int getUpperBoundAt(int i);
  2148. public void setSizeAt(int newSize, int i);
  2149. }
  2150. private interface Resizable3 extends Resizable2 {
  2151. public int getMidPointAt(int i);
  2152. }
  2153. private void adjustSizes(long target, final Resizable3 r, boolean inverse) {
  2154. int N = r.getElementCount();
  2155. long totalPreferred = 0;
  2156. for(int i = 0; i < N; i++) {
  2157. totalPreferred += r.getMidPointAt(i);
  2158. }
  2159. Resizable2 s;
  2160. if ((target < totalPreferred) == !inverse) {
  2161. s = new Resizable2() {
  2162. public int getElementCount() { return r.getElementCount(); }
  2163. public int getLowerBoundAt(int i) { return r.getLowerBoundAt(i); }
  2164. public int getUpperBoundAt(int i) { return r.getMidPointAt(i); }
  2165. public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
  2166. };
  2167. }
  2168. else {
  2169. s = new Resizable2() {
  2170. public int getElementCount() { return r.getElementCount(); }
  2171. public int getLowerBoundAt(int i) { return r.getMidPointAt(i); }
  2172. public int getUpperBoundAt(int i) { return r.getUpperBoundAt(i); }
  2173. public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
  2174. };
  2175. }
  2176. adjustSizes(target, s, !inverse);
  2177. }
  2178. private void adjustSizes(long target, Resizable2 r, boolean limitToRange) {
  2179. long totalLowerBound = 0;
  2180. long totalUpperBound = 0;
  2181. for(int i = 0; i < r.getElementCount(); i++) {
  2182. totalLowerBound += r.getLowerBoundAt(i);
  2183. totalUpperBound += r.getUpperBoundAt(i);
  2184. }
  2185. if (limitToRange) {
  2186. target = Math.min(Math.max(totalLowerBound, target), totalUpperBound);
  2187. }
  2188. for(int i = 0; i < r.getElementCount(); i++) {
  2189. int lowerBound = r.getLowerBoundAt(i);
  2190. int upperBound = r.getUpperBoundAt(i);
  2191. // Check for zero. This happens when the distribution of the delta
  2192. // finishes early due to a series of "fixed" entries at the end.
  2193. // In this case, lowerBound == upperBound, for all subsequent terms.
  2194. int newSize;
  2195. if (totalLowerBound == totalUpperBound) {
  2196. newSize = lowerBound;
  2197. }
  2198. else {
  2199. double f = (double)(target - totalLowerBound)/(totalUpperBound - totalLowerBound);
  2200. newSize = (int)Math.round(lowerBound+f*(upperBound - lowerBound));
  2201. // We'd need to round manually in an all integer version.
  2202. // size[i] = (int)(((totalUpperBound - target) * lowerBound +
  2203. // (target - totalLowerBound) * upperBound)/(totalUpperBound-totalLowerBound));
  2204. }
  2205. r.setSizeAt(newSize, i);
  2206. target -= newSize;
  2207. totalLowerBound -= lowerBound;
  2208. totalUpperBound -= upperBound;
  2209. }
  2210. }
  2211. /**
  2212. * Overrides <code>JComponent</code>'s <code>getToolTipText</code>
  2213. * method in order to allow the renderer's tips to be used
  2214. * if it has text set.
  2215. * <p>
  2216. * <bold>Note:</bold> For <code>JTable</code> to properly display
  2217. * tooltips of its renderers
  2218. * <code>JTable</code> must be a registered component with the
  2219. * <code>ToolTipManager</code>.
  2220. * This is done automatically in <code>initializeLocalVars</code>,
  2221. * but if at a later point <code>JTable</code> is told
  2222. * <code>setToolTipText(null)</code> it will unregister the table
  2223. * component, and no tips from renderers will display anymore.
  2224. *
  2225. * @see JComponent#getToolTipText
  2226. */
  2227. public String getToolTipText(MouseEvent event) {
  2228. String tip = null;
  2229. Point p = event.getPoint();
  2230. // Locate the renderer under the event location
  2231. int hitColumnIndex = columnAtPoint(p);
  2232. int hitRowIndex = rowAtPoint(p);
  2233. if ((hitColumnIndex != -1) && (hitRowIndex != -1)) {
  2234. TableCellRenderer renderer = getCellRenderer(hitRowIndex, hitColumnIndex);
  2235. Component component = prepareRenderer(renderer, hitRowIndex, hitColumnIndex);
  2236. // Now have to see if the component is a JComponent before
  2237. // getting the tip
  2238. if (component instanceof JComponent) {
  2239. // Convert the event to the renderer's coordinate system
  2240. Rectangle cellRect = getCellRect(hitRowIndex, hitColumnIndex, false);
  2241. p.translate(-cellRect.x, -cellRect.y);
  2242. MouseEvent newEvent = new MouseEvent(component, event.getID(),
  2243. event.getWhen(), event.getModifiers(),
  2244. p.x, p.y, event.getClickCount(),
  2245. event.isPopupTrigger());
  2246. tip = ((JComponent)component).getToolTipText(newEvent);
  2247. }
  2248. }
  2249. // No tip from the renderer get our own tip
  2250. if (tip == null)
  2251. tip = getToolTipText();
  2252. return tip;
  2253. }
  2254. //
  2255. // Editing Support
  2256. //
  2257. /**
  2258. * Sets whether editors in this JTable get the keyboard focus
  2259. * when an editor is activated as a result of the JTable
  2260. * forwarding keyboard events for a cell.
  2261. * By default, this property is false, and the JTable
  2262. * retains the focus unless the cell is clicked.
  2263. *
  2264. * @param surrendersFocusOnKeystroke true if the editor should get the focus
  2265. * when keystrokes cause the editor to be
  2266. * activated
  2267. *
  2268. *
  2269. * @see #getSurrendersFocusOnKeystroke
  2270. */
  2271. public void setSurrendersFocusOnKeystroke(boolean surrendersFocusOnKeystroke) {
  2272. this.surrendersFocusOnKeystroke = surrendersFocusOnKeystroke;
  2273. }
  2274. /**
  2275. * Returns true if the editor should get the focus
  2276. * when keystrokes cause the editor to be activated
  2277. *
  2278. * @return true if the editor should get the focus
  2279. * when keystrokes cause the editor to be
  2280. * activated
  2281. *
  2282. * @see #setSurrendersFocusOnKeystroke
  2283. */
  2284. public boolean getSurrendersFocusOnKeystroke() {
  2285. return surrendersFocusOnKeystroke;
  2286. }
  2287. /**
  2288. * Programmatically starts editing the cell at <code>row</code> and
  2289. * <code>column</code>, if the cell is editable. Note that this is
  2290. * a convenience method for <code>editCellAt(int, int, null)</code>.
  2291. *
  2292. * @param row the row to be edited
  2293. * @param column the column to be edited
  2294. * @exception IllegalArgumentException if <code>row</code> or
  2295. * <code>column</code>
  2296. * is not in the valid range
  2297. * @return false if for any reason the cell cannot be edited
  2298. */
  2299. public boolean editCellAt(int row, int column) {
  2300. return editCellAt(row, column, null);
  2301. }
  2302. /**
  2303. * Programmatically starts editing the cell at <code>row</code> and
  2304. * <code>column</code>, if the cell is editable.
  2305. * To prevent the <code>JTable</code> from editing a particular table,
  2306. * column or cell value, return false from the <code>isCellEditable</code>
  2307. * method in the <code>TableModel</code> interface.
  2308. *
  2309. * @param row the row to be edited
  2310. * @param column the column to be edited
  2311. * @param e event to pass into <code>shouldSelectCell</code>
  2312. * note that as of Java 2 platform v1.2, the call to
  2313. * <code>shouldSelectCell</code> is no longer made
  2314. * @exception IllegalArgumentException if <code>row</code> or
  2315. * <code>column</code>
  2316. * is not in the valid range
  2317. * @return false if for any reason the cell cannot be edited
  2318. */
  2319. public boolean editCellAt(int row, int column, EventObject e){
  2320. if (cellEditor != null && !cellEditor.stopCellEditing()) {
  2321. return false;
  2322. }
  2323. if (row < 0 || row >= getRowCount() ||
  2324. column < 0 || column >= getColumnCount()) {
  2325. return false;
  2326. }
  2327. if (!isCellEditable(row, column))
  2328. return false;
  2329. if (editorRemover == null) {
  2330. KeyboardFocusManager fm =
  2331. KeyboardFocusManager.getCurrentKeyboardFocusManager();
  2332. editorRemover = new CellEditorRemover(fm);
  2333. fm.addPropertyChangeListener("permanentFocusOwner", editorRemover);
  2334. }
  2335. TableCellEditor editor = getCellEditor(row, column);
  2336. if (editor != null && editor.isCellEditable(e)) {
  2337. editorComp = prepareEditor(editor, row, column);
  2338. if (editorComp == null) {
  2339. removeEditor();
  2340. return false;
  2341. }
  2342. editorComp.setBounds(getCellRect(row, column, false));
  2343. add(editorComp);
  2344. editorComp.validate();
  2345. setCellEditor(editor);
  2346. setEditingRow(row);
  2347. setEditingColumn(column);
  2348. editor.addCellEditorListener(this);
  2349. return true;
  2350. }
  2351. return false;
  2352. }
  2353. /**
  2354. * Returns true if a cell is being edited.
  2355. *
  2356. * @return true if the table is editing a cell
  2357. * @see #editingColumn
  2358. * @see #editingRow
  2359. */
  2360. public boolean isEditing() {
  2361. return (cellEditor == null)? false : true;
  2362. }
  2363. /**
  2364. * Returns the component that is handling the editing session.
  2365. * If nothing is being edited, returns null.
  2366. *
  2367. * @return Component handling editing session
  2368. */
  2369. public Component getEditorComponent() {
  2370. return editorComp;
  2371. }
  2372. /**
  2373. * Returns the index of the column that contains the cell currently
  2374. * being edited. If nothing is being edited, returns -1.
  2375. *
  2376. * @return the index of the column that contains the cell currently
  2377. * being edited; returns -1 if nothing being edited
  2378. * @see #editingRow
  2379. */
  2380. public int getEditingColumn() {
  2381. return editingColumn;
  2382. }
  2383. /**
  2384. * Returns the index of the row that contains the cell currently
  2385. * being edited. If nothing is being edited, returns -1.
  2386. *
  2387. * @return the index of the row that contains the cell currently
  2388. * being edited; returns -1 if nothing being edited
  2389. * @see #editingColumn
  2390. */
  2391. public int getEditingRow() {
  2392. return editingRow;
  2393. }
  2394. //
  2395. // Managing TableUI
  2396. //
  2397. /**
  2398. * Returns the L&F object that renders this component.
  2399. *
  2400. * @return the <code>TableUI</code> object that renders this component
  2401. */
  2402. public TableUI getUI() {
  2403. return (TableUI)ui;
  2404. }
  2405. /**
  2406. * Sets the L&F object that renders this component and repaints.
  2407. *
  2408. * @param ui the TableUI L&F object
  2409. * @see UIDefaults#getUI
  2410. * @beaninfo
  2411. * bound: true
  2412. * hidden: true
  2413. * attribute: visualUpdate true
  2414. * description: The UI object that implements the Component's LookAndFeel.
  2415. */
  2416. public void setUI(TableUI ui) {
  2417. if (this.ui != ui) {
  2418. super.setUI(ui);
  2419. repaint();
  2420. }
  2421. }
  2422. private void updateSubComponentUI(Object componentShell) {
  2423. if (componentShell == null) {
  2424. return;
  2425. }
  2426. Component component = null;
  2427. if (componentShell instanceof Component) {
  2428. component = (Component)componentShell;
  2429. }
  2430. if (componentShell instanceof DefaultCellEditor) {
  2431. component = ((DefaultCellEditor)componentShell).getComponent();
  2432. }
  2433. if (component != null && component instanceof JComponent) {
  2434. ((JComponent)component).updateUI();
  2435. }
  2436. }
  2437. /**
  2438. * Notification from the <code>UIManager</code> that the L&F has changed.
  2439. * Replaces the current UI object with the latest version from the
  2440. * <code>UIManager</code>.
  2441. *
  2442. * @see JComponent#updateUI
  2443. */
  2444. public void updateUI() {
  2445. // Update the UIs of the cell renderers, cell editors and header renderers.
  2446. TableColumnModel cm = getColumnModel();
  2447. for(int column = 0; column < cm.getColumnCount(); column++) {
  2448. TableColumn aColumn = cm.getColumn(column);
  2449. updateSubComponentUI(aColumn.getCellRenderer());
  2450. updateSubComponentUI(aColumn.getCellEditor());
  2451. updateSubComponentUI(aColumn.getHeaderRenderer());
  2452. }
  2453. // Update the UIs of all the default renderers.
  2454. Enumeration defaultRenderers = defaultRenderersByColumnClass.elements();
  2455. while (defaultRenderers.hasMoreElements()) {
  2456. updateSubComponentUI(defaultRenderers.nextElement());
  2457. }
  2458. // Update the UIs of all the default editors.
  2459. Enumeration defaultEditors = defaultEditorsByColumnClass.elements();
  2460. while (defaultEditors.hasMoreElements()) {
  2461. updateSubComponentUI(defaultEditors.nextElement());
  2462. }
  2463. setUI((TableUI)UIManager.getUI(this));
  2464. resizeAndRepaint();
  2465. }
  2466. /**
  2467. * Returns the suffix used to construct the name of the L&F class used to
  2468. * render this component.
  2469. *
  2470. * @return the string "TableUI"
  2471. * @see JComponent#getUIClassID
  2472. * @see UIDefaults#getUI
  2473. */
  2474. public String getUIClassID() {
  2475. return uiClassID;
  2476. }
  2477. //
  2478. // Managing models
  2479. //
  2480. /**
  2481. * Sets the data model for this table to <code>newModel</code> and registers
  2482. * with it for listener notifications from the new data model.
  2483. *
  2484. * @param dataModel the new data source for this table
  2485. * @exception IllegalArgumentException if <code>newModel</code> is <code>null</code>
  2486. * @see #getModel
  2487. * @beaninfo
  2488. * bound: true
  2489. * description: The model that is the source of the data for this view.
  2490. */
  2491. public void setModel(TableModel dataModel) {
  2492. if (dataModel == null) {
  2493. throw new IllegalArgumentException("Cannot set a null TableModel");
  2494. }
  2495. if (this.dataModel != dataModel) {
  2496. TableModel old = this.dataModel;
  2497. if (old != null) {
  2498. old.removeTableModelListener(this);
  2499. }
  2500. this.dataModel = dataModel;
  2501. dataModel.addTableModelListener(this);
  2502. // If this method is called from the JTable constructor,
  2503. // the column model will be null. In this case we can't use
  2504. // the usual methods to update the internal state. In all other
  2505. // cases, use the usual tableChanged() method to reconfigure
  2506. // the JTable for the new model.
  2507. if (getColumnModel() != null) {
  2508. tableChanged(new TableModelEvent(dataModel, TableModelEvent.HEADER_ROW));
  2509. }
  2510. firePropertyChange("model", old, dataModel);
  2511. }
  2512. }
  2513. /**
  2514. * Returns the <code>TableModel</code> that provides the data displayed by this
  2515. * <code>JTable</code>.
  2516. *
  2517. * @return the <code>TableModel</code> that provides the data displayed by this <code>JTable</code>
  2518. * @see #setModel
  2519. */
  2520. public TableModel getModel() {
  2521. return dataModel;
  2522. }
  2523. /**
  2524. * Sets the column model for this table to <code>newModel</code> and registers
  2525. * for listener notifications from the new column model. Also sets
  2526. * the column model of the <code>JTableHeader</code> to <code>columnModel</code>.
  2527. *
  2528. * @param columnModel the new data source for this table
  2529. * @exception IllegalArgumentException if <code>columnModel</code> is <code>null</code>
  2530. * @see #getColumnModel
  2531. * @beaninfo
  2532. * bound: true
  2533. * description: The object governing the way columns appear in the view.
  2534. */
  2535. public void setColumnModel(TableColumnModel columnModel) {
  2536. if (columnModel == null) {
  2537. throw new IllegalArgumentException("Cannot set a null ColumnModel");
  2538. }
  2539. TableColumnModel old = this.columnModel;
  2540. if (columnModel != old) {
  2541. if (old != null) {
  2542. old.removeColumnModelListener(this);
  2543. }
  2544. this.columnModel = columnModel;
  2545. columnModel.addColumnModelListener(this);
  2546. // Set the column model of the header as well.
  2547. if (tableHeader != null) {
  2548. tableHeader.setColumnModel(columnModel);
  2549. }
  2550. firePropertyChange("columnModel", old, columnModel);
  2551. resizeAndRepaint();
  2552. }
  2553. }
  2554. /**
  2555. * Returns the <code>TableColumnModel</code> that contains all column information
  2556. * of this table.
  2557. *
  2558. * @return the object that provides the column state of the table
  2559. * @see #setColumnModel
  2560. */
  2561. public TableColumnModel getColumnModel() {
  2562. return columnModel;
  2563. }
  2564. /**
  2565. * Sets the row selection model for this table to <code>newModel</code>
  2566. * and registers for listener notifications from the new selection model.
  2567. *
  2568. * @param newModel the new selection model
  2569. * @exception IllegalArgumentException if <code>newModel</code> is <code>null</code>
  2570. * @see #getSelectionModel
  2571. * @beaninfo
  2572. * bound: true
  2573. * description: The selection model for rows.
  2574. */
  2575. public void setSelectionModel(ListSelectionModel newModel) {
  2576. if (newModel == null) {
  2577. throw new IllegalArgumentException("Cannot set a null SelectionModel");
  2578. }
  2579. ListSelectionModel oldModel = selectionModel;
  2580. if (newModel != oldModel) {
  2581. if (oldModel != null) {
  2582. oldModel.removeListSelectionListener(this);
  2583. }
  2584. selectionModel = newModel;
  2585. if (newModel != null) {
  2586. newModel.addListSelectionListener(this);
  2587. }
  2588. firePropertyChange("selectionModel", oldModel, newModel);
  2589. repaint();
  2590. }
  2591. }
  2592. /**
  2593. * Returns the <code>ListSelectionModel</code> that is used to maintain row
  2594. * selection state.
  2595. *
  2596. * @return the object that provides row selection state, <code>null</code>
  2597. * if row selection is not allowed
  2598. * @see #setSelectionModel
  2599. */
  2600. public ListSelectionModel getSelectionModel() {
  2601. return selectionModel;
  2602. }
  2603. //
  2604. // Implementing TableModelListener interface
  2605. //
  2606. /**
  2607. * Invoked when this table's <code>TableModel</code> generates
  2608. * a <code>TableModelEvent</code>.
  2609. * The <code>TableModelEvent</code> should be constructed in the
  2610. * coordinate system of the model; the appropriate mapping to the
  2611. * view coordinate system is performed by this <code>JTable</code>
  2612. * when it receives the event.
  2613. * <p>
  2614. * Application code will not use these methods explicitly, they
  2615. * are used internally by <code>JTable</code>.
  2616. * <p>
  2617. * Note that as of 1.3, this method clears the selection, if any.
  2618. */
  2619. public void tableChanged(TableModelEvent e) {
  2620. if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
  2621. // The whole thing changed
  2622. clearSelection();
  2623. rowModel = null;
  2624. if (getAutoCreateColumnsFromModel()) {
  2625. // This will effect invalidation of the JTable and JTableHeader.
  2626. createDefaultColumnsFromModel();
  2627. return;
  2628. }
  2629. resizeAndRepaint();
  2630. return;
  2631. }
  2632. // The totalRowHeight calculated below will be incorrect if
  2633. // there are variable height rows. Repaint the visible region,
  2634. // but don't return as a revalidate may be necessary as well.
  2635. if (rowModel != null) {
  2636. repaint();
  2637. }
  2638. if (e.getType() == TableModelEvent.INSERT) {
  2639. tableRowsInserted(e);
  2640. return;
  2641. }
  2642. if (e.getType() == TableModelEvent.DELETE) {
  2643. tableRowsDeleted(e);
  2644. return;
  2645. }
  2646. int modelColumn = e.getColumn();
  2647. int start = e.getFirstRow();
  2648. int end = e.getLastRow();
  2649. Rectangle dirtyRegion;
  2650. if (modelColumn == TableModelEvent.ALL_COLUMNS) {
  2651. // 1 or more rows changed
  2652. dirtyRegion = new Rectangle(0, start * getRowHeight(),
  2653. getColumnModel().getTotalColumnWidth(), 0);
  2654. }
  2655. else {
  2656. // A cell or column of cells has changed.
  2657. // Unlike the rest of the methods in the JTable, the TableModelEvent
  2658. // uses the coordinate system of the model instead of the view.
  2659. // This is the only place in the JTable where this "reverse mapping"
  2660. // is used.
  2661. int column = convertColumnIndexToView(modelColumn);
  2662. dirtyRegion = getCellRect(start, column, false);
  2663. }
  2664. // Now adjust the height of the dirty region according to the value of "end".
  2665. // Check for Integer.MAX_VALUE as this will cause an overflow.
  2666. if (end != Integer.MAX_VALUE) {
  2667. dirtyRegion.height = (end-start+1)*getRowHeight();
  2668. repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
  2669. }
  2670. // In fact, if the end is Integer.MAX_VALUE we need to revalidate anyway
  2671. // because the scrollbar may need repainting.
  2672. else {
  2673. clearSelection();
  2674. resizeAndRepaint();
  2675. rowModel = null;
  2676. }
  2677. }
  2678. /*
  2679. * Invoked when rows have been inserted into the table.
  2680. * <p>
  2681. * Application code will not use these methods explicitly, they
  2682. * are used internally by JTable.
  2683. *
  2684. * @param e the TableModelEvent encapsulating the insertion
  2685. */
  2686. private void tableRowsInserted(TableModelEvent e) {
  2687. int start = e.getFirstRow();
  2688. int end = e.getLastRow();
  2689. if (start < 0) {
  2690. start = 0;
  2691. }
  2692. if (end < 0) {
  2693. end = getRowCount()-1;
  2694. }
  2695. // Adjust the selection to account for the new rows.
  2696. int length = end - start + 1;
  2697. selectionModel.insertIndexInterval(start, length, true);
  2698. // If we have variable height rows, adjust the row model.
  2699. if (rowModel != null) {
  2700. rowModel.insertEntries(start, length, getRowHeight());
  2701. }
  2702. int rh = getRowHeight() ;
  2703. Rectangle drawRect = new Rectangle(0, start * rh,
  2704. getColumnModel().getTotalColumnWidth(),
  2705. (getRowCount()-start) * rh);
  2706. revalidate();
  2707. // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
  2708. // repaint still required in the unusual case where there is no ScrollPane
  2709. repaint(drawRect);
  2710. }
  2711. /*
  2712. * Invoked when rows have been removed from the table.
  2713. * <p>
  2714. * Application code will not use these methods explicitly, they
  2715. * are used internally by JTable.
  2716. *
  2717. * @param e the TableModelEvent encapsulating the deletion
  2718. */
  2719. private void tableRowsDeleted(TableModelEvent e) {
  2720. int start = e.getFirstRow();
  2721. int end = e.getLastRow();
  2722. if (start < 0) {
  2723. start = 0;
  2724. }
  2725. if (end < 0) {
  2726. end = getRowCount()-1;
  2727. }
  2728. int deletedCount = end - start + 1;
  2729. int previousRowCount = getRowCount() + deletedCount;
  2730. // Adjust the selection to account for the new rows
  2731. selectionModel.removeIndexInterval(start, end);
  2732. // If we have variable height rows, adjust the row model.
  2733. if (rowModel != null) {
  2734. rowModel.removeEntries(start, deletedCount);
  2735. }
  2736. int rh = getRowHeight();
  2737. Rectangle drawRect = new Rectangle(0, start * rh,
  2738. getColumnModel().getTotalColumnWidth(),
  2739. (previousRowCount - start) * rh);
  2740. revalidate();
  2741. // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
  2742. // repaint still required in the unusual case where there is no ScrollPane
  2743. repaint(drawRect);
  2744. }
  2745. //
  2746. // Implementing TableColumnModelListener interface
  2747. //
  2748. /**
  2749. * Invoked when a column is added to the table column model.
  2750. * <p>
  2751. * Application code will not use these methods explicitly, they
  2752. * are used internally by JTable.
  2753. *
  2754. * @see TableColumnModelListener
  2755. */
  2756. public void columnAdded(TableColumnModelEvent e) {
  2757. // If I'm currently editing, then I should stop editing
  2758. if (isEditing()) {
  2759. removeEditor();
  2760. }
  2761. resizeAndRepaint();
  2762. }
  2763. /**
  2764. * Invoked when a column is removed from the table column model.
  2765. * <p>
  2766. * Application code will not use these methods explicitly, they
  2767. * are used internally by JTable.
  2768. *
  2769. * @see TableColumnModelListener
  2770. */
  2771. public void columnRemoved(TableColumnModelEvent e) {
  2772. // If I'm currently editing, then I should stop editing
  2773. if (isEditing()) {
  2774. removeEditor();
  2775. }
  2776. resizeAndRepaint();
  2777. }
  2778. /**
  2779. * Invoked when a column is repositioned. If a cell is being
  2780. * edited, then editing is stopped and the cell is redrawn.
  2781. * <p>
  2782. * Application code will not use these methods explicitly, they
  2783. * are used internally by JTable.
  2784. *
  2785. * @param e the event received
  2786. * @see TableColumnModelListener
  2787. */
  2788. public void columnMoved(TableColumnModelEvent e) {
  2789. // If I'm currently editing, then I should stop editing
  2790. if (isEditing()) {
  2791. removeEditor();
  2792. }
  2793. repaint();
  2794. }
  2795. /**
  2796. * Invoked when a column is moved due to a margin change.
  2797. * If a cell is being edited, then editing is stopped and the cell
  2798. * is redrawn.
  2799. * <p>
  2800. * Application code will not use these methods explicitly, they
  2801. * are used internally by JTable.
  2802. *
  2803. * @param e the event received
  2804. * @see TableColumnModelListener
  2805. */
  2806. public void columnMarginChanged(ChangeEvent e) {
  2807. if (isEditing()) {
  2808. removeEditor();
  2809. }
  2810. TableColumn resizingColumn = getResizingColumn();
  2811. // Need to do this here, before the parent's
  2812. // layout manager calls getPreferredSize().
  2813. if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF) {
  2814. resizingColumn.setPreferredWidth(resizingColumn.getWidth());
  2815. }
  2816. resizeAndRepaint();
  2817. }
  2818. private int limit(int i, int a, int b) {
  2819. return Math.min(b, Math.max(i, a));
  2820. }
  2821. /**
  2822. * Invoked when the selection model of the <code>TableColumnModel</code>
  2823. * is changed.
  2824. * <p>
  2825. * Application code will not use these methods explicitly, they
  2826. * are used internally by JTable.
  2827. *
  2828. * @param e the event received
  2829. * @see TableColumnModelListener
  2830. */
  2831. public void columnSelectionChanged(ListSelectionEvent e) {
  2832. boolean isAdjusting = e.getValueIsAdjusting();
  2833. if (columnSelectionAdjusting && !isAdjusting) {
  2834. // The assumption is that when the model is no longer adjusting
  2835. // we will have already gotten all the changes, and therefore
  2836. // don't need to do an additional paint.
  2837. columnSelectionAdjusting = false;
  2838. return;
  2839. }
  2840. columnSelectionAdjusting = isAdjusting;
  2841. // The getCellRect() call will fail unless there is at least one row.
  2842. if (getRowCount() <= 0 || getColumnCount() <= 0) {
  2843. return;
  2844. }
  2845. int firstIndex = limit(e.getFirstIndex(), 0, getColumnCount()-1);
  2846. int lastIndex = limit(e.getLastIndex(), 0, getColumnCount()-1);
  2847. int minRow = 0;
  2848. int maxRow = getRowCount() - 1;
  2849. if (getRowSelectionAllowed()) {
  2850. minRow = selectionModel.getMinSelectionIndex();
  2851. maxRow = selectionModel.getMaxSelectionIndex();
  2852. if (minRow == -1 || maxRow == -1) {
  2853. return;
  2854. }
  2855. }
  2856. Rectangle firstColumnRect = getCellRect(minRow, firstIndex, false);
  2857. Rectangle lastColumnRect = getCellRect(maxRow, lastIndex, false);
  2858. Rectangle dirtyRegion = firstColumnRect.union(lastColumnRect);
  2859. repaint(dirtyRegion);
  2860. }
  2861. //
  2862. // Implementing ListSelectionListener interface
  2863. //
  2864. /**
  2865. * Invoked when the row selection changes -- repaints to show the new
  2866. * selection.
  2867. * <p>
  2868. * Application code will not use these methods explicitly, they
  2869. * are used internally by JTable.
  2870. *
  2871. * @param e the event received
  2872. * @see ListSelectionListener
  2873. */
  2874. public void valueChanged(ListSelectionEvent e) {
  2875. boolean isAdjusting = e.getValueIsAdjusting();
  2876. if (rowSelectionAdjusting && !isAdjusting) {
  2877. // The assumption is that when the model is no longer adjusting
  2878. // we will have already gotten all the changes, and therefore
  2879. // don't need to do an additional paint.
  2880. rowSelectionAdjusting = false;
  2881. return;
  2882. }
  2883. rowSelectionAdjusting = isAdjusting;
  2884. // The getCellRect() calls will fail unless there is at least one column.
  2885. if (getRowCount() <= 0 || getColumnCount() <= 0) {
  2886. return;
  2887. }
  2888. int firstIndex = limit(e.getFirstIndex(), 0, getRowCount()-1);
  2889. int lastIndex = limit(e.getLastIndex(), 0, getRowCount()-1);
  2890. Rectangle firstRowRect = getCellRect(firstIndex, 0, false);
  2891. Rectangle lastRowRect = getCellRect(lastIndex, getColumnCount()-1, false);
  2892. Rectangle dirtyRegion = firstRowRect.union(lastRowRect);
  2893. repaint(dirtyRegion);
  2894. }
  2895. //
  2896. // Implementing the CellEditorListener interface
  2897. //
  2898. /**
  2899. * Invoked when editing is finished. The changes are saved and the
  2900. * editor is discarded.
  2901. * <p>
  2902. * Application code will not use these methods explicitly, they
  2903. * are used internally by JTable.
  2904. *
  2905. * @param e the event received
  2906. * @see CellEditorListener
  2907. */
  2908. public void editingStopped(ChangeEvent e) {
  2909. // Take in the new value
  2910. TableCellEditor editor = getCellEditor();
  2911. if (editor != null) {
  2912. Object value = editor.getCellEditorValue();
  2913. setValueAt(value, editingRow, editingColumn);
  2914. removeEditor();
  2915. }
  2916. }
  2917. /**
  2918. * Invoked when editing is canceled. The editor object is discarded
  2919. * and the cell is rendered once again.
  2920. * <p>
  2921. * Application code will not use these methods explicitly, they
  2922. * are used internally by JTable.
  2923. *
  2924. * @param e the event received
  2925. * @see CellEditorListener
  2926. */
  2927. public void editingCanceled(ChangeEvent e) {
  2928. removeEditor();
  2929. }
  2930. //
  2931. // Implementing the Scrollable interface
  2932. //
  2933. /**
  2934. * Sets the preferred size of the viewport for this table.
  2935. *
  2936. * @param size a <code>Dimension</code> object specifying the <code>preferredSize</code> of a
  2937. * <code>JViewport</code> whose view is this table
  2938. * @see Scrollable#getPreferredScrollableViewportSize
  2939. * @beaninfo
  2940. * description: The preferred size of the viewport.
  2941. */
  2942. public void setPreferredScrollableViewportSize(Dimension size) {
  2943. preferredViewportSize = size;
  2944. }
  2945. /**
  2946. * Returns the preferred size of the viewport for this table.
  2947. *
  2948. * @return a <code>Dimension</code> object containing the <code>preferredSize</code> of the <code>JViewport</code>
  2949. * which displays this table
  2950. * @see Scrollable#getPreferredScrollableViewportSize
  2951. */
  2952. public Dimension getPreferredScrollableViewportSize() {
  2953. return preferredViewportSize;
  2954. }
  2955. /**
  2956. * Returns the scroll increment (in pixels) that completely exposes one new
  2957. * row or column (depending on the orientation).
  2958. * <p>
  2959. * This method is called each time the user requests a unit scroll.
  2960. *
  2961. * @param visibleRect the view area visible within the viewport
  2962. * @param orientation either <code>SwingConstants.VERTICAL</code>
  2963. * or <code>SwingConstants.HORIZONTAL</code>
  2964. * @param direction less than zero to scroll up/left,
  2965. * greater than zero for down/right
  2966. * @return the "unit" increment for scrolling in the specified direction
  2967. * @see Scrollable#getScrollableUnitIncrement
  2968. */
  2969. public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
  2970. int direction) {
  2971. // PENDING(alan): do something smarter
  2972. if (orientation == SwingConstants.HORIZONTAL) {
  2973. return 100;
  2974. }
  2975. return getRowHeight();
  2976. }
  2977. /**
  2978. * Returns <code>visibleRect.height</code> or
  2979. * <code>visibleRect.width</code>,
  2980. * depending on this table's orientation. Note that as of Swing 1.1.1
  2981. * (Java 2 v 1.2.2) the value
  2982. * returned will ensure that the viewport is cleanly aligned on
  2983. * a row boundary.
  2984. *
  2985. * @return <code>visibleRect.height</code> or
  2986. * <code>visibleRect.width</code>
  2987. * per the orientation
  2988. * @see Scrollable#getScrollableBlockIncrement
  2989. */
  2990. public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation,
  2991. int direction) {
  2992. if (orientation == SwingConstants.VERTICAL) {
  2993. int rh = getRowHeight();
  2994. return (rh > 0) ? Math.max(rh, (visibleRect.height / rh) * rh) : visibleRect.height;
  2995. }
  2996. else {
  2997. return visibleRect.width;
  2998. }
  2999. }
  3000. /**
  3001. * Returns false if <code>autoResizeMode</code> is set to
  3002. * <code>AUTO_RESIZE_OFF</code>, which indicates that the
  3003. * width of the viewport does not determine the width
  3004. * of the table. Otherwise returns true.
  3005. *
  3006. * @return false if <code>autoResizeMode</code> is set
  3007. * to <code>AUTO_RESIZE_OFF</code>, otherwise returns true
  3008. * @see Scrollable#getScrollableTracksViewportWidth
  3009. */
  3010. public boolean getScrollableTracksViewportWidth() {
  3011. return !(autoResizeMode == AUTO_RESIZE_OFF);
  3012. }
  3013. /**
  3014. * Returns false to indicate that the height of the viewport does not
  3015. * determine the height of the table.
  3016. *
  3017. * @return false
  3018. * @see Scrollable#getScrollableTracksViewportHeight
  3019. */
  3020. public boolean getScrollableTracksViewportHeight() {
  3021. return false;
  3022. }
  3023. //
  3024. // Protected Methods
  3025. //
  3026. protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
  3027. int condition, boolean pressed) {
  3028. boolean retValue = super.processKeyBinding(ks, e, condition, pressed);
  3029. // Start editing when a key is typed. UI classes can disable this behavior
  3030. // by setting the client property JTable.autoStartsEdit to Boolean.FALSE.
  3031. if (!retValue && condition == WHEN_ANCESTOR_OF_FOCUSED_COMPONENT &&
  3032. isFocusOwner() &&
  3033. !Boolean.FALSE.equals((Boolean)getClientProperty("JTable.autoStartsEdit"))) {
  3034. // We do not have a binding for the event.
  3035. Component editorComponent = getEditorComponent();
  3036. if (editorComponent == null) {
  3037. // Only attempt to install the editor on a KEY_PRESSED,
  3038. if (e == null || e.getID() != KeyEvent.KEY_PRESSED) {
  3039. return false;
  3040. }
  3041. // Don't start when just a modifier is pressed
  3042. int code = e.getKeyCode();
  3043. if (code == KeyEvent.VK_SHIFT || code == KeyEvent.VK_CONTROL ||
  3044. code == KeyEvent.VK_ALT) {
  3045. return false;
  3046. }
  3047. // Try to install the editor
  3048. int anchorRow = getSelectionModel().getAnchorSelectionIndex();
  3049. int anchorColumn = getColumnModel().getSelectionModel().
  3050. getAnchorSelectionIndex();
  3051. if (anchorRow != -1 && anchorColumn != -1 && !isEditing()) {
  3052. if (!editCellAt(anchorRow, anchorColumn)) {
  3053. return false;
  3054. }
  3055. }
  3056. editorComponent = getEditorComponent();
  3057. if (editorComponent == null) {
  3058. return false;
  3059. }
  3060. }
  3061. // If the editorComponent is a JComponent, pass the event to it.
  3062. if (editorComponent instanceof JComponent) {
  3063. retValue = ((JComponent)editorComponent).processKeyBinding
  3064. (ks, e, WHEN_FOCUSED, pressed);
  3065. // If we have started an editor as a result of the user
  3066. // pressing a key and the surrendersFocusOnKeystroke property
  3067. // is true, give the focus to the new editor.
  3068. if (getSurrendersFocusOnKeystroke()) {
  3069. editorComponent.requestFocus();
  3070. }
  3071. }
  3072. }
  3073. return retValue;
  3074. }
  3075. private void setLazyValue(Hashtable h, Class c, String s) {
  3076. h.put(c, new UIDefaults.ProxyLazyValue(s));
  3077. }
  3078. private void setLazyRenderer(Class c, String s) {
  3079. setLazyValue(defaultRenderersByColumnClass, c, s);
  3080. }
  3081. /**
  3082. * Creates default cell renderers for objects, numbers, doubles, dates,
  3083. * booleans, and icons.
  3084. * @see javax.swing.table.DefaultTableCellRenderer
  3085. *
  3086. */
  3087. protected void createDefaultRenderers() {
  3088. defaultRenderersByColumnClass = new UIDefaults();
  3089. // Objects
  3090. setLazyRenderer(Object.class, "javax.swing.table.DefaultTableCellRenderer");
  3091. // Numbers
  3092. setLazyRenderer(Number.class, "javax.swing.JTable$NumberRenderer");
  3093. // Doubles and Floats
  3094. setLazyRenderer(Float.class, "javax.swing.JTable$DoubleRenderer");
  3095. setLazyRenderer(Double.class, "javax.swing.JTable$DoubleRenderer");
  3096. // Dates
  3097. setLazyRenderer(Date.class, "javax.swing.JTable$DateRenderer");
  3098. // Icons and ImageIcons
  3099. setLazyRenderer(Icon.class, "javax.swing.JTable$IconRenderer");
  3100. setLazyRenderer(ImageIcon.class, "javax.swing.JTable$IconRenderer");
  3101. // Booleans
  3102. setLazyRenderer(Boolean.class, "javax.swing.JTable$BooleanRenderer");
  3103. }
  3104. /**
  3105. * Default Renderers
  3106. **/
  3107. static class NumberRenderer extends DefaultTableCellRenderer {
  3108. public NumberRenderer() {
  3109. super();
  3110. setHorizontalAlignment(JLabel.RIGHT);
  3111. }
  3112. }
  3113. static class DoubleRenderer extends NumberRenderer {
  3114. NumberFormat formatter;
  3115. public DoubleRenderer() { super(); }
  3116. public void setValue(Object value) {
  3117. if (formatter == null) {
  3118. formatter = NumberFormat.getInstance();
  3119. }
  3120. setText((value == null) ? "" : formatter.format(value));
  3121. }
  3122. }
  3123. static class DateRenderer extends DefaultTableCellRenderer {
  3124. DateFormat formatter;
  3125. public DateRenderer() { super(); }
  3126. public void setValue(Object value) {
  3127. if (formatter==null) {
  3128. formatter = DateFormat.getDateInstance();
  3129. }
  3130. setText((value == null) ? "" : formatter.format(value));
  3131. }
  3132. }
  3133. static class IconRenderer extends DefaultTableCellRenderer {
  3134. public IconRenderer() {
  3135. super();
  3136. setHorizontalAlignment(JLabel.CENTER);
  3137. }
  3138. public void setValue(Object value) { setIcon((value instanceof Icon) ? (Icon)value : null); }
  3139. }
  3140. static class BooleanRenderer extends JCheckBox implements TableCellRenderer
  3141. {
  3142. public BooleanRenderer() {
  3143. super();
  3144. setHorizontalAlignment(JLabel.CENTER);
  3145. }
  3146. public Component getTableCellRendererComponent(JTable table, Object value,
  3147. boolean isSelected, boolean hasFocus, int row, int column) {
  3148. if (isSelected) {
  3149. setForeground(table.getSelectionForeground());
  3150. super.setBackground(table.getSelectionBackground());
  3151. }
  3152. else {
  3153. setForeground(table.getForeground());
  3154. setBackground(table.getBackground());
  3155. }
  3156. setSelected((value != null && ((Boolean)value).booleanValue()));
  3157. return this;
  3158. }
  3159. }
  3160. private void setLazyEditor(Class c, String s) {
  3161. setLazyValue(defaultEditorsByColumnClass, c, s);
  3162. }
  3163. /**
  3164. * Creates default cell editors for objects, numbers, and boolean values.
  3165. * @see DefaultCellEditor
  3166. */
  3167. protected void createDefaultEditors() {
  3168. defaultEditorsByColumnClass = new UIDefaults();
  3169. // Objects
  3170. setLazyEditor(Object.class, "javax.swing.JTable$GenericEditor");
  3171. // Numbers
  3172. setLazyEditor(Number.class, "javax.swing.JTable$NumberEditor");
  3173. // Booleans
  3174. setLazyEditor(Boolean.class, "javax.swing.JTable$BooleanEditor");
  3175. }
  3176. /**
  3177. * Default Editors
  3178. */
  3179. static class GenericEditor extends DefaultCellEditor {
  3180. Class[] argTypes = new Class[]{String.class};
  3181. java.lang.reflect.Constructor constructor;
  3182. Object value;
  3183. public GenericEditor() { super(new JTextField()); }
  3184. public boolean stopCellEditing() {
  3185. String s = (String)super.getCellEditorValue();
  3186. // Here we are dealing with the case where a user
  3187. // has deleted the string value in a cell, possibly
  3188. // after a failed validation. Return null, so that
  3189. // they have the option to replace the value with
  3190. // null or use escape to restore the original.
  3191. // For Strings, return "" for backward compatibility.
  3192. if ("".equals(s)) {
  3193. if (constructor.getDeclaringClass() == String.class) {
  3194. value = s;
  3195. }
  3196. super.stopCellEditing();
  3197. }
  3198. try {
  3199. value = constructor.newInstance(new Object[]{s});
  3200. }
  3201. catch (Exception e) {
  3202. ((JComponent)getComponent()).setBorder(new LineBorder(Color.red));
  3203. return false;
  3204. }
  3205. return super.stopCellEditing();
  3206. }
  3207. public Component getTableCellEditorComponent(JTable table, Object value,
  3208. boolean isSelected,
  3209. int row, int column) {
  3210. this.value = null;
  3211. ((JComponent)getComponent()).setBorder(new LineBorder(Color.black));
  3212. try {
  3213. Class type = table.getColumnClass(column);
  3214. // Since our obligation is to produce a value which is
  3215. // assignable for the required type it is OK to use the
  3216. // String constructor for columns which are declared
  3217. // to contain Objects. A String is an Object.
  3218. if (type == Object.class) {
  3219. type = String.class;
  3220. }
  3221. constructor = type.getConstructor(argTypes);
  3222. }
  3223. catch (Exception e) {
  3224. return null;
  3225. }
  3226. return super.getTableCellEditorComponent(table, value, isSelected, row, column);
  3227. }
  3228. public Object getCellEditorValue() {
  3229. return value;
  3230. }
  3231. }
  3232. static class NumberEditor extends GenericEditor {
  3233. public NumberEditor() {
  3234. ((JTextField)getComponent()).setHorizontalAlignment(JTextField.RIGHT);
  3235. }
  3236. }
  3237. static class BooleanEditor extends DefaultCellEditor {
  3238. public BooleanEditor() {
  3239. super(new JCheckBox());
  3240. JCheckBox checkBox = (JCheckBox)getComponent();
  3241. checkBox.setHorizontalAlignment(JCheckBox.CENTER);
  3242. }
  3243. }
  3244. /**
  3245. * Initializes table properties to their default values.
  3246. */
  3247. protected void initializeLocalVars() {
  3248. getSelectionModel().setAnchorSelectionIndex(0);
  3249. setOpaque(true);
  3250. createDefaultRenderers();
  3251. createDefaultEditors();
  3252. setTableHeader(createDefaultTableHeader());
  3253. setShowGrid(true);
  3254. setAutoResizeMode(AUTO_RESIZE_SUBSEQUENT_COLUMNS);
  3255. setRowHeight(16);
  3256. setRowMargin(1);
  3257. setRowSelectionAllowed(true);
  3258. setCellEditor(null);
  3259. setEditingColumn(-1);
  3260. setEditingRow(-1);
  3261. setSurrendersFocusOnKeystroke(false);
  3262. setPreferredScrollableViewportSize(new Dimension(450, 400));
  3263. // I'm registered to do tool tips so we can draw tips for the renderers
  3264. ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
  3265. toolTipManager.registerComponent(this);
  3266. setAutoscrolls(true);
  3267. }
  3268. /**
  3269. * Returns the default table model object, which is
  3270. * a <code>DefaultTableModel</code>. A subclass can override this
  3271. * method to return a different table model object.
  3272. *
  3273. * @return the default table model object
  3274. * @see javax.swing.table.DefaultTableModel
  3275. */
  3276. protected TableModel createDefaultDataModel() {
  3277. return new DefaultTableModel();
  3278. }
  3279. /**
  3280. * Returns the default column model object, which is
  3281. * a <code>DefaultTableColumnModel</code>. A subclass can override this
  3282. * method to return a different column model object.
  3283. *
  3284. * @return the default column model object
  3285. * @see javax.swing.table.DefaultTableColumnModel
  3286. */
  3287. protected TableColumnModel createDefaultColumnModel() {
  3288. return new DefaultTableColumnModel();
  3289. }
  3290. /**
  3291. * Returns the default selection model object, which is
  3292. * a <code>DefaultListSelectionModel</code>. A subclass can override this
  3293. * method to return a different selection model object.
  3294. *
  3295. * @return the default selection model object
  3296. * @see javax.swing.DefaultListSelectionModel
  3297. */
  3298. protected ListSelectionModel createDefaultSelectionModel() {
  3299. return new DefaultListSelectionModel();
  3300. }
  3301. /**
  3302. * Returns the default table header object, which is
  3303. * a <code>JTableHeader</code>. A subclass can override this
  3304. * method to return a different table header object.
  3305. *
  3306. * @return the default table header object
  3307. * @see javax.swing.table.JTableHeader
  3308. */
  3309. protected JTableHeader createDefaultTableHeader() {
  3310. return new JTableHeader(columnModel);
  3311. }
  3312. /**
  3313. * Equivalent to <code>revalidate</code> followed by <code>repaint</code>.
  3314. */
  3315. protected void resizeAndRepaint() {
  3316. revalidate();
  3317. repaint();
  3318. }
  3319. /**
  3320. * Returns the cell editor.
  3321. *
  3322. * @return the <code>TableCellEditor</code> that does the editing
  3323. * @see #cellEditor
  3324. */
  3325. public TableCellEditor getCellEditor() {
  3326. return cellEditor;
  3327. }
  3328. /**
  3329. * Sets the <code>cellEditor</code> variable.
  3330. *
  3331. * @param anEditor the TableCellEditor that does the editing
  3332. * @see #cellEditor
  3333. * @beaninfo
  3334. * bound: true
  3335. * description: The table's active cell editor, if one exists.
  3336. */
  3337. public void setCellEditor(TableCellEditor anEditor) {
  3338. TableCellEditor oldEditor = cellEditor;
  3339. cellEditor = anEditor;
  3340. firePropertyChange("tableCellEditor", oldEditor, anEditor);
  3341. }
  3342. /**
  3343. * Sets the <code>editingColumn</code> variable.
  3344. * @param aColumn the column of the cell to be edited
  3345. *
  3346. * @see #editingColumn
  3347. */
  3348. public void setEditingColumn(int aColumn) {
  3349. editingColumn = aColumn;
  3350. }
  3351. /**
  3352. * Sets the <code>editingRow</code> variable.
  3353. * @param aRow the row of the cell to be edited
  3354. *
  3355. * @see #editingRow
  3356. */
  3357. public void setEditingRow(int aRow) {
  3358. editingRow = aRow;
  3359. }
  3360. /**
  3361. * Returns an appropriate renderer for the cell specified by this row and
  3362. * column. If the <code>TableColumn</code> for this column has a non-null
  3363. * renderer, returns that. If not, finds the class of the data in
  3364. * this column (using <code>getColumnClass</code>)
  3365. * and returns the default renderer for this type of data.
  3366. * <p>
  3367. * <b>Note:</b>
  3368. * Throughout the table package, the internal implementations always
  3369. * use this method to provide renderers so that this default behavior
  3370. * can be safely overridden by a subclass.
  3371. *
  3372. * @param row the row of the cell to render, where 0 is the first row
  3373. * @param column the column of the cell to render,
  3374. * where 0 is the first column
  3375. * @return the assigned renderer; if <code>null</code>
  3376. * returns the default renderer
  3377. * for this type of object
  3378. * @see javax.swing.table.DefaultTableCellRenderer
  3379. * @see javax.swing.table.TableColumn#setCellRenderer
  3380. * @see #setDefaultRenderer
  3381. */
  3382. public TableCellRenderer getCellRenderer(int row, int column) {
  3383. TableColumn tableColumn = getColumnModel().getColumn(column);
  3384. TableCellRenderer renderer = tableColumn.getCellRenderer();
  3385. if (renderer == null) {
  3386. renderer = getDefaultRenderer(getColumnClass(column));
  3387. }
  3388. return renderer;
  3389. }
  3390. /**
  3391. * Prepares the renderer by querying the data model for the
  3392. * value and selection state
  3393. * of the cell at <code>row</code>, <code>column</code>.
  3394. * Returns the component (may be a <code>Component</code>
  3395. * or a <code>JComponent</code>) under the event location.
  3396. * <p>
  3397. * <b>Note:</b>
  3398. * Throughout the table package, the internal implementations always
  3399. * use this method to prepare renderers so that this default behavior
  3400. * can be safely overridden by a subclass.
  3401. *
  3402. * @param renderer the <code>TableCellRenderer</code> to prepare
  3403. * @param row the row of the cell to render, where 0 is the first row
  3404. * @param column the column of the cell to render,
  3405. * where 0 is the first column
  3406. * @return the <code>Component</code> under the event location
  3407. */
  3408. public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
  3409. Object value = getValueAt(row, column);
  3410. boolean isSelected = isCellSelected(row, column);
  3411. boolean rowIsAnchor = (selectionModel.getAnchorSelectionIndex() == row);
  3412. boolean colIsAnchor =
  3413. (columnModel.getSelectionModel().getAnchorSelectionIndex() == column);
  3414. boolean hasFocus = (rowIsAnchor && colIsAnchor) && isFocusOwner();
  3415. return renderer.getTableCellRendererComponent(this, value,
  3416. isSelected, hasFocus,
  3417. row, column);
  3418. }
  3419. /**
  3420. * Returns an appropriate editor for the cell specified by
  3421. * <code>row</code> and <code>column</code>. If the
  3422. * <code>TableColumn</code> for this column has a non-null editor,
  3423. * returns that. If not, finds the class of the data in this
  3424. * column (using <code>getColumnClass</code>)
  3425. * and returns the default editor for this type of data.
  3426. * <p>
  3427. * <b>Note:</b>
  3428. * Throughout the table package, the internal implementations always
  3429. * use this method to provide editors so that this default behavior
  3430. * can be safely overridden by a subclass.
  3431. *
  3432. * @param row the row of the cell to edit, where 0 is the first row
  3433. * @param column the column of the cell to edit,
  3434. * where 0 is the first column
  3435. * @return the editor for this cell;
  3436. * if <code>null</code> return the default editor for
  3437. * this type of cell
  3438. * @see DefaultCellEditor
  3439. */
  3440. public TableCellEditor getCellEditor(int row, int column) {
  3441. TableColumn tableColumn = getColumnModel().getColumn(column);
  3442. TableCellEditor editor = tableColumn.getCellEditor();
  3443. if (editor == null) {
  3444. editor = getDefaultEditor(getColumnClass(column));
  3445. }
  3446. return editor;
  3447. }
  3448. /**
  3449. * Prepares the editor by querying the data model for the value and
  3450. * selection state of the cell at <code>row</code>, <code>column</code>.
  3451. * <p>
  3452. * <b>Note:</b>
  3453. * Throughout the table package, the internal implementations always
  3454. * use this method to prepare editors so that this default behavior
  3455. * can be safely overridden by a subclass.
  3456. *
  3457. * @param editor the <code>TableCellEditor</code> to set up
  3458. * @param row the row of the cell to edit,
  3459. * where 0 is the first row
  3460. * @param column the column of the cell to edit,
  3461. * where 0 is the first column
  3462. * @return the <code>Component</code> being edited
  3463. */
  3464. public Component prepareEditor(TableCellEditor editor, int row, int column) {
  3465. Object value = getValueAt(row, column);
  3466. boolean isSelected = isCellSelected(row, column);
  3467. Component comp = editor.getTableCellEditorComponent(this, value, isSelected,
  3468. row, column);
  3469. if (comp instanceof JComponent) {
  3470. JComponent jComp = (JComponent)comp;
  3471. if (jComp.getNextFocusableComponent() == null) {
  3472. jComp.setNextFocusableComponent(this);
  3473. }
  3474. }
  3475. return comp;
  3476. }
  3477. /**
  3478. * Discards the editor object and frees the real estate it used for
  3479. * cell rendering.
  3480. */
  3481. public void removeEditor() {
  3482. KeyboardFocusManager.getCurrentKeyboardFocusManager().
  3483. removePropertyChangeListener("permanentFocusOwner", editorRemover);
  3484. editorRemover = null;
  3485. TableCellEditor editor = getCellEditor();
  3486. if(editor != null) {
  3487. editor.removeCellEditorListener(this);
  3488. if (editorComp != null) {
  3489. remove(editorComp);
  3490. }
  3491. Rectangle cellRect = getCellRect(editingRow, editingColumn, false);
  3492. setCellEditor(null);
  3493. setEditingColumn(-1);
  3494. setEditingRow(-1);
  3495. editorComp = null;
  3496. repaint(cellRect);
  3497. }
  3498. }
  3499. //
  3500. // Serialization
  3501. //
  3502. /**
  3503. * See readObject() and writeObject() in JComponent for more
  3504. * information about serialization in Swing.
  3505. */
  3506. private void writeObject(ObjectOutputStream s) throws IOException {
  3507. s.defaultWriteObject();
  3508. if (getUIClassID().equals(uiClassID)) {
  3509. byte count = JComponent.getWriteObjCounter(this);
  3510. JComponent.setWriteObjCounter(this, --count);
  3511. if (count == 0 && ui != null) {
  3512. ui.installUI(this);
  3513. }
  3514. }
  3515. }
  3516. private void readObject(ObjectInputStream s)
  3517. throws IOException, ClassNotFoundException
  3518. {
  3519. s.defaultReadObject();
  3520. if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  3521. ui.installUI(this);
  3522. }
  3523. createDefaultRenderers();
  3524. createDefaultEditors();
  3525. // If ToolTipText != null, then the tooltip has already been
  3526. // registered by JComponent.readObject() and we don't want
  3527. // to re-register here
  3528. if (getToolTipText() == null) {
  3529. ToolTipManager.sharedInstance().registerComponent(this);
  3530. }
  3531. }
  3532. /* Called from the JComponent's EnableSerializationFocusListener to
  3533. * do any Swing-specific pre-serialization configuration.
  3534. */
  3535. void compWriteObjectNotify() {
  3536. super.compWriteObjectNotify();
  3537. // If ToolTipText != null, then the tooltip has already been
  3538. // unregistered by JComponent.compWriteObjectNotify()
  3539. if (getToolTipText() == null) {
  3540. ToolTipManager.sharedInstance().unregisterComponent(this);
  3541. }
  3542. }
  3543. /**
  3544. * Returns a string representation of this table. This method
  3545. * is intended to be used only for debugging purposes, and the
  3546. * content and format of the returned string may vary between
  3547. * implementations. The returned string may be empty but may not
  3548. * be <code>null</code>.
  3549. *
  3550. * @return a string representation of this table
  3551. */
  3552. protected String paramString() {
  3553. String gridColorString = (gridColor != null ?
  3554. gridColor.toString() : "");
  3555. String showHorizontalLinesString = (showHorizontalLines ?
  3556. "true" : "false");
  3557. String showVerticalLinesString = (showVerticalLines ?
  3558. "true" : "false");
  3559. String autoResizeModeString;
  3560. if (autoResizeMode == AUTO_RESIZE_OFF) {
  3561. autoResizeModeString = "AUTO_RESIZE_OFF";
  3562. } else if (autoResizeMode == AUTO_RESIZE_NEXT_COLUMN) {
  3563. autoResizeModeString = "AUTO_RESIZE_NEXT_COLUMN";
  3564. } else if (autoResizeMode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) {
  3565. autoResizeModeString = "AUTO_RESIZE_SUBSEQUENT_COLUMNS";
  3566. } else if (autoResizeMode == AUTO_RESIZE_LAST_COLUMN) {
  3567. autoResizeModeString = "AUTO_RESIZE_LAST_COLUMN";
  3568. } else if (autoResizeMode == AUTO_RESIZE_ALL_COLUMNS) {
  3569. autoResizeModeString = "AUTO_RESIZE_ALL_COLUMNS";
  3570. } else autoResizeModeString = "";
  3571. String autoCreateColumnsFromModelString = (autoCreateColumnsFromModel ?
  3572. "true" : "false");
  3573. String preferredViewportSizeString = (preferredViewportSize != null ?
  3574. preferredViewportSize.toString()
  3575. : "");
  3576. String rowSelectionAllowedString = (rowSelectionAllowed ?
  3577. "true" : "false");
  3578. String cellSelectionEnabledString = (cellSelectionEnabled ?
  3579. "true" : "false");
  3580. String selectionForegroundString = (selectionForeground != null ?
  3581. selectionForeground.toString() :
  3582. "");
  3583. String selectionBackgroundString = (selectionBackground != null ?
  3584. selectionBackground.toString() :
  3585. "");
  3586. return super.paramString() +
  3587. ",autoCreateColumnsFromModel=" + autoCreateColumnsFromModelString +
  3588. ",autoResizeMode=" + autoResizeModeString +
  3589. ",cellSelectionEnabled=" + cellSelectionEnabledString +
  3590. ",editingColumn=" + editingColumn +
  3591. ",editingRow=" + editingRow +
  3592. ",gridColor=" + gridColorString +
  3593. ",preferredViewportSize=" + preferredViewportSizeString +
  3594. ",rowHeight=" + rowHeight +
  3595. ",rowMargin=" + rowMargin +
  3596. ",rowSelectionAllowed=" + rowSelectionAllowedString +
  3597. ",selectionBackground=" + selectionBackgroundString +
  3598. ",selectionForeground=" + selectionForegroundString +
  3599. ",showHorizontalLines=" + showHorizontalLinesString +
  3600. ",showVerticalLines=" + showVerticalLinesString;
  3601. }
  3602. // This class tracks changes in the keyboard focus state. It is used
  3603. // when the JTable is editing to determine when to cancel the edit.
  3604. // If focus switches to a component outside of the jtable, but in the
  3605. // same window, this will cancel editing.
  3606. class CellEditorRemover implements PropertyChangeListener {
  3607. KeyboardFocusManager focusManager;
  3608. public CellEditorRemover(KeyboardFocusManager fm) {
  3609. this.focusManager = fm;
  3610. }
  3611. public void propertyChange(PropertyChangeEvent ev) {
  3612. if (!isEditing() || getClientProperty("terminateEditOnFocusLost") != Boolean.TRUE) {
  3613. return;
  3614. }
  3615. Component c = focusManager.getPermanentFocusOwner();
  3616. while (c != null) {
  3617. if (c == JTable.this) {
  3618. // focus remains inside the table
  3619. return;
  3620. } else if ((c instanceof Window) ||
  3621. (c instanceof Applet && c.getParent() == null)) {
  3622. if (c == SwingUtilities.getRoot(JTable.this)) {
  3623. if (!getCellEditor().stopCellEditing()) {
  3624. getCellEditor().cancelCellEditing();
  3625. }
  3626. }
  3627. break;
  3628. }
  3629. c = c.getParent();
  3630. }
  3631. }
  3632. }
  3633. /////////////////
  3634. // Accessibility support
  3635. ////////////////
  3636. /**
  3637. * Gets the AccessibleContext associated with this JTable.
  3638. * For tables, the AccessibleContext takes the form of an
  3639. * AccessibleJTable.
  3640. * A new AccessibleJTable instance is created if necessary.
  3641. *
  3642. * @return an AccessibleJTable that serves as the
  3643. * AccessibleContext of this JTable
  3644. */
  3645. public AccessibleContext getAccessibleContext() {
  3646. if (accessibleContext == null) {
  3647. accessibleContext = new AccessibleJTable();
  3648. }
  3649. return accessibleContext;
  3650. }
  3651. //
  3652. // *** should also implement AccessibleSelection?
  3653. // *** and what's up with keyboard navigation/manipulation?
  3654. //
  3655. /**
  3656. * This class implements accessibility support for the
  3657. * <code>JTable</code> class. It provides an implementation of the
  3658. * Java Accessibility API appropriate to table user-interface elements.
  3659. * <p>
  3660. * <strong>Warning:</strong>
  3661. * Serialized objects of this class will not be compatible with
  3662. * future Swing releases. The current serialization support is
  3663. * appropriate for short term storage or RMI between applications running
  3664. * the same version of Swing. As of 1.4, support for long term storage
  3665. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  3666. * has been added to the <code>java.beans</code> package.
  3667. * Please see {@link java.beans.XMLEncoder}.
  3668. */
  3669. protected class AccessibleJTable extends AccessibleJComponent
  3670. implements AccessibleSelection, ListSelectionListener, TableModelListener,
  3671. TableColumnModelListener, CellEditorListener, PropertyChangeListener,
  3672. AccessibleExtendedTable {
  3673. int lastSelectedRow;
  3674. int lastSelectedCol;
  3675. AccessibleJTable() {
  3676. super();
  3677. JTable.this.addPropertyChangeListener(this);
  3678. JTable.this.getSelectionModel().addListSelectionListener(this);
  3679. TableColumnModel tcm = JTable.this.getColumnModel();
  3680. tcm.addColumnModelListener(this);
  3681. tcm.getSelectionModel().addListSelectionListener(this);
  3682. JTable.this.getModel().addTableModelListener(this);
  3683. lastSelectedRow = JTable.this.getSelectedRow();
  3684. lastSelectedCol = JTable.this.getSelectedColumn();
  3685. }
  3686. // Listeners to track model, etc. changes to as to re-place the other
  3687. // listeners
  3688. /**
  3689. * Track changes to selection model, column model, etc. so as to
  3690. * be able to re-place listeners on those in order to pass on
  3691. * information to the Accessibility PropertyChange mechanism
  3692. */
  3693. public void propertyChange(PropertyChangeEvent e) {
  3694. String name = e.getPropertyName();
  3695. Object oldValue = e.getOldValue();
  3696. Object newValue = e.getNewValue();
  3697. // re-set tableModel listeners
  3698. if (name.compareTo("model") == 0) {
  3699. if (oldValue != null && oldValue instanceof TableModel) {
  3700. ((TableModel) oldValue).removeTableModelListener(this);
  3701. }
  3702. if (newValue != null && newValue instanceof TableModel) {
  3703. ((TableModel) newValue).addTableModelListener(this);
  3704. }
  3705. // re-set selectionModel listeners
  3706. } else if (name.compareTo("selectionModel") == 0) {
  3707. Object source = e.getSource();
  3708. if (source == JTable.this) { // row selection model
  3709. if (oldValue != null &&
  3710. oldValue instanceof ListSelectionModel) {
  3711. ((ListSelectionModel) oldValue).removeListSelectionListener(this);
  3712. }
  3713. if (newValue != null &&
  3714. newValue instanceof ListSelectionModel) {
  3715. ((ListSelectionModel) newValue).addListSelectionListener(this);
  3716. }
  3717. } else if (source == JTable.this.getColumnModel()) {
  3718. if (oldValue != null &&
  3719. oldValue instanceof ListSelectionModel) {
  3720. ((ListSelectionModel) oldValue).removeListSelectionListener(this);
  3721. }
  3722. if (newValue != null &&
  3723. newValue instanceof ListSelectionModel) {
  3724. ((ListSelectionModel) newValue).addListSelectionListener(this);
  3725. }
  3726. } else {
  3727. // System.out.println("!!! Bug in source of selectionModel propertyChangeEvent");
  3728. }
  3729. // re-set columnModel listeners
  3730. // and column's selection property listener as well
  3731. } else if (name.compareTo("columnModel") == 0) {
  3732. if (oldValue != null && oldValue instanceof TableColumnModel) {
  3733. TableColumnModel tcm = (TableColumnModel) oldValue;
  3734. tcm.removeColumnModelListener(this);
  3735. tcm.getSelectionModel().removeListSelectionListener(this);
  3736. }
  3737. if (newValue != null && newValue instanceof TableColumnModel) {
  3738. TableColumnModel tcm = (TableColumnModel) newValue;
  3739. tcm.addColumnModelListener(this);
  3740. tcm.getSelectionModel().addListSelectionListener(this);
  3741. }
  3742. // re-se cellEditor listeners
  3743. } else if (name.compareTo("tableCellEditor") == 0) {
  3744. if (oldValue != null && oldValue instanceof TableCellEditor) {
  3745. ((TableCellEditor) oldValue).removeCellEditorListener((CellEditorListener) this);
  3746. }
  3747. if (newValue != null && newValue instanceof TableCellEditor) {
  3748. ((TableCellEditor) newValue).addCellEditorListener((CellEditorListener) this);
  3749. }
  3750. }
  3751. }
  3752. // Listeners to echo changes to the AccessiblePropertyChange mechanism
  3753. /*
  3754. * Describes a change in the accessible table model.
  3755. */
  3756. protected class AccessibleJTableModelChange
  3757. implements AccessibleTableModelChange {
  3758. protected int type;
  3759. protected int firstRow;
  3760. protected int lastRow;
  3761. protected int firstColumn;
  3762. protected int lastColumn;
  3763. protected AccessibleJTableModelChange(int type, int firstRow,
  3764. int lastRow, int firstColumn,
  3765. int lastColumn) {
  3766. this.type = type;
  3767. this.firstRow = firstRow;
  3768. this.lastRow = lastRow;
  3769. this.firstColumn = firstColumn;
  3770. this.lastColumn = lastColumn;
  3771. }
  3772. public int getType() {
  3773. return type;
  3774. }
  3775. public int getFirstRow() {
  3776. return firstRow;
  3777. }
  3778. public int getLastRow() {
  3779. return lastRow;
  3780. }
  3781. public int getFirstColumn() {
  3782. return firstColumn;
  3783. }
  3784. public int getLastColumn() {
  3785. return lastColumn;
  3786. }
  3787. }
  3788. /**
  3789. * Track changes to the table contents
  3790. */
  3791. public void tableChanged(TableModelEvent e) {
  3792. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3793. null, null);
  3794. if (e != null) {
  3795. int firstColumn = e.getColumn();
  3796. int lastColumn = e.getColumn();
  3797. if (firstColumn == TableModelEvent.ALL_COLUMNS) {
  3798. firstColumn = 0;
  3799. lastColumn = getColumnCount() - 1;
  3800. }
  3801. // Fire a property change event indicating the table model
  3802. // has changed.
  3803. AccessibleJTableModelChange change =
  3804. new AccessibleJTableModelChange(e.getType(),
  3805. e.getFirstRow(),
  3806. e.getLastRow(),
  3807. firstColumn,
  3808. lastColumn);
  3809. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  3810. null, change);
  3811. }
  3812. }
  3813. /**
  3814. * Track changes to the table contents (row insertions)
  3815. */
  3816. public void tableRowsInserted(TableModelEvent e) {
  3817. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3818. null, null);
  3819. // Fire a property change event indicating the table model
  3820. // has changed.
  3821. int firstColumn = e.getColumn();
  3822. int lastColumn = e.getColumn();
  3823. if (firstColumn == TableModelEvent.ALL_COLUMNS) {
  3824. firstColumn = 0;
  3825. lastColumn = getColumnCount() - 1;
  3826. }
  3827. AccessibleJTableModelChange change =
  3828. new AccessibleJTableModelChange(e.getType(),
  3829. e.getFirstRow(),
  3830. e.getLastRow(),
  3831. firstColumn,
  3832. lastColumn);
  3833. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  3834. null, change);
  3835. }
  3836. /**
  3837. * Track changes to the table contents (row deletions)
  3838. */
  3839. public void tableRowsDeleted(TableModelEvent e) {
  3840. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3841. null, null);
  3842. // Fire a property change event indicating the table model
  3843. // has changed.
  3844. int firstColumn = e.getColumn();
  3845. int lastColumn = e.getColumn();
  3846. if (firstColumn == TableModelEvent.ALL_COLUMNS) {
  3847. firstColumn = 0;
  3848. lastColumn = getColumnCount() - 1;
  3849. }
  3850. AccessibleJTableModelChange change =
  3851. new AccessibleJTableModelChange(e.getType(),
  3852. e.getFirstRow(),
  3853. e.getLastRow(),
  3854. firstColumn,
  3855. lastColumn);
  3856. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  3857. null, change);
  3858. }
  3859. /**
  3860. * Track changes to the table contents (column insertions)
  3861. */
  3862. public void columnAdded(TableColumnModelEvent e) {
  3863. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3864. null, null);
  3865. // Fire a property change event indicating the table model
  3866. // has changed.
  3867. int type = AccessibleTableModelChange.INSERT;
  3868. AccessibleJTableModelChange change =
  3869. new AccessibleJTableModelChange(type,
  3870. 0,
  3871. 0,
  3872. e.getFromIndex(),
  3873. e.getToIndex());
  3874. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  3875. null, change);
  3876. }
  3877. /**
  3878. * Track changes to the table contents (column deletions)
  3879. */
  3880. public void columnRemoved(TableColumnModelEvent e) {
  3881. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3882. null, null);
  3883. // Fire a property change event indicating the table model
  3884. // has changed.
  3885. int type = AccessibleTableModelChange.DELETE;
  3886. AccessibleJTableModelChange change =
  3887. new AccessibleJTableModelChange(type,
  3888. 0,
  3889. 0,
  3890. e.getFromIndex(),
  3891. e.getToIndex());
  3892. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  3893. null, change);
  3894. }
  3895. /**
  3896. * Track changes of a column repositioning.
  3897. *
  3898. * @see TableColumnModelListener
  3899. */
  3900. public void columnMoved(TableColumnModelEvent e) {
  3901. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3902. null, null);
  3903. // Fire property change events indicating the table model
  3904. // has changed.
  3905. int type = AccessibleTableModelChange.DELETE;
  3906. AccessibleJTableModelChange change =
  3907. new AccessibleJTableModelChange(type,
  3908. 0,
  3909. 0,
  3910. e.getFromIndex(),
  3911. e.getFromIndex());
  3912. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  3913. null, change);
  3914. int type2 = AccessibleTableModelChange.INSERT;
  3915. AccessibleJTableModelChange change2 =
  3916. new AccessibleJTableModelChange(type2,
  3917. 0,
  3918. 0,
  3919. e.getToIndex(),
  3920. e.getToIndex());
  3921. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  3922. null, change2);
  3923. }
  3924. /**
  3925. * Track changes of a column moving due to margin changes.
  3926. *
  3927. * @see TableColumnModelListener
  3928. */
  3929. public void columnMarginChanged(ChangeEvent e) {
  3930. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3931. null, null);
  3932. }
  3933. /**
  3934. * Track that the selection model of the TableColumnModel changed.
  3935. *
  3936. * @see TableColumnModelListener
  3937. */
  3938. public void columnSelectionChanged(ListSelectionEvent e) {
  3939. // we should now re-place our TableColumn listener
  3940. }
  3941. /**
  3942. * Track changes to a cell's contents.
  3943. *
  3944. * Invoked when editing is finished. The changes are saved, the
  3945. * editor object is discarded, and the cell is rendered once again.
  3946. *
  3947. * @see CellEditorListener
  3948. */
  3949. public void editingStopped(ChangeEvent e) {
  3950. // it'd be great if we could figure out which cell, and pass that
  3951. // somehow as a parameter
  3952. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  3953. null, null);
  3954. }
  3955. /**
  3956. * Invoked when editing is canceled. The editor object is discarded
  3957. * and the cell is rendered once again.
  3958. *
  3959. * @see CellEditorListener
  3960. */
  3961. public void editingCanceled(ChangeEvent e) {
  3962. // nothing to report, 'cause nothing changed
  3963. }
  3964. /**
  3965. * Track changes to table cell selections
  3966. */
  3967. public void valueChanged(ListSelectionEvent e) {
  3968. firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
  3969. Boolean.valueOf(false), Boolean.valueOf(true));
  3970. int selectedRow = JTable.this.getSelectedRow();
  3971. int selectedCol = JTable.this.getSelectedColumn();
  3972. if (selectedRow != lastSelectedRow ||
  3973. selectedCol != lastSelectedCol) {
  3974. Accessible oldA = getAccessibleAt(lastSelectedRow,
  3975. lastSelectedCol);
  3976. Accessible newA = getAccessibleAt(selectedRow, selectedCol);
  3977. firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
  3978. oldA, newA);
  3979. lastSelectedRow = selectedRow;
  3980. lastSelectedCol = selectedCol;
  3981. }
  3982. }
  3983. // AccessibleContext support
  3984. /**
  3985. * Get the AccessibleSelection associated with this object. In the
  3986. * implementation of the Java Accessibility API for this class,
  3987. * return this object, which is responsible for implementing the
  3988. * AccessibleSelection interface on behalf of itself.
  3989. *
  3990. * @return this object
  3991. */
  3992. public AccessibleSelection getAccessibleSelection() {
  3993. return this;
  3994. }
  3995. /**
  3996. * Gets the role of this object.
  3997. *
  3998. * @return an instance of AccessibleRole describing the role of the
  3999. * object
  4000. * @see AccessibleRole
  4001. */
  4002. public AccessibleRole getAccessibleRole() {
  4003. return AccessibleRole.TABLE;
  4004. }
  4005. /**
  4006. * Returns the <code>Accessible</code> child, if one exists,
  4007. * contained at the local coordinate <code>Point</code>.
  4008. *
  4009. * @param p the point defining the top-left corner of the
  4010. * <code>Accessible</code>, given in the coordinate space
  4011. * of the object's parent
  4012. * @return the <code>Accessible</code>, if it exists,
  4013. * at the specified location; else <code>null</code>
  4014. */
  4015. public Accessible getAccessibleAt(Point p) {
  4016. int column = columnAtPoint(p);
  4017. int row = rowAtPoint(p);
  4018. if ((column != -1) && (row != -1)) {
  4019. TableColumn aColumn = getColumnModel().getColumn(column);
  4020. TableCellRenderer renderer = aColumn.getCellRenderer();
  4021. if (renderer == null) {
  4022. Class columnClass = getColumnClass(column);
  4023. renderer = getDefaultRenderer(columnClass);
  4024. }
  4025. Component component = renderer.getTableCellRendererComponent(
  4026. JTable.this, null, false, false,
  4027. row, column);
  4028. return new AccessibleJTableCell(JTable.this, row, column,
  4029. getAccessibleIndexAt(row, column));
  4030. }
  4031. return null;
  4032. }
  4033. /**
  4034. * Returns the number of accessible children in the object. If all
  4035. * of the children of this object implement <code>Accessible</code>,
  4036. * then this method should return the number of children of this object.
  4037. *
  4038. * @return the number of accessible children in the object
  4039. */
  4040. public int getAccessibleChildrenCount() {
  4041. return (JTable.this.getColumnCount() * JTable.this.getRowCount());
  4042. }
  4043. /**
  4044. * Returns the nth <code>Accessible</code> child of the object.
  4045. *
  4046. * @param i zero-based index of child
  4047. * @return the nth Accessible child of the object
  4048. */
  4049. public Accessible getAccessibleChild(int i) {
  4050. if (i < 0 || i >= getAccessibleChildrenCount()) {
  4051. return null;
  4052. } else {
  4053. // children increase across, and then down, for tables
  4054. // (arbitrary decision)
  4055. int column = getAccessibleColumnAtIndex(i);
  4056. int row = getAccessibleRowAtIndex(i);
  4057. TableColumn aColumn = getColumnModel().getColumn(column);
  4058. TableCellRenderer renderer = aColumn.getCellRenderer();
  4059. if (renderer == null) {
  4060. Class columnClass = getColumnClass(column);
  4061. renderer = getDefaultRenderer(columnClass);
  4062. }
  4063. Component component = renderer.getTableCellRendererComponent(
  4064. JTable.this, null, false, false,
  4065. row, column);
  4066. return new AccessibleJTableCell(JTable.this, row, column,
  4067. getAccessibleIndexAt(row, column));
  4068. }
  4069. }
  4070. // AccessibleSelection support
  4071. /**
  4072. * Returns the number of <code>Accessible</code> children
  4073. * currently selected.
  4074. * If no children are selected, the return value will be 0.
  4075. *
  4076. * @return the number of items currently selected
  4077. */
  4078. public int getAccessibleSelectionCount() {
  4079. int rowsSel = JTable.this.getSelectedRowCount();
  4080. int colsSel = JTable.this.getSelectedColumnCount();
  4081. if (JTable.this.cellSelectionEnabled) { // a contiguous block
  4082. return rowsSel * colsSel;
  4083. } else {
  4084. // a column swath and a row swath, with a shared block
  4085. if (JTable.this.getRowSelectionAllowed() &&
  4086. JTable.this.getColumnSelectionAllowed()) {
  4087. return rowsSel * JTable.this.getColumnCount() +
  4088. colsSel * JTable.this.getRowCount() -
  4089. rowsSel * colsSel;
  4090. // just one or more rows in selection
  4091. } else if (JTable.this.getRowSelectionAllowed()) {
  4092. return rowsSel * JTable.this.getColumnCount();
  4093. // just one or more rows in selection
  4094. } else if (JTable.this.getColumnSelectionAllowed()) {
  4095. return colsSel * JTable.this.getRowCount();
  4096. } else {
  4097. return 0; // JTable doesn't allow selections
  4098. }
  4099. }
  4100. }
  4101. /**
  4102. * Returns an <code>Accessible</code> representing the
  4103. * specified selected child in the object. If there
  4104. * isn't a selection, or there are fewer children selected
  4105. * than the integer passed in, the return
  4106. * value will be <code>null</code>.
  4107. * <p>Note that the index represents the i-th selected child, which
  4108. * is different from the i-th child.
  4109. *
  4110. * @param i the zero-based index of selected children
  4111. * @return the i-th selected child
  4112. * @see #getAccessibleSelectionCount
  4113. */
  4114. public Accessible getAccessibleSelection(int i) {
  4115. if (i < 0 || i > getAccessibleSelectionCount()) {
  4116. return (Accessible) null;
  4117. }
  4118. int rowsSel = JTable.this.getSelectedRowCount();
  4119. int colsSel = JTable.this.getSelectedColumnCount();
  4120. int rowIndicies[] = getSelectedRows();
  4121. int colIndicies[] = getSelectedColumns();
  4122. int ttlCols = JTable.this.getColumnCount();
  4123. int ttlRows = JTable.this.getRowCount();
  4124. int r;
  4125. int c;
  4126. if (JTable.this.cellSelectionEnabled) { // a contiguous block
  4127. r = rowIndicies[i / colsSel];
  4128. c = colIndicies[i % colsSel];
  4129. return getAccessibleChild((r * ttlCols) + c);
  4130. } else {
  4131. // a column swath and a row swath, with a shared block
  4132. if (JTable.this.getRowSelectionAllowed() &&
  4133. JTable.this.getColumnSelectionAllowed()) {
  4134. // Situation:
  4135. // We have a table, like the 6x3 table below,
  4136. // wherein three colums and one row selected
  4137. // (selected cells marked with "*", unselected "0"):
  4138. //
  4139. // 0 * 0 * * 0
  4140. // * * * * * *
  4141. // 0 * 0 * * 0
  4142. //
  4143. // State machine below walks through the array of
  4144. // selected rows in two states: in a selected row,
  4145. // and not in one; continuing until we are in a row
  4146. // in which the ith selection exists. Then we return
  4147. // the appropriate cell. In the state machine, we
  4148. // always do rows above the "current" selected row first,
  4149. // then the cells in the selected row. If we're done
  4150. // with the state machine before finding the requested
  4151. // selected child, we handle the rows below the last
  4152. // selected row at the end.
  4153. //
  4154. int curIndex = i;
  4155. final int IN_ROW = 0;
  4156. final int NOT_IN_ROW = 1;
  4157. int state = (rowIndicies[0] == 0 ? IN_ROW : NOT_IN_ROW);
  4158. int j = 0;
  4159. int prevRow = -1;
  4160. while (j < rowIndicies.length) {
  4161. switch (state) {
  4162. case IN_ROW: // on individual row full of selections
  4163. if (curIndex < ttlCols) { // it's here!
  4164. c = curIndex % ttlCols;
  4165. r = rowIndicies[j];
  4166. return getAccessibleChild((r * ttlCols) + c);
  4167. } else { // not here
  4168. curIndex -= ttlCols;
  4169. }
  4170. // is the next row in table selected or not?
  4171. if (j + 1 == rowIndicies.length ||
  4172. rowIndicies[j] != rowIndicies[j+1] - 1) {
  4173. state = NOT_IN_ROW;
  4174. prevRow = rowIndicies[j];
  4175. }
  4176. j++; // we didn't return earlier, so go to next row
  4177. break;
  4178. case NOT_IN_ROW: // sparse bunch of rows of selections
  4179. if (curIndex <
  4180. (colsSel * (rowIndicies[j] -
  4181. (prevRow == -1 ? 0 : (prevRow + 1))))) {
  4182. // it's here!
  4183. c = colIndicies[curIndex % colsSel];
  4184. r = (j > 0 ? rowIndicies[j-1] + 1 : 0)
  4185. + curIndex / colsSel;
  4186. return getAccessibleChild((r * ttlCols) + c);
  4187. } else { // not here
  4188. curIndex -= colsSel * (rowIndicies[j] -
  4189. (prevRow == -1 ? 0 : (prevRow + 1)));
  4190. }
  4191. state = IN_ROW;
  4192. break;
  4193. }
  4194. }
  4195. // we got here, so we didn't find it yet; find it in
  4196. // the last sparse bunch of rows
  4197. if (curIndex <
  4198. (colsSel * (ttlRows -
  4199. (prevRow == -1 ? 0 : (prevRow + 1))))) { // it's here!
  4200. c = colIndicies[curIndex % colsSel];
  4201. r = rowIndicies[j-1] + curIndex / colsSel + 1;
  4202. return getAccessibleChild((r * ttlCols) + c);
  4203. } else { // not here
  4204. // we shouldn't get to this spot in the code!
  4205. // System.out.println("Bug in AccessibleJTable.getAccessibleSelection()");
  4206. }
  4207. // one or more rows selected
  4208. } else if (JTable.this.getRowSelectionAllowed()) {
  4209. c = i % ttlCols;
  4210. r = rowIndicies[i / ttlCols];
  4211. return getAccessibleChild((r * ttlCols) + c);
  4212. // one or more columns selected
  4213. } else if (JTable.this.getColumnSelectionAllowed()) {
  4214. c = colIndicies[i % colsSel];
  4215. r = i / colsSel;
  4216. return getAccessibleChild((r * ttlCols) + c);
  4217. }
  4218. }
  4219. return (Accessible) null;
  4220. }
  4221. /**
  4222. * Determines if the current child of this object is selected.
  4223. *
  4224. * @param i the zero-based index of the child in this
  4225. * <code>Accessible</code> object
  4226. * @return true if the current child of this object is selected
  4227. * @see AccessibleContext#getAccessibleChild
  4228. */
  4229. public boolean isAccessibleChildSelected(int i) {
  4230. int column = getAccessibleColumnAtIndex(i);
  4231. int row = getAccessibleRowAtIndex(i);
  4232. return JTable.this.isCellSelected(row, column);
  4233. }
  4234. /**
  4235. * Adds the specified <code>Accessible</code> child of the
  4236. * object to the object's selection. If the object supports
  4237. * multiple selections, the specified child is added to
  4238. * any existing selection, otherwise
  4239. * it replaces any existing selection in the object. If the
  4240. * specified child is already selected, this method has no effect.
  4241. * <p>
  4242. * This method only works on <code>JTable</code>s which have
  4243. * individual cell selection enabled.
  4244. *
  4245. * @param i the zero-based index of the child
  4246. * @see AccessibleContext#getAccessibleChild
  4247. */
  4248. public void addAccessibleSelection(int i) {
  4249. if (JTable.this.cellSelectionEnabled) {
  4250. int column = getAccessibleColumnAtIndex(i);
  4251. int row = getAccessibleRowAtIndex(i);
  4252. JTable.this.addRowSelectionInterval(row, row);
  4253. JTable.this.addColumnSelectionInterval(column, column);
  4254. }
  4255. }
  4256. /**
  4257. * Removes the specified child of the object from the object's
  4258. * selection. If the specified item isn't currently selected, this
  4259. * method has no effect.
  4260. * <p>
  4261. * This method only works on <code>JTables</code> which have
  4262. * individual cell selection enabled.
  4263. *
  4264. * @param i the zero-based index of the child
  4265. * @see AccessibleContext#getAccessibleChild
  4266. */
  4267. public void removeAccessibleSelection(int i) {
  4268. if (JTable.this.cellSelectionEnabled) {
  4269. int column = getAccessibleColumnAtIndex(i);
  4270. int row = getAccessibleRowAtIndex(i);
  4271. JTable.this.removeRowSelectionInterval(row, row);
  4272. JTable.this.removeColumnSelectionInterval(column, column);
  4273. }
  4274. }
  4275. /**
  4276. * Clears the selection in the object, so that no children in the
  4277. * object are selected.
  4278. */
  4279. public void clearAccessibleSelection() {
  4280. JTable.this.clearSelection();
  4281. }
  4282. /**
  4283. * Causes every child of the object to be selected, but only
  4284. * if the <code>JTable</code> supports multiple selections,
  4285. * and if individual cell selection is enabled.
  4286. */
  4287. public void selectAllAccessibleSelection() {
  4288. if (JTable.this.cellSelectionEnabled) {
  4289. JTable.this.selectAll();
  4290. }
  4291. }
  4292. // begin AccessibleExtendedTable implementation -------------
  4293. /**
  4294. * Returns the row number of an index in the table.
  4295. *
  4296. * @param index the zero-based index in the table
  4297. * @return the zero-based row of the table if one exists;
  4298. * otherwise -1.
  4299. */
  4300. public int getAccessibleRow(int index) {
  4301. return getAccessibleRowAtIndex(index);
  4302. }
  4303. /**
  4304. * Returns the column number of an index in the table.
  4305. *
  4306. * @param index the zero-based index in the table
  4307. * @return the zero-based column of the table if one exists;
  4308. * otherwise -1.
  4309. */
  4310. public int getAccessibleColumn(int index) {
  4311. return getAccessibleColumnAtIndex(index);
  4312. }
  4313. /**
  4314. * Returns the index at a row and column in the table.
  4315. *
  4316. * @param r zero-based row of the table
  4317. * @param c zero-based column of the table
  4318. * @return the zero-based index in the table if one exists;
  4319. * otherwise -1.
  4320. */
  4321. public int getAccessibleIndex(int r, int c) {
  4322. return getAccessibleIndexAt(r, c);
  4323. }
  4324. // end of AccessibleExtendedTable implementation ------------
  4325. // start of AccessibleTable implementation ------------------
  4326. private Accessible caption;
  4327. private Accessible summary;
  4328. private Accessible [] rowDescription;
  4329. private Accessible [] columnDescription;
  4330. /**
  4331. * Gets the <code>AccessibleTable</code> associated with this
  4332. * object. In the implementation of the Java Accessibility
  4333. * API for this class, return this object, which is responsible
  4334. * for implementing the <code>AccessibleTables</code> interface
  4335. * on behalf of itself.
  4336. *
  4337. * @return this object
  4338. */
  4339. public AccessibleTable getAccessibleTable() {
  4340. return this;
  4341. }
  4342. /**
  4343. * Returns the caption for the table.
  4344. *
  4345. * @return the caption for the table
  4346. */
  4347. public Accessible getAccessibleCaption() {
  4348. return this.caption;
  4349. }
  4350. /**
  4351. * Sets the caption for the table.
  4352. *
  4353. * @param a the caption for the table
  4354. */
  4355. public void setAccessibleCaption(Accessible a) {
  4356. Accessible oldCaption = caption;
  4357. this.caption = a;
  4358. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_CAPTION_CHANGED,
  4359. oldCaption, this.caption);
  4360. }
  4361. /**
  4362. * Returns the summary description of the table.
  4363. *
  4364. * @return the summary description of the table
  4365. */
  4366. public Accessible getAccessibleSummary() {
  4367. return this.summary;
  4368. }
  4369. /**
  4370. * Sets the summary description of the table.
  4371. *
  4372. * @param a the summary description of the table
  4373. */
  4374. public void setAccessibleSummary(Accessible a) {
  4375. Accessible oldSummary = summary;
  4376. this.summary = a;
  4377. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_SUMMARY_CHANGED,
  4378. oldSummary, this.summary);
  4379. }
  4380. /*
  4381. * Returns the total number of rows in this table.
  4382. *
  4383. * @return the total number of rows in this table
  4384. */
  4385. public int getAccessibleRowCount() {
  4386. return JTable.this.getRowCount();
  4387. }
  4388. /*
  4389. * Returns the total number of columns in the table.
  4390. *
  4391. * @return the total number of columns in the table
  4392. */
  4393. public int getAccessibleColumnCount() {
  4394. return JTable.this.getColumnCount();
  4395. }
  4396. /*
  4397. * Returns the <code>Accessible</code> at a specified row
  4398. * and column in the table.
  4399. *
  4400. * @param r zero-based row of the table
  4401. * @param c zero-based column of the table
  4402. * @return the <code>Accessible</code> at the specified row and column
  4403. * in the table
  4404. */
  4405. public Accessible getAccessibleAt(int r, int c) {
  4406. return getAccessibleChild((r * getAccessibleColumnCount()) + c);
  4407. }
  4408. /**
  4409. * Returns the number of rows occupied by the <code>Accessible</code>
  4410. * at a specified row and column in the table.
  4411. *
  4412. * @return the number of rows occupied by the <code>Accessible</code>
  4413. * at a specified row and column in the table
  4414. */
  4415. public int getAccessibleRowExtentAt(int r, int c) {
  4416. return 1;
  4417. }
  4418. /**
  4419. * Returns the number of columns occupied by the
  4420. * <code>Accessible</code> at a given (row, column).
  4421. *
  4422. * @return the number of columns occupied by the <code>Accessible</code>
  4423. * at a specified row and column in the table
  4424. */
  4425. public int getAccessibleColumnExtentAt(int r, int c) {
  4426. return 1;
  4427. }
  4428. /**
  4429. * Returns the row headers as an <code>AccessibleTable</code>.
  4430. *
  4431. * @return an <code>AccessibleTable</code> representing the row
  4432. * headers
  4433. */
  4434. public AccessibleTable getAccessibleRowHeader() {
  4435. // row headers are not supported
  4436. return null;
  4437. }
  4438. /**
  4439. * Returns the row headers as an <code>AccessibleTable</code>.
  4440. *
  4441. * @return an <code>AccessibleTable</code> representing
  4442. * the row headers
  4443. */
  4444. public void setAccessibleRowHeader(AccessibleTable a) {
  4445. // row headers are not supported
  4446. }
  4447. /**
  4448. * Returns the column headers as an <code>AccessibleTable</code>.
  4449. *
  4450. * @return an <code>AccessibleTable</code> representing the column
  4451. * headers
  4452. */
  4453. public AccessibleTable getAccessibleColumnHeader() {
  4454. return new AccessibleTableHeader(JTable.this.getTableHeader());
  4455. }
  4456. /*
  4457. * Private class representing a table column header
  4458. */
  4459. private class AccessibleTableHeader implements AccessibleTable {
  4460. private JTableHeader header;
  4461. private TableColumnModel headerModel;
  4462. AccessibleTableHeader(JTableHeader header) {
  4463. this.header = header;
  4464. this.headerModel = header.getColumnModel();
  4465. }
  4466. /**
  4467. * Returns the caption for the table.
  4468. *
  4469. * @return the caption for the table
  4470. */
  4471. public Accessible getAccessibleCaption() { return null; }
  4472. /**
  4473. * Sets the caption for the table.
  4474. *
  4475. * @param a the caption for the table
  4476. */
  4477. public void setAccessibleCaption(Accessible a) {}
  4478. /**
  4479. * Returns the summary description of the table.
  4480. *
  4481. * @return the summary description of the table
  4482. */
  4483. public Accessible getAccessibleSummary() { return null; }
  4484. /**
  4485. * Sets the summary description of the table
  4486. *
  4487. * @param a the summary description of the table
  4488. */
  4489. public void setAccessibleSummary(Accessible a) {}
  4490. /**
  4491. * Returns the number of rows in the table.
  4492. *
  4493. * @return the number of rows in the table
  4494. */
  4495. public int getAccessibleRowCount() { return 1; }
  4496. /**
  4497. * Returns the number of columns in the table.
  4498. *
  4499. * @return the number of columns in the table
  4500. */
  4501. public int getAccessibleColumnCount() {
  4502. return headerModel.getColumnCount();
  4503. }
  4504. /**
  4505. * Returns the Accessible at a specified row and column
  4506. * in the table.
  4507. *
  4508. * @param row zero-based row of the table
  4509. * @param column zero-based column of the table
  4510. * @return the Accessible at the specified row and column
  4511. */
  4512. public Accessible getAccessibleAt(int row, int column) {
  4513. TableColumn aColumn = headerModel.getColumn(column);
  4514. TableCellRenderer renderer = aColumn.getHeaderRenderer();
  4515. if (renderer == null) {
  4516. renderer = header.getDefaultRenderer();
  4517. }
  4518. Component component = renderer.getTableCellRendererComponent(
  4519. header.getTable(),
  4520. aColumn.getHeaderValue(), false, false,
  4521. -1, column);
  4522. if (component instanceof Accessible) {
  4523. return ((Accessible) component);
  4524. } else {
  4525. return null;
  4526. }
  4527. }
  4528. /**
  4529. * Returns the number of rows occupied by the Accessible at
  4530. * a specified row and column in the table.
  4531. *
  4532. * @return the number of rows occupied by the Accessible at a
  4533. * given specified (row, column)
  4534. */
  4535. public int getAccessibleRowExtentAt(int r, int c) { return 1; }
  4536. /**
  4537. * Returns the number of columns occupied by the Accessible at
  4538. * a specified row and column in the table.
  4539. *
  4540. * @return the number of columns occupied by the Accessible at a
  4541. * given specified row and column
  4542. */
  4543. public int getAccessibleColumnExtentAt(int r, int c) { return 1; }
  4544. /**
  4545. * Returns the row headers as an AccessibleTable.
  4546. *
  4547. * @return an AccessibleTable representing the row
  4548. * headers
  4549. */
  4550. public AccessibleTable getAccessibleRowHeader() { return null; }
  4551. /**
  4552. * Sets the row headers.
  4553. *
  4554. * @param table an AccessibleTable representing the
  4555. * row headers
  4556. */
  4557. public void setAccessibleRowHeader(AccessibleTable table) {}
  4558. /**
  4559. * Returns the column headers as an AccessibleTable.
  4560. *
  4561. * @return an AccessibleTable representing the column
  4562. * headers
  4563. */
  4564. public AccessibleTable getAccessibleColumnHeader() { return null; }
  4565. /**
  4566. * Sets the column headers.
  4567. *
  4568. * @param table an AccessibleTable representing the
  4569. * column headers
  4570. */
  4571. public void setAccessibleColumnHeader(AccessibleTable table) {}
  4572. /**
  4573. * Returns the description of the specified row in the table.
  4574. *
  4575. * @param r zero-based row of the table
  4576. * @return the description of the row
  4577. */
  4578. public Accessible getAccessibleRowDescription(int r) { return null; }
  4579. /**
  4580. * Sets the description text of the specified row of the table.
  4581. *
  4582. * @param r zero-based row of the table
  4583. * @param a the description of the row
  4584. */
  4585. public void setAccessibleRowDescription(int r, Accessible a) {}
  4586. /**
  4587. * Returns the description text of the specified column in the table.
  4588. *
  4589. * @param c zero-based column of the table
  4590. * @return the text description of the column
  4591. */
  4592. public Accessible getAccessibleColumnDescription(int c) { return null; }
  4593. /**
  4594. * Sets the description text of the specified column in the table.
  4595. *
  4596. * @param c zero-based column of the table
  4597. * @param a the text description of the column
  4598. */
  4599. public void setAccessibleColumnDescription(int c, Accessible a) {}
  4600. /**
  4601. * Returns a boolean value indicating whether the accessible at
  4602. * a specified row and column is selected.
  4603. *
  4604. * @param r zero-based row of the table
  4605. * @param c zero-based column of the table
  4606. * @return the boolean value true if the accessible at the
  4607. * row and column is selected. Otherwise, the boolean value
  4608. * false
  4609. */
  4610. public boolean isAccessibleSelected(int r, int c) { return false; }
  4611. /**
  4612. * Returns a boolean value indicating whether the specified row
  4613. * is selected.
  4614. *
  4615. * @param r zero-based row of the table
  4616. * @return the boolean value true if the specified row is selected.
  4617. * Otherwise, false.
  4618. */
  4619. public boolean isAccessibleRowSelected(int r) { return false; }
  4620. /**
  4621. * Returns a boolean value indicating whether the specified column
  4622. * is selected.
  4623. *
  4624. * @param r zero-based column of the table
  4625. * @return the boolean value true if the specified column is selected.
  4626. * Otherwise, false.
  4627. */
  4628. public boolean isAccessibleColumnSelected(int c) { return false; }
  4629. /**
  4630. * Returns the selected rows in a table.
  4631. *
  4632. * @return an array of selected rows where each element is a
  4633. * zero-based row of the table
  4634. */
  4635. public int [] getSelectedAccessibleRows() { return new int[0]; }
  4636. /**
  4637. * Returns the selected columns in a table.
  4638. *
  4639. * @return an array of selected columns where each element is a
  4640. * zero-based column of the table
  4641. */
  4642. public int [] getSelectedAccessibleColumns() { return new int[0]; }
  4643. }
  4644. /**
  4645. * Returns the column headers as an <code>AccessibleTable</code>.
  4646. *
  4647. * @return an <code>AccessibleTable</code> representing the column
  4648. * headers
  4649. */
  4650. public void setAccessibleColumnHeader(AccessibleTable a) {
  4651. // XXX not implemented
  4652. }
  4653. /**
  4654. * Returns the description of the specified row in the table.
  4655. *
  4656. * @param r zero-based row of the table
  4657. * @return the description of the row
  4658. */
  4659. public Accessible getAccessibleRowDescription(int r) {
  4660. if (r < 0 || r >= getAccessibleRowCount()) {
  4661. throw new IllegalArgumentException(new Integer(r).toString());
  4662. }
  4663. if (rowDescription == null) {
  4664. return null;
  4665. } else {
  4666. return rowDescription[r];
  4667. }
  4668. }
  4669. /**
  4670. * Sets the description text of the specified row of the table.
  4671. *
  4672. * @param r zero-based row of the table
  4673. * @param a the description of the row
  4674. */
  4675. public void setAccessibleRowDescription(int r, Accessible a) {
  4676. if (r < 0 || r >= getAccessibleRowCount()) {
  4677. throw new IllegalArgumentException(new Integer(r).toString());
  4678. }
  4679. if (rowDescription == null) {
  4680. int numRows = getAccessibleRowCount();
  4681. rowDescription = new Accessible[numRows];
  4682. }
  4683. rowDescription[r] = a;
  4684. }
  4685. /**
  4686. * Returns the description of the specified column in the table.
  4687. *
  4688. * @param c zero-based column of the table
  4689. * @return the description of the column
  4690. */
  4691. public Accessible getAccessibleColumnDescription(int c) {
  4692. if (c < 0 || c >= getAccessibleColumnCount()) {
  4693. throw new IllegalArgumentException(new Integer(c).toString());
  4694. }
  4695. if (columnDescription == null) {
  4696. return null;
  4697. } else {
  4698. return columnDescription[c];
  4699. }
  4700. }
  4701. /**
  4702. * Sets the description text of the specified column of the table.
  4703. *
  4704. * @param c zero-based column of the table
  4705. * @param a the description of the column
  4706. */
  4707. public void setAccessibleColumnDescription(int c, Accessible a) {
  4708. if (c < 0 || c >= getAccessibleColumnCount()) {
  4709. throw new IllegalArgumentException(new Integer(c).toString());
  4710. }
  4711. if (columnDescription == null) {
  4712. int numColumns = getAccessibleColumnCount();
  4713. columnDescription = new Accessible[numColumns];
  4714. }
  4715. columnDescription[c] = a;
  4716. }
  4717. /**
  4718. * Returns a boolean value indicating whether the accessible at a
  4719. * given (row, column) is selected.
  4720. *
  4721. * @param r zero-based row of the table
  4722. * @param c zero-based column of the table
  4723. * @return the boolean value true if the accessible at (row, column)
  4724. * is selected; otherwise, the boolean value false
  4725. */
  4726. public boolean isAccessibleSelected(int r, int c) {
  4727. return JTable.this.isCellSelected(r, c);
  4728. }
  4729. /**
  4730. * Returns a boolean value indicating whether the specified row
  4731. * is selected.
  4732. *
  4733. * @param r zero-based row of the table
  4734. * @return the boolean value true if the specified row is selected;
  4735. * otherwise, false
  4736. */
  4737. public boolean isAccessibleRowSelected(int r) {
  4738. return JTable.this.isRowSelected(r);
  4739. }
  4740. /**
  4741. * Returns a boolean value indicating whether the specified column
  4742. * is selected.
  4743. *
  4744. * @param c zero-based column of the table
  4745. * @return the boolean value true if the specified column is selected;
  4746. * otherwise, false
  4747. */
  4748. public boolean isAccessibleColumnSelected(int c) {
  4749. return JTable.this.isColumnSelected(c);
  4750. }
  4751. /**
  4752. * Returns the selected rows in a table.
  4753. *
  4754. * @return an array of selected rows where each element is a
  4755. * zero-based row of the table
  4756. */
  4757. public int [] getSelectedAccessibleRows() {
  4758. return JTable.this.getSelectedRows();
  4759. }
  4760. /**
  4761. * Returns the selected columns in a table.
  4762. *
  4763. * @return an array of selected columns where each element is a
  4764. * zero-based column of the table
  4765. */
  4766. public int [] getSelectedAccessibleColumns() {
  4767. return JTable.this.getSelectedColumns();
  4768. }
  4769. /**
  4770. * Returns the row at a given index into the table.
  4771. *
  4772. * @param i zero-based index into the table
  4773. * @return the row at a given index
  4774. */
  4775. public int getAccessibleRowAtIndex(int i) {
  4776. int columnCount = getAccessibleColumnCount();
  4777. if (columnCount == 0) {
  4778. return -1;
  4779. } else {
  4780. return (i / columnCount);
  4781. }
  4782. }
  4783. /**
  4784. * Returns the column at a given index into the table.
  4785. *
  4786. * @param i zero-based index into the table
  4787. * @return the column at a given index
  4788. */
  4789. public int getAccessibleColumnAtIndex(int i) {
  4790. int columnCount = getAccessibleColumnCount();
  4791. if (columnCount == 0) {
  4792. return -1;
  4793. } else {
  4794. return (i % columnCount);
  4795. }
  4796. }
  4797. /**
  4798. * Returns the index at a given (row, column) in the table.
  4799. *
  4800. * @param r zero-based row of the table
  4801. * @param c zero-based column of the table
  4802. * @return the index into the table
  4803. */
  4804. public int getAccessibleIndexAt(int r, int c) {
  4805. return ((r * getAccessibleColumnCount()) + c);
  4806. }
  4807. // end of AccessibleTable implementation --------------------
  4808. /**
  4809. * The class provides an implementation of the Java Accessibility
  4810. * API appropriate to table cells.
  4811. */
  4812. protected class AccessibleJTableCell extends AccessibleContext
  4813. implements Accessible, AccessibleComponent {
  4814. private JTable parent;
  4815. private int row;
  4816. private int column;
  4817. private int index;
  4818. /**
  4819. * Constructs an <code>AccessibleJTableHeaderEntry</code>.
  4820. */
  4821. public AccessibleJTableCell(JTable t, int r, int c, int i) {
  4822. parent = t;
  4823. row = r;
  4824. column = c;
  4825. index = i;
  4826. this.setAccessibleParent(parent);
  4827. }
  4828. /**
  4829. * Gets the <code>AccessibleContext</code> associated with this
  4830. * component. In the implementation of the Java Accessibility
  4831. * API for this class, return this object, which is its own
  4832. * <code>AccessibleContext</code>.
  4833. *
  4834. * @return this object
  4835. */
  4836. public AccessibleContext getAccessibleContext() {
  4837. return this;
  4838. }
  4839. private AccessibleContext getCurrentAccessibleContext() {
  4840. TableColumn aColumn = getColumnModel().getColumn(column);
  4841. TableCellRenderer renderer = aColumn.getCellRenderer();
  4842. if (renderer == null) {
  4843. Class columnClass = getColumnClass(column);
  4844. renderer = getDefaultRenderer(columnClass);
  4845. }
  4846. Component component = renderer.getTableCellRendererComponent(
  4847. JTable.this, getValueAt(row, column),
  4848. false, false, row, column);
  4849. if (component instanceof Accessible) {
  4850. return ((Accessible) component).getAccessibleContext();
  4851. } else {
  4852. return null;
  4853. }
  4854. }
  4855. private Component getCurrentComponent() {
  4856. TableColumn aColumn = getColumnModel().getColumn(column);
  4857. TableCellRenderer renderer = aColumn.getCellRenderer();
  4858. if (renderer == null) {
  4859. Class columnClass = getColumnClass(column);
  4860. renderer = getDefaultRenderer(columnClass);
  4861. }
  4862. return renderer.getTableCellRendererComponent(
  4863. JTable.this, null, false, false,
  4864. row, column);
  4865. }
  4866. // AccessibleContext methods
  4867. /**
  4868. * Gets the accessible name of this object.
  4869. *
  4870. * @return the localized name of the object; <code>null</code>
  4871. * if this object does not have a name
  4872. */
  4873. public String getAccessibleName() {
  4874. AccessibleContext ac = getCurrentAccessibleContext();
  4875. if (ac != null) {
  4876. String name = ac.getAccessibleName();
  4877. if ((name != null) && (name != "")) {
  4878. return ac.getAccessibleName();
  4879. }
  4880. }
  4881. if ((accessibleName != null) && (accessibleName != "")) {
  4882. return accessibleName;
  4883. } else {
  4884. return null;
  4885. }
  4886. }
  4887. /**
  4888. * Sets the localized accessible name of this object.
  4889. *
  4890. * @param s the new localized name of the object
  4891. */
  4892. public void setAccessibleName(String s) {
  4893. AccessibleContext ac = getCurrentAccessibleContext();
  4894. if (ac != null) {
  4895. ac.setAccessibleName(s);
  4896. } else {
  4897. super.setAccessibleName(s);
  4898. }
  4899. }
  4900. //
  4901. // *** should check toolTip text for desc. (needs MouseEvent)
  4902. //
  4903. /**
  4904. * Gets the accessible description of this object.
  4905. *
  4906. * @return the localized description of the object;
  4907. * <code>null</code> if this object does not have
  4908. * a description
  4909. */
  4910. public String getAccessibleDescription() {
  4911. AccessibleContext ac = getCurrentAccessibleContext();
  4912. if (ac != null) {
  4913. return ac.getAccessibleDescription();
  4914. } else {
  4915. return super.getAccessibleDescription();
  4916. }
  4917. }
  4918. /**
  4919. * Sets the accessible description of this object.
  4920. *
  4921. * @param s the new localized description of the object
  4922. */
  4923. public void setAccessibleDescription(String s) {
  4924. AccessibleContext ac = getCurrentAccessibleContext();
  4925. if (ac != null) {
  4926. ac.setAccessibleDescription(s);
  4927. } else {
  4928. super.setAccessibleDescription(s);
  4929. }
  4930. }
  4931. /**
  4932. * Gets the role of this object.
  4933. *
  4934. * @return an instance of <code>AccessibleRole</code>
  4935. * describing the role of the object
  4936. * @see AccessibleRole
  4937. */
  4938. public AccessibleRole getAccessibleRole() {
  4939. AccessibleContext ac = getCurrentAccessibleContext();
  4940. if (ac != null) {
  4941. return ac.getAccessibleRole();
  4942. } else {
  4943. return AccessibleRole.UNKNOWN;
  4944. }
  4945. }
  4946. /**
  4947. * Gets the state set of this object.
  4948. *
  4949. * @return an instance of <code>AccessibleStateSet</code>
  4950. * containing the current state set of the object
  4951. * @see AccessibleState
  4952. */
  4953. public AccessibleStateSet getAccessibleStateSet() {
  4954. AccessibleContext ac = getCurrentAccessibleContext();
  4955. AccessibleStateSet as = null;
  4956. if (ac != null) {
  4957. as = ac.getAccessibleStateSet();
  4958. }
  4959. if (as == null) {
  4960. as = new AccessibleStateSet();
  4961. }
  4962. Rectangle rjt = JTable.this.getVisibleRect();
  4963. Rectangle rcell = JTable.this.getCellRect(row, column, false);
  4964. if (rjt.intersects(rcell)) {
  4965. as.add(AccessibleState.SHOWING);
  4966. } else {
  4967. if (as.contains(AccessibleState.SHOWING)) {
  4968. as.remove(AccessibleState.SHOWING);
  4969. }
  4970. }
  4971. if (parent.isCellSelected(row, column)) {
  4972. as.add(AccessibleState.SELECTED);
  4973. } else if (as.contains(AccessibleState.SELECTED)) {
  4974. as.remove(AccessibleState.SELECTED);
  4975. }
  4976. if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
  4977. as.add(AccessibleState.ACTIVE);
  4978. }
  4979. as.add(AccessibleState.TRANSIENT);
  4980. return as;
  4981. }
  4982. /**
  4983. * Gets the <code>Accessible</code> parent of this object.
  4984. *
  4985. * @return the Accessible parent of this object;
  4986. * <code>null</code> if this object does not
  4987. * have an <code>Accessible</code> parent
  4988. */
  4989. public Accessible getAccessibleParent() {
  4990. return parent;
  4991. }
  4992. /**
  4993. * Gets the index of this object in its accessible parent.
  4994. *
  4995. * @return the index of this object in its parent; -1 if this
  4996. * object does not have an accessible parent
  4997. * @see #getAccessibleParent
  4998. */
  4999. public int getAccessibleIndexInParent() {
  5000. return index;
  5001. }
  5002. /**
  5003. * Returns the number of accessible children in the object.
  5004. *
  5005. * @return the number of accessible children in the object
  5006. */
  5007. public int getAccessibleChildrenCount() {
  5008. AccessibleContext ac = getCurrentAccessibleContext();
  5009. if (ac != null) {
  5010. return ac.getAccessibleChildrenCount();
  5011. } else {
  5012. return 0;
  5013. }
  5014. }
  5015. /**
  5016. * Returns the specified <code>Accessible</code> child of the
  5017. * object.
  5018. *
  5019. * @param i zero-based index of child
  5020. * @return the <code>Accessible</code> child of the object
  5021. */
  5022. public Accessible getAccessibleChild(int i) {
  5023. AccessibleContext ac = getCurrentAccessibleContext();
  5024. if (ac != null) {
  5025. Accessible accessibleChild = ac.getAccessibleChild(i);
  5026. ac.setAccessibleParent(this);
  5027. return accessibleChild;
  5028. } else {
  5029. return null;
  5030. }
  5031. }
  5032. /**
  5033. * Gets the locale of the component. If the component
  5034. * does not have a locale, then the locale of its parent
  5035. * is returned.
  5036. *
  5037. * @return this component's locale; if this component does
  5038. * not have a locale, the locale of its parent is returned
  5039. * @exception IllegalComponentStateException if the
  5040. * <code>Component</code> does not have its own locale
  5041. * and has not yet been added to a containment hierarchy
  5042. * such that the locale can be determined from the
  5043. * containing parent
  5044. * @see #setLocale
  5045. */
  5046. public Locale getLocale() {
  5047. AccessibleContext ac = getCurrentAccessibleContext();
  5048. if (ac != null) {
  5049. return ac.getLocale();
  5050. } else {
  5051. return null;
  5052. }
  5053. }
  5054. /**
  5055. * Adds a <code>PropertyChangeListener</code> to the listener list.
  5056. * The listener is registered for all properties.
  5057. *
  5058. * @param l the <code>PropertyChangeListener</code>
  5059. * to be added
  5060. */
  5061. public void addPropertyChangeListener(PropertyChangeListener l) {
  5062. AccessibleContext ac = getCurrentAccessibleContext();
  5063. if (ac != null) {
  5064. ac.addPropertyChangeListener(l);
  5065. } else {
  5066. super.addPropertyChangeListener(l);
  5067. }
  5068. }
  5069. /**
  5070. * Removes a <code>PropertyChangeListener</code> from the
  5071. * listener list. This removes a <code>PropertyChangeListener</code>
  5072. * that was registered for all properties.
  5073. *
  5074. * @param l the <code>PropertyChangeListener</code>
  5075. * to be removed
  5076. */
  5077. public void removePropertyChangeListener(PropertyChangeListener l) {
  5078. AccessibleContext ac = getCurrentAccessibleContext();
  5079. if (ac != null) {
  5080. ac.removePropertyChangeListener(l);
  5081. } else {
  5082. super.removePropertyChangeListener(l);
  5083. }
  5084. }
  5085. /**
  5086. * Gets the <code>AccessibleAction</code> associated with this
  5087. * object if one exists. Otherwise returns <code>null</code>.
  5088. *
  5089. * @return the <code>AccessibleAction</code>, or <code>null</code>
  5090. */
  5091. public AccessibleAction getAccessibleAction() {
  5092. return getCurrentAccessibleContext().getAccessibleAction();
  5093. }
  5094. /**
  5095. * Gets the <code>AccessibleComponent</code> associated with
  5096. * this object if one exists. Otherwise returns <code>null</code>.
  5097. *
  5098. * @return the <code>AccessibleComponent</code>, or
  5099. * <code>null</code>
  5100. */
  5101. public AccessibleComponent getAccessibleComponent() {
  5102. return this; // to override getBounds()
  5103. }
  5104. /**
  5105. * Gets the <code>AccessibleSelection</code> associated with
  5106. * this object if one exists. Otherwise returns <code>null</code>.
  5107. *
  5108. * @return the <code>AccessibleSelection</code>, or
  5109. * <code>null</code>
  5110. */
  5111. public AccessibleSelection getAccessibleSelection() {
  5112. return getCurrentAccessibleContext().getAccessibleSelection();
  5113. }
  5114. /**
  5115. * Gets the <code>AccessibleText</code> associated with this
  5116. * object if one exists. Otherwise returns <code>null</code>.
  5117. *
  5118. * @return the <code>AccessibleText</code>, or <code>null</code>
  5119. */
  5120. public AccessibleText getAccessibleText() {
  5121. return getCurrentAccessibleContext().getAccessibleText();
  5122. }
  5123. /**
  5124. * Gets the <code>AccessibleValue</code> associated with
  5125. * this object if one exists. Otherwise returns <code>null</code>.
  5126. *
  5127. * @return the <code>AccessibleValue</code>, or <code>null</code>
  5128. */
  5129. public AccessibleValue getAccessibleValue() {
  5130. return getCurrentAccessibleContext().getAccessibleValue();
  5131. }
  5132. // AccessibleComponent methods
  5133. /**
  5134. * Gets the background color of this object.
  5135. *
  5136. * @return the background color, if supported, of the object;
  5137. * otherwise, <code>null</code>
  5138. */
  5139. public Color getBackground() {
  5140. AccessibleContext ac = getCurrentAccessibleContext();
  5141. if (ac instanceof AccessibleComponent) {
  5142. return ((AccessibleComponent) ac).getBackground();
  5143. } else {
  5144. Component c = getCurrentComponent();
  5145. if (c != null) {
  5146. return c.getBackground();
  5147. } else {
  5148. return null;
  5149. }
  5150. }
  5151. }
  5152. /**
  5153. * Sets the background color of this object.
  5154. *
  5155. * @param c the new <code>Color</code> for the background
  5156. */
  5157. public void setBackground(Color c) {
  5158. AccessibleContext ac = getCurrentAccessibleContext();
  5159. if (ac instanceof AccessibleComponent) {
  5160. ((AccessibleComponent) ac).setBackground(c);
  5161. } else {
  5162. Component cp = getCurrentComponent();
  5163. if (cp != null) {
  5164. cp.setBackground(c);
  5165. }
  5166. }
  5167. }
  5168. /**
  5169. * Gets the foreground color of this object.
  5170. *
  5171. * @return the foreground color, if supported, of the object;
  5172. * otherwise, <code>null</code>
  5173. */
  5174. public Color getForeground() {
  5175. AccessibleContext ac = getCurrentAccessibleContext();
  5176. if (ac instanceof AccessibleComponent) {
  5177. return ((AccessibleComponent) ac).getForeground();
  5178. } else {
  5179. Component c = getCurrentComponent();
  5180. if (c != null) {
  5181. return c.getForeground();
  5182. } else {
  5183. return null;
  5184. }
  5185. }
  5186. }
  5187. /**
  5188. * Sets the foreground color of this object.
  5189. *
  5190. * @param c the new <code>Color</code> for the foreground
  5191. */
  5192. public void setForeground(Color c) {
  5193. AccessibleContext ac = getCurrentAccessibleContext();
  5194. if (ac instanceof AccessibleComponent) {
  5195. ((AccessibleComponent) ac).setForeground(c);
  5196. } else {
  5197. Component cp = getCurrentComponent();
  5198. if (cp != null) {
  5199. cp.setForeground(c);
  5200. }
  5201. }
  5202. }
  5203. /**
  5204. * Gets the <code>Cursor</code> of this object.
  5205. *
  5206. * @return the <code>Cursor</code>, if supported,
  5207. * of the object; otherwise, <code>null</code>
  5208. */
  5209. public Cursor getCursor() {
  5210. AccessibleContext ac = getCurrentAccessibleContext();
  5211. if (ac instanceof AccessibleComponent) {
  5212. return ((AccessibleComponent) ac).getCursor();
  5213. } else {
  5214. Component c = getCurrentComponent();
  5215. if (c != null) {
  5216. return c.getCursor();
  5217. } else {
  5218. Accessible ap = getAccessibleParent();
  5219. if (ap instanceof AccessibleComponent) {
  5220. return ((AccessibleComponent) ap).getCursor();
  5221. } else {
  5222. return null;
  5223. }
  5224. }
  5225. }
  5226. }
  5227. /**
  5228. * Sets the <code>Cursor</code> of this object.
  5229. *
  5230. * @param c the new <code>Cursor</code> for the object
  5231. */
  5232. public void setCursor(Cursor c) {
  5233. AccessibleContext ac = getCurrentAccessibleContext();
  5234. if (ac instanceof AccessibleComponent) {
  5235. ((AccessibleComponent) ac).setCursor(c);
  5236. } else {
  5237. Component cp = getCurrentComponent();
  5238. if (cp != null) {
  5239. cp.setCursor(c);
  5240. }
  5241. }
  5242. }
  5243. /**
  5244. * Gets the <code>Font</code> of this object.
  5245. *
  5246. * @return the <code>Font</code>,if supported,
  5247. * for the object; otherwise, <code>null</code>
  5248. */
  5249. public Font getFont() {
  5250. AccessibleContext ac = getCurrentAccessibleContext();
  5251. if (ac instanceof AccessibleComponent) {
  5252. return ((AccessibleComponent) ac).getFont();
  5253. } else {
  5254. Component c = getCurrentComponent();
  5255. if (c != null) {
  5256. return c.getFont();
  5257. } else {
  5258. return null;
  5259. }
  5260. }
  5261. }
  5262. /**
  5263. * Sets the <code>Font</code> of this object.
  5264. *
  5265. * @param f the new <code>Font</code> for the object
  5266. */
  5267. public void setFont(Font f) {
  5268. AccessibleContext ac = getCurrentAccessibleContext();
  5269. if (ac instanceof AccessibleComponent) {
  5270. ((AccessibleComponent) ac).setFont(f);
  5271. } else {
  5272. Component c = getCurrentComponent();
  5273. if (c != null) {
  5274. c.setFont(f);
  5275. }
  5276. }
  5277. }
  5278. /**
  5279. * Gets the <code>FontMetrics</code> of this object.
  5280. *
  5281. * @param f the <code>Font</code>
  5282. * @return the <code>FontMetrics</code> object, if supported;
  5283. * otherwise <code>null</code>
  5284. * @see #getFont
  5285. */
  5286. public FontMetrics getFontMetrics(Font f) {
  5287. AccessibleContext ac = getCurrentAccessibleContext();
  5288. if (ac instanceof AccessibleComponent) {
  5289. return ((AccessibleComponent) ac).getFontMetrics(f);
  5290. } else {
  5291. Component c = getCurrentComponent();
  5292. if (c != null) {
  5293. return c.getFontMetrics(f);
  5294. } else {
  5295. return null;
  5296. }
  5297. }
  5298. }
  5299. /**
  5300. * Determines if the object is enabled.
  5301. *
  5302. * @return true if object is enabled; otherwise, false
  5303. */
  5304. public boolean isEnabled() {
  5305. AccessibleContext ac = getCurrentAccessibleContext();
  5306. if (ac instanceof AccessibleComponent) {
  5307. return ((AccessibleComponent) ac).isEnabled();
  5308. } else {
  5309. Component c = getCurrentComponent();
  5310. if (c != null) {
  5311. return c.isEnabled();
  5312. } else {
  5313. return false;
  5314. }
  5315. }
  5316. }
  5317. /**
  5318. * Sets the enabled state of the object.
  5319. *
  5320. * @param b if true, enables this object; otherwise, disables it
  5321. */
  5322. public void setEnabled(boolean b) {
  5323. AccessibleContext ac = getCurrentAccessibleContext();
  5324. if (ac instanceof AccessibleComponent) {
  5325. ((AccessibleComponent) ac).setEnabled(b);
  5326. } else {
  5327. Component c = getCurrentComponent();
  5328. if (c != null) {
  5329. c.setEnabled(b);
  5330. }
  5331. }
  5332. }
  5333. /**
  5334. * Determines if this object is visible. Note: this means that the
  5335. * object intends to be visible; however, it may not in fact be
  5336. * showing on the screen because one of the objects that this object
  5337. * is contained by is not visible. To determine if an object is
  5338. * showing on the screen, use <code>isShowing</code>.
  5339. *
  5340. * @return true if object is visible; otherwise, false
  5341. */
  5342. public boolean isVisible() {
  5343. AccessibleContext ac = getCurrentAccessibleContext();
  5344. if (ac instanceof AccessibleComponent) {
  5345. return ((AccessibleComponent) ac).isVisible();
  5346. } else {
  5347. Component c = getCurrentComponent();
  5348. if (c != null) {
  5349. return c.isVisible();
  5350. } else {
  5351. return false;
  5352. }
  5353. }
  5354. }
  5355. /**
  5356. * Sets the visible state of the object.
  5357. *
  5358. * @param b if true, shows this object; otherwise, hides it
  5359. */
  5360. public void setVisible(boolean b) {
  5361. AccessibleContext ac = getCurrentAccessibleContext();
  5362. if (ac instanceof AccessibleComponent) {
  5363. ((AccessibleComponent) ac).setVisible(b);
  5364. } else {
  5365. Component c = getCurrentComponent();
  5366. if (c != null) {
  5367. c.setVisible(b);
  5368. }
  5369. }
  5370. }
  5371. /**
  5372. * Determines if the object is showing. This is determined
  5373. * by checking the visibility of the object and ancestors
  5374. * of the object. Note: this will return true even if the
  5375. * object is obscured by another (for example,
  5376. * it happens to be underneath a menu that was pulled down).
  5377. *
  5378. * @return true if the object is showing; otherwise, false
  5379. */
  5380. public boolean isShowing() {
  5381. AccessibleContext ac = getCurrentAccessibleContext();
  5382. if (ac instanceof AccessibleComponent) {
  5383. if (ac.getAccessibleParent() != null) {
  5384. return ((AccessibleComponent) ac).isShowing();
  5385. } else {
  5386. // Fixes 4529616 - AccessibleJTableCell.isShowing()
  5387. // returns false when the cell on the screen
  5388. // if no parent
  5389. return isVisible();
  5390. }
  5391. } else {
  5392. Component c = getCurrentComponent();
  5393. if (c != null) {
  5394. return c.isShowing();
  5395. } else {
  5396. return false;
  5397. }
  5398. }
  5399. }
  5400. /**
  5401. * Checks whether the specified point is within this
  5402. * object's bounds, where the point's x and y coordinates
  5403. * are defined to be relative to the coordinate system of
  5404. * the object.
  5405. *
  5406. * @param p the <code>Point</code> relative to the
  5407. * coordinate system of the object
  5408. * @return true if object contains <code>Point</code>
  5409. * otherwise false
  5410. */
  5411. public boolean contains(Point p) {
  5412. AccessibleContext ac = getCurrentAccessibleContext();
  5413. if (ac instanceof AccessibleComponent) {
  5414. Rectangle r = ((AccessibleComponent) ac).getBounds();
  5415. return r.contains(p);
  5416. } else {
  5417. Component c = getCurrentComponent();
  5418. if (c != null) {
  5419. Rectangle r = c.getBounds();
  5420. return r.contains(p);
  5421. } else {
  5422. return getBounds().contains(p);
  5423. }
  5424. }
  5425. }
  5426. /**
  5427. * Returns the location of the object on the screen.
  5428. *
  5429. * @return location of object on screen -- can be
  5430. * <code>null</code> if this object is not on the screen
  5431. */
  5432. public Point getLocationOnScreen() {
  5433. if (parent != null) {
  5434. Point parentLocation = parent.getLocationOnScreen();
  5435. Point componentLocation = getLocation();
  5436. componentLocation.translate(parentLocation.x, parentLocation.y);
  5437. return componentLocation;
  5438. } else {
  5439. return null;
  5440. }
  5441. }
  5442. /**
  5443. * Gets the location of the object relative to the parent
  5444. * in the form of a point specifying the object's
  5445. * top-left corner in the screen's coordinate space.
  5446. *
  5447. * @return an instance of <code>Point</code> representing
  5448. * the top-left corner of the object's bounds in the
  5449. * coordinate space of the screen; <code>null</code> if
  5450. * this object or its parent are not on the screen
  5451. */
  5452. public Point getLocation() {
  5453. if (parent != null) {
  5454. Rectangle r = parent.getCellRect(row, column, false);
  5455. if (r != null) {
  5456. return r.getLocation();
  5457. }
  5458. }
  5459. return null;
  5460. }
  5461. /**
  5462. * Sets the location of the object relative to the parent.
  5463. */
  5464. public void setLocation(Point p) {
  5465. // if ((parent != null) && (parent.contains(p))) {
  5466. // ensureIndexIsVisible(indexInParent);
  5467. // }
  5468. }
  5469. public Rectangle getBounds() {
  5470. if (parent != null) {
  5471. return parent.getCellRect(row, column, false);
  5472. } else {
  5473. return null;
  5474. }
  5475. }
  5476. public void setBounds(Rectangle r) {
  5477. AccessibleContext ac = getCurrentAccessibleContext();
  5478. if (ac instanceof AccessibleComponent) {
  5479. ((AccessibleComponent) ac).setBounds(r);
  5480. } else {
  5481. Component c = getCurrentComponent();
  5482. if (c != null) {
  5483. c.setBounds(r);
  5484. }
  5485. }
  5486. }
  5487. public Dimension getSize() {
  5488. if (parent != null) {
  5489. Rectangle r = parent.getCellRect(row, column, false);
  5490. if (r != null) {
  5491. return r.getSize();
  5492. }
  5493. }
  5494. return null;
  5495. }
  5496. public void setSize (Dimension d) {
  5497. AccessibleContext ac = getCurrentAccessibleContext();
  5498. if (ac instanceof AccessibleComponent) {
  5499. ((AccessibleComponent) ac).setSize(d);
  5500. } else {
  5501. Component c = getCurrentComponent();
  5502. if (c != null) {
  5503. c.setSize(d);
  5504. }
  5505. }
  5506. }
  5507. public Accessible getAccessibleAt(Point p) {
  5508. AccessibleContext ac = getCurrentAccessibleContext();
  5509. if (ac instanceof AccessibleComponent) {
  5510. return ((AccessibleComponent) ac).getAccessibleAt(p);
  5511. } else {
  5512. return null;
  5513. }
  5514. }
  5515. public boolean isFocusTraversable() {
  5516. AccessibleContext ac = getCurrentAccessibleContext();
  5517. if (ac instanceof AccessibleComponent) {
  5518. return ((AccessibleComponent) ac).isFocusTraversable();
  5519. } else {
  5520. Component c = getCurrentComponent();
  5521. if (c != null) {
  5522. return c.isFocusTraversable();
  5523. } else {
  5524. return false;
  5525. }
  5526. }
  5527. }
  5528. public void requestFocus() {
  5529. AccessibleContext ac = getCurrentAccessibleContext();
  5530. if (ac instanceof AccessibleComponent) {
  5531. ((AccessibleComponent) ac).requestFocus();
  5532. } else {
  5533. Component c = getCurrentComponent();
  5534. if (c != null) {
  5535. c.requestFocus();
  5536. }
  5537. }
  5538. }
  5539. public void addFocusListener(FocusListener l) {
  5540. AccessibleContext ac = getCurrentAccessibleContext();
  5541. if (ac instanceof AccessibleComponent) {
  5542. ((AccessibleComponent) ac).addFocusListener(l);
  5543. } else {
  5544. Component c = getCurrentComponent();
  5545. if (c != null) {
  5546. c.addFocusListener(l);
  5547. }
  5548. }
  5549. }
  5550. public void removeFocusListener(FocusListener l) {
  5551. AccessibleContext ac = getCurrentAccessibleContext();
  5552. if (ac instanceof AccessibleComponent) {
  5553. ((AccessibleComponent) ac).removeFocusListener(l);
  5554. } else {
  5555. Component c = getCurrentComponent();
  5556. if (c != null) {
  5557. c.removeFocusListener(l);
  5558. }
  5559. }
  5560. }
  5561. } // inner class AccessibleJTableCell
  5562. } // inner class AccessibleJTable
  5563. } // End of Class JTable