1. /*
  2. * @(#)JTable.java 1.238 04/06/28
  3. *
  4. * Copyright 2004 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.awt.print.*;
  13. import java.beans.*;
  14. import java.io.Serializable;
  15. import java.io.ObjectOutputStream;
  16. import java.io.ObjectInputStream;
  17. import java.io.IOException;
  18. import javax.accessibility.*;
  19. import javax.swing.event.*;
  20. import javax.swing.plaf.*;
  21. import javax.swing.table.*;
  22. import javax.swing.border.*;
  23. import java.text.NumberFormat;
  24. import java.text.DateFormat;
  25. import java.text.MessageFormat;
  26. import javax.print.attribute.*;
  27. /**
  28. * The <code>JTable</code> is used to display and edit regular two-dimensional tables
  29. * of cells.
  30. * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/table.html">How to Use Tables</a>
  31. * in <em>The Java Tutorial</em>
  32. * for task-oriented documentation and examples of using <code>JTable</code>.
  33. *
  34. * <p>
  35. * The <code>JTable</code> has many
  36. * facilities that make it possible to customize its rendering and editing
  37. * but provides defaults for these features so that simple tables can be
  38. * set up easily. For example, to set up a table with 10 rows and 10
  39. * columns of numbers:
  40. * <p>
  41. * <pre>
  42. * TableModel dataModel = new AbstractTableModel() {
  43. * public int getColumnCount() { return 10; }
  44. * public int getRowCount() { return 10;}
  45. * public Object getValueAt(int row, int col) { return new Integer(row*col); }
  46. * };
  47. * JTable table = new JTable(dataModel);
  48. * JScrollPane scrollpane = new JScrollPane(table);
  49. * </pre>
  50. * <p>
  51. * Note that if you wish to use a <code>JTable</code> in a standalone
  52. * view (outside of a <code>JScrollPane</code>) and want the header
  53. * displayed, you can get it using {@link #getTableHeader} and
  54. * display it separately.
  55. * <p>
  56. * When designing applications that use the <code>JTable</code> it is worth paying
  57. * close attention to the data structures that will represent the table's data.
  58. * The <code>DefaultTableModel</code> is a model implementation that
  59. * uses a <code>Vector</code> of <code>Vector</code>s of <code>Object</code>s to
  60. * store the cell values. As well as copying the data from an
  61. * application into the <code>DefaultTableModel</code>,
  62. * it is also possible to wrap the data in the methods of the
  63. * <code>TableModel</code> interface so that the data can be passed to the
  64. * <code>JTable</code> directly, as in the example above. This often results
  65. * in more efficient applications because the model is free to choose the
  66. * internal representation that best suits the data.
  67. * A good rule of thumb for deciding whether to use the <code>AbstractTableModel</code>
  68. * or the <code>DefaultTableModel</code> is to use the <code>AbstractTableModel</code>
  69. * as the base class for creating subclasses and the <code>DefaultTableModel</code>
  70. * when subclassing is not required.
  71. * <p>
  72. * The "TableExample" directory in the demo area of the source distribution
  73. * gives a number of complete examples of <code>JTable</code> usage,
  74. * covering how the <code>JTable</code> can be used to provide an
  75. * editable view of data taken from a database and how to modify
  76. * the columns in the display to use specialized renderers and editors.
  77. * <p>
  78. * The <code>JTable</code> uses integers exclusively to refer to both the rows and the columns
  79. * of the model that it displays. The <code>JTable</code> simply takes a tabular range of cells
  80. * and uses <code>getValueAt(int, int)</code> to retrieve the
  81. * values from the model during painting.
  82. * <p>
  83. * By default, columns may be rearranged in the <code>JTable</code> so that the
  84. * view's columns appear in a different order to the columns in the model.
  85. * This does not affect the implementation of the model at all: when the
  86. * columns are reordered, the <code>JTable</code> maintains the new order of the columns
  87. * internally and converts its column indices before querying the model.
  88. * <p>
  89. * So, when writing a <code>TableModel</code>, it is not necessary to listen for column
  90. * reordering events as the model will be queried in its own coordinate
  91. * system regardless of what is happening in the view.
  92. * In the examples area there is a demonstration of a sorting algorithm making
  93. * use of exactly this technique to interpose yet another coordinate system
  94. * where the order of the rows is changed, rather than the order of the columns.
  95. * <p>
  96. * J2SE 5 adds methods to <code>JTable</code> to provide convenient access to some
  97. * common printing needs. Simple new {@link #print()} methods allow for quick
  98. * and easy addition of printing support to your application. In addition, a new
  99. * {@link #getPrintable} method is available for more advanced printing needs.
  100. * <p>
  101. * As for all <code>JComponent</code> classes, you can use
  102. * {@link InputMap} and {@link ActionMap} to associate an
  103. * {@link Action} object with a {@link KeyStroke} and execute the
  104. * action under specified conditions.
  105. * <p>
  106. * <strong>Warning:</strong>
  107. * Serialized objects of this class will not be compatible with
  108. * future Swing releases. The current serialization support is
  109. * appropriate for short term storage or RMI between applications running
  110. * the same version of Swing. As of 1.4, support for long term storage
  111. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  112. * has been added to the <code>java.beans</code> package.
  113. * Please see {@link java.beans.XMLEncoder}.
  114. *
  115. *
  116. * @beaninfo
  117. * attribute: isContainer false
  118. * description: A component which displays data in a two dimensional grid.
  119. *
  120. * @version 1.238 06/28/04
  121. * @author Philip Milne
  122. * @author Shannon Hickey (printing support)
  123. */
  124. /* The first versions of the JTable, contained in Swing-0.1 through
  125. * Swing-0.4, were written by Alan Chung.
  126. */
  127. public class JTable extends JComponent implements TableModelListener, Scrollable,
  128. TableColumnModelListener, ListSelectionListener, CellEditorListener,
  129. Accessible
  130. {
  131. //
  132. // Static Constants
  133. //
  134. /**
  135. * @see #getUIClassID
  136. * @see #readObject
  137. */
  138. private static final String uiClassID = "TableUI";
  139. /** Do not adjust column widths automatically; use a scrollbar. */
  140. public static final int AUTO_RESIZE_OFF = 0;
  141. /** When a column is adjusted in the UI, adjust the next column the opposite way. */
  142. public static final int AUTO_RESIZE_NEXT_COLUMN = 1;
  143. /** During UI adjustment, change subsequent columns to preserve the total width;
  144. * this is the default behavior. */
  145. public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
  146. /** During all resize operations, apply adjustments to the last column only. */
  147. public static final int AUTO_RESIZE_LAST_COLUMN = 3;
  148. /** During all resize operations, proportionately resize all columns. */
  149. public static final int AUTO_RESIZE_ALL_COLUMNS = 4;
  150. /**
  151. * Printing modes, used in printing <code>JTable</code>s.
  152. *
  153. * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
  154. * boolean, PrintRequestAttributeSet, boolean)
  155. * @see #getPrintable
  156. * @since 1.5
  157. */
  158. public enum PrintMode {
  159. /**
  160. * Printing mode that prints the table at its current size,
  161. * spreading both columns and rows across multiple pages if necessary.
  162. */
  163. NORMAL,
  164. /**
  165. * Printing mode that scales the output smaller, if necessary,
  166. * to fit the table's entire width (and thereby all columns) on each page;
  167. * Rows are spread across multiple pages as necessary.
  168. */
  169. FIT_WIDTH
  170. }
  171. //
  172. // Instance Variables
  173. //
  174. /** The <code>TableModel</code> of the table. */
  175. protected TableModel dataModel;
  176. /** The <code>TableColumnModel</code> of the table. */
  177. protected TableColumnModel columnModel;
  178. /** The <code>ListSelectionModel</code> of the table, used to keep track of row selections. */
  179. protected ListSelectionModel selectionModel;
  180. /** The <code>TableHeader</code> working with the table. */
  181. protected JTableHeader tableHeader;
  182. /** The height in pixels of each row in the table. */
  183. protected int rowHeight;
  184. /** The height in pixels of the margin between the cells in each row. */
  185. protected int rowMargin;
  186. /** The color of the grid. */
  187. protected Color gridColor;
  188. /** The table draws horizontal lines between cells if <code>showHorizontalLines</code> is true. */
  189. protected boolean showHorizontalLines;
  190. /** The table draws vertical lines between cells if <code>showVerticalLines</code> is true. */
  191. protected boolean showVerticalLines;
  192. /**
  193. * Determines if the table automatically resizes the
  194. * width of the table's columns to take up the entire width of the
  195. * table, and how it does the resizing.
  196. */
  197. protected int autoResizeMode;
  198. /**
  199. * The table will query the <code>TableModel</code> to build the default
  200. * set of columns if this is true.
  201. */
  202. protected boolean autoCreateColumnsFromModel;
  203. /** Used by the <code>Scrollable</code> interface to determine the initial visible area. */
  204. protected Dimension preferredViewportSize;
  205. /** True if row selection is allowed in this table. */
  206. protected boolean rowSelectionAllowed;
  207. /**
  208. * Obsolete as of Java 2 platform v1.3. Please use the
  209. * <code>rowSelectionAllowed</code> property and the
  210. * <code>columnSelectionAllowed</code> property of the
  211. * <code>columnModel</code> instead. Or use the
  212. * method <code>getCellSelectionEnabled</code>.
  213. */
  214. /*
  215. * If true, both a row selection and a column selection
  216. * can be non-empty at the same time, the selected cells are the
  217. * the cells whose row and column are both selected.
  218. */
  219. protected boolean cellSelectionEnabled;
  220. /** If editing, the <code>Component</code> that is handling the editing. */
  221. transient protected Component editorComp;
  222. /**
  223. * The object that overwrites the screen real estate occupied by the
  224. * current cell and allows the user to change its contents.
  225. */
  226. transient protected TableCellEditor cellEditor;
  227. /** Identifies the column of the cell being edited. */
  228. transient protected int editingColumn;
  229. /** Identifies the row of the cell being edited. */
  230. transient protected int editingRow;
  231. /**
  232. * A table of objects that display the contents of a cell,
  233. * indexed by class as declared in <code>getColumnClass</code>
  234. * in the <code>TableModel</code> interface.
  235. */
  236. transient protected Hashtable defaultRenderersByColumnClass;
  237. /**
  238. * A table of objects that display and edit the contents of a cell,
  239. * indexed by class as declared in <code>getColumnClass</code>
  240. * in the <code>TableModel</code> interface.
  241. */
  242. transient protected Hashtable defaultEditorsByColumnClass;
  243. /** The foreground color of selected cells. */
  244. protected Color selectionForeground;
  245. /** The background color of selected cells. */
  246. protected Color selectionBackground;
  247. //
  248. // Private state
  249. //
  250. private SizeSequence rowModel;
  251. private boolean dragEnabled;
  252. private boolean surrendersFocusOnKeystroke;
  253. private PropertyChangeListener editorRemover = null;
  254. /**
  255. * The last value of getValueIsAdjusting from the column selection models
  256. * columnSelectionChanged notification. Used to test if a repaint is
  257. * needed.
  258. */
  259. private boolean columnSelectionAdjusting;
  260. /**
  261. * The last value of getValueIsAdjusting from the row selection models
  262. * valueChanged notification. Used to test if a repaint is needed.
  263. */
  264. private boolean rowSelectionAdjusting;
  265. /**
  266. * A flag to indicate whether or not the table is currently being printed.
  267. * Used by print() and prepareRenderer() to disable indication of the
  268. * selection and focused cell while printing.
  269. */
  270. private boolean isPrinting = false;
  271. /**
  272. * To communicate errors between threads during printing.
  273. */
  274. private Throwable printError;
  275. /**
  276. * True when setRowHeight(int) has been invoked.
  277. */
  278. private boolean isRowHeightSet;
  279. //
  280. // Constructors
  281. //
  282. /**
  283. * Constructs a default <code>JTable</code> that is initialized with a default
  284. * data model, a default column model, and a default selection
  285. * model.
  286. *
  287. * @see #createDefaultDataModel
  288. * @see #createDefaultColumnModel
  289. * @see #createDefaultSelectionModel
  290. */
  291. public JTable() {
  292. this(null, null, null);
  293. }
  294. /**
  295. * Constructs a <code>JTable</code> that is initialized with
  296. * <code>dm</code> as the data model, a default column model,
  297. * and a default selection model.
  298. *
  299. * @param dm the data model for the table
  300. * @see #createDefaultColumnModel
  301. * @see #createDefaultSelectionModel
  302. */
  303. public JTable(TableModel dm) {
  304. this(dm, null, null);
  305. }
  306. /**
  307. * Constructs a <code>JTable</code> that is initialized with
  308. * <code>dm</code> as the data model, <code>cm</code>
  309. * as the column model, and a default selection model.
  310. *
  311. * @param dm the data model for the table
  312. * @param cm the column model for the table
  313. * @see #createDefaultSelectionModel
  314. */
  315. public JTable(TableModel dm, TableColumnModel cm) {
  316. this(dm, cm, null);
  317. }
  318. /**
  319. * Constructs a <code>JTable</code> that is initialized with
  320. * <code>dm</code> as the data model, <code>cm</code> as the
  321. * column model, and <code>sm</code> as the selection model.
  322. * If any of the parameters are <code>null</code> this method
  323. * will initialize the table with the corresponding default model.
  324. * The <code>autoCreateColumnsFromModel</code> flag is set to false
  325. * if <code>cm</code> is non-null, otherwise it is set to true
  326. * and the column model is populated with suitable
  327. * <code>TableColumns</code> for the columns in <code>dm</code>.
  328. *
  329. * @param dm the data model for the table
  330. * @param cm the column model for the table
  331. * @param sm the row selection model for the table
  332. * @see #createDefaultDataModel
  333. * @see #createDefaultColumnModel
  334. * @see #createDefaultSelectionModel
  335. */
  336. public JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
  337. super();
  338. setLayout(null);
  339. setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
  340. JComponent.getManagingFocusForwardTraversalKeys());
  341. setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
  342. JComponent.getManagingFocusBackwardTraversalKeys());
  343. if (cm == null) {
  344. cm = createDefaultColumnModel();
  345. autoCreateColumnsFromModel = true;
  346. }
  347. setColumnModel(cm);
  348. if (sm == null) {
  349. sm = createDefaultSelectionModel();
  350. }
  351. setSelectionModel(sm);
  352. // Set the model last, that way if the autoCreatColumnsFromModel has
  353. // been set above, we will automatically populate an empty columnModel
  354. // with suitable columns for the new model.
  355. if (dm == null) {
  356. dm = createDefaultDataModel();
  357. }
  358. setModel(dm);
  359. initializeLocalVars();
  360. updateUI();
  361. }
  362. /**
  363. * Constructs a <code>JTable</code> with <code>numRows</code>
  364. * and <code>numColumns</code> of empty cells using
  365. * <code>DefaultTableModel</code>. The columns will have
  366. * names of the form "A", "B", "C", etc.
  367. *
  368. * @param numRows the number of rows the table holds
  369. * @param numColumns the number of columns the table holds
  370. * @see javax.swing.table.DefaultTableModel
  371. */
  372. public JTable(int numRows, int numColumns) {
  373. this(new DefaultTableModel(numRows, numColumns));
  374. }
  375. /**
  376. * Constructs a <code>JTable</code> to display the values in the
  377. * <code>Vector</code> of <code>Vectors</code>, <code>rowData</code>,
  378. * with column names, <code>columnNames</code>. The
  379. * <code>Vectors</code> contained in <code>rowData</code>
  380. * should contain the values for that row. In other words,
  381. * the value of the cell at row 1, column 5 can be obtained
  382. * with the following code:
  383. * <p>
  384. * <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
  385. * <p>
  386. * @param rowData the data for the new table
  387. * @param columnNames names of each column
  388. */
  389. public JTable(Vector rowData, Vector columnNames) {
  390. this(new DefaultTableModel(rowData, columnNames));
  391. }
  392. /**
  393. * Constructs a <code>JTable</code> to display the values in the two dimensional array,
  394. * <code>rowData</code>, with column names, <code>columnNames</code>.
  395. * <code>rowData</code> is an array of rows, so the value of the cell at row 1,
  396. * column 5 can be obtained with the following code:
  397. * <p>
  398. * <pre> rowData[1][5]; </pre>
  399. * <p>
  400. * All rows must be of the same length as <code>columnNames</code>.
  401. * <p>
  402. * @param rowData the data for the new table
  403. * @param columnNames names of each column
  404. */
  405. public JTable(final Object[][] rowData, final Object[] columnNames) {
  406. this(new AbstractTableModel() {
  407. public String getColumnName(int column) { return columnNames[column].toString(); }
  408. public int getRowCount() { return rowData.length; }
  409. public int getColumnCount() { return columnNames.length; }
  410. public Object getValueAt(int row, int col) { return rowData[row][col]; }
  411. public boolean isCellEditable(int row, int column) { return true; }
  412. public void setValueAt(Object value, int row, int col) {
  413. rowData[row][col] = value;
  414. fireTableCellUpdated(row, col);
  415. }
  416. });
  417. }
  418. /**
  419. * Calls the <code>configureEnclosingScrollPane</code> method.
  420. *
  421. * @see #configureEnclosingScrollPane
  422. */
  423. public void addNotify() {
  424. super.addNotify();
  425. configureEnclosingScrollPane();
  426. }
  427. /**
  428. * If this <code>JTable</code> is the <code>viewportView</code> of an enclosing <code>JScrollPane</code>
  429. * (the usual situation), configure this <code>ScrollPane</code> by, amongst other things,
  430. * installing the table's <code>tableHeader</code> as the <code>columnHeaderView</code> of the scroll pane.
  431. * When a <code>JTable</code> is added to a <code>JScrollPane</code> in the usual way,
  432. * using <code>new JScrollPane(myTable)</code>, <code>addNotify</code> is
  433. * called in the <code>JTable</code> (when the table is added to the viewport).
  434. * <code>JTable</code>'s <code>addNotify</code> method in turn calls this method,
  435. * which is protected so that this default installation procedure can
  436. * be overridden by a subclass.
  437. *
  438. * @see #addNotify
  439. */
  440. protected void configureEnclosingScrollPane() {
  441. Container p = getParent();
  442. if (p instanceof JViewport) {
  443. Container gp = p.getParent();
  444. if (gp instanceof JScrollPane) {
  445. JScrollPane scrollPane = (JScrollPane)gp;
  446. // Make certain we are the viewPort's view and not, for
  447. // example, the rowHeaderView of the scrollPane -
  448. // an implementor of fixed columns might do this.
  449. JViewport viewport = scrollPane.getViewport();
  450. if (viewport == null || viewport.getView() != this) {
  451. return;
  452. }
  453. scrollPane.setColumnHeaderView(getTableHeader());
  454. // scrollPane.getViewport().setBackingStoreEnabled(true);
  455. Border border = scrollPane.getBorder();
  456. if (border == null || border instanceof UIResource) {
  457. scrollPane.setBorder(UIManager.getBorder("Table.scrollPaneBorder"));
  458. }
  459. }
  460. }
  461. }
  462. /**
  463. * Calls the <code>unconfigureEnclosingScrollPane</code> method.
  464. *
  465. * @see #unconfigureEnclosingScrollPane
  466. */
  467. public void removeNotify() {
  468. KeyboardFocusManager.getCurrentKeyboardFocusManager().
  469. removePropertyChangeListener("permanentFocusOwner", editorRemover);
  470. editorRemover = null;
  471. unconfigureEnclosingScrollPane();
  472. super.removeNotify();
  473. }
  474. /**
  475. * Reverses the effect of <code>configureEnclosingScrollPane</code>
  476. * by replacing the <code>columnHeaderView</code> of the enclosing
  477. * scroll pane with <code>null</code>. <code>JTable</code>'s
  478. * <code>removeNotify</code> method calls
  479. * this method, which is protected so that this default uninstallation
  480. * procedure can be overridden by a subclass.
  481. *
  482. * @see #removeNotify
  483. * @see #configureEnclosingScrollPane
  484. */
  485. protected void unconfigureEnclosingScrollPane() {
  486. Container p = getParent();
  487. if (p instanceof JViewport) {
  488. Container gp = p.getParent();
  489. if (gp instanceof JScrollPane) {
  490. JScrollPane scrollPane = (JScrollPane)gp;
  491. // Make certain we are the viewPort's view and not, for
  492. // example, the rowHeaderView of the scrollPane -
  493. // an implementor of fixed columns might do this.
  494. JViewport viewport = scrollPane.getViewport();
  495. if (viewport == null || viewport.getView() != this) {
  496. return;
  497. }
  498. scrollPane.setColumnHeaderView(null);
  499. }
  500. }
  501. }
  502. void setUIProperty(String propertyName, Object value) {
  503. if (propertyName == "rowHeight") {
  504. if (!isRowHeightSet) {
  505. setRowHeight(((Number)value).intValue());
  506. isRowHeightSet = false;
  507. }
  508. return;
  509. }
  510. super.setUIProperty(propertyName, value);
  511. }
  512. //
  513. // Static Methods
  514. //
  515. /**
  516. * Equivalent to <code>new JScrollPane(aTable)</code>.
  517. *
  518. * @deprecated As of Swing version 1.0.2,
  519. * replaced by <code>new JScrollPane(aTable)</code>.
  520. */
  521. @Deprecated
  522. static public JScrollPane createScrollPaneForTable(JTable aTable) {
  523. return new JScrollPane(aTable);
  524. }
  525. //
  526. // Table Attributes
  527. //
  528. /**
  529. * Sets the <code>tableHeader</code> working with this <code>JTable</code> to <code>newHeader</code>.
  530. * It is legal to have a <code>null</code> <code>tableHeader</code>.
  531. *
  532. * @param tableHeader new tableHeader
  533. * @see #getTableHeader
  534. * @beaninfo
  535. * bound: true
  536. * description: The JTableHeader instance which renders the column headers.
  537. */
  538. public void setTableHeader(JTableHeader tableHeader) {
  539. if (this.tableHeader != tableHeader) {
  540. JTableHeader old = this.tableHeader;
  541. // Release the old header
  542. if (old != null) {
  543. old.setTable(null);
  544. }
  545. this.tableHeader = tableHeader;
  546. if (tableHeader != null) {
  547. tableHeader.setTable(this);
  548. }
  549. firePropertyChange("tableHeader", old, tableHeader);
  550. }
  551. }
  552. /**
  553. * Returns the <code>tableHeader</code> used by this <code>JTable</code>.
  554. *
  555. * @return the <code>tableHeader</code> used by this table
  556. * @see #setTableHeader
  557. */
  558. public JTableHeader getTableHeader() {
  559. return tableHeader;
  560. }
  561. /**
  562. * Sets the height, in pixels, of all cells to <code>rowHeight</code>,
  563. * revalidates, and repaints.
  564. * The height of the cells will be equal to the row height minus
  565. * the row margin.
  566. *
  567. * @param rowHeight new row height
  568. * @exception IllegalArgumentException if <code>rowHeight</code> is
  569. * less than 1
  570. * @see #getRowHeight
  571. * @beaninfo
  572. * bound: true
  573. * description: The height of the specified row.
  574. */
  575. public void setRowHeight(int rowHeight) {
  576. if (rowHeight <= 0) {
  577. throw new IllegalArgumentException("New row height less than 1");
  578. }
  579. int old = this.rowHeight;
  580. this.rowHeight = rowHeight;
  581. rowModel = null;
  582. isRowHeightSet = true;
  583. resizeAndRepaint();
  584. firePropertyChange("rowHeight", old, rowHeight);
  585. }
  586. /**
  587. * Returns the height of a table row, in pixels.
  588. * The default row height is 16.0.
  589. *
  590. * @return the height in pixels of a table row
  591. * @see #setRowHeight
  592. */
  593. public int getRowHeight() {
  594. return rowHeight;
  595. }
  596. private SizeSequence getRowModel() {
  597. if (rowModel == null) {
  598. rowModel = new SizeSequence(getRowCount(), getRowHeight());
  599. }
  600. return rowModel;
  601. }
  602. /**
  603. * Sets the height for <code>row</code> to <code>rowHeight</code>,
  604. * revalidates, and repaints. The height of the cells in this row
  605. * will be equal to the row height minus the row margin.
  606. *
  607. * @param row the row whose height is being
  608. changed
  609. * @param rowHeight new row height, in pixels
  610. * @exception IllegalArgumentException if <code>rowHeight</code> is
  611. * less than 1
  612. * @beaninfo
  613. * bound: true
  614. * description: The height in pixels of the cells in <code>row</code>
  615. */
  616. public void setRowHeight(int row, int rowHeight) {
  617. if (rowHeight <= 0) {
  618. throw new IllegalArgumentException("New row height less than 1");
  619. }
  620. getRowModel().setSize(row, rowHeight);
  621. resizeAndRepaint();
  622. }
  623. /**
  624. * Returns the height, in pixels, of the cells in <code>row</code>.
  625. * @param row the row whose height is to be returned
  626. * @return the height, in pixels, of the cells in the row
  627. */
  628. public int getRowHeight(int row) {
  629. return (rowModel == null) ? getRowHeight() : rowModel.getSize(row);
  630. }
  631. /**
  632. * Sets the amount of empty space between cells in adjacent rows.
  633. *
  634. * @param rowMargin the number of pixels between cells in a row
  635. * @see #getRowMargin
  636. * @beaninfo
  637. * bound: true
  638. * description: The amount of space between cells.
  639. */
  640. public void setRowMargin(int rowMargin) {
  641. int old = this.rowMargin;
  642. this.rowMargin = rowMargin;
  643. resizeAndRepaint();
  644. firePropertyChange("rowMargin", old, rowMargin);
  645. }
  646. /**
  647. * Gets the amount of empty space, in pixels, between cells. Equivalent to:
  648. * <code>getIntercellSpacing().height</code>.
  649. * @return the number of pixels between cells in a row
  650. *
  651. * @see #setRowMargin
  652. */
  653. public int getRowMargin() {
  654. return rowMargin;
  655. }
  656. /**
  657. * Sets the <code>rowMargin</code> and the <code>columnMargin</code> --
  658. * the height and width of the space between cells -- to
  659. * <code>intercellSpacing</code>.
  660. *
  661. * @param intercellSpacing a <code>Dimension</code>
  662. * specifying the new width
  663. * and height between cells
  664. * @see #getIntercellSpacing
  665. * @beaninfo
  666. * description: The spacing between the cells,
  667. * drawn in the background color of the JTable.
  668. */
  669. public void setIntercellSpacing(Dimension intercellSpacing) {
  670. // Set the rowMargin here and columnMargin in the TableColumnModel
  671. setRowMargin(intercellSpacing.height);
  672. getColumnModel().setColumnMargin(intercellSpacing.width);
  673. resizeAndRepaint();
  674. }
  675. /**
  676. * Returns the horizontal and vertical space between cells.
  677. * The default spacing is (1, 1), which provides room to draw the grid.
  678. *
  679. * @return the horizontal and vertical spacing between cells
  680. * @see #setIntercellSpacing
  681. */
  682. public Dimension getIntercellSpacing() {
  683. return new Dimension(getColumnModel().getColumnMargin(), rowMargin);
  684. }
  685. /**
  686. * Sets the color used to draw grid lines to <code>gridColor</code> and redisplays.
  687. * The default color is look and feel dependent.
  688. *
  689. * @param gridColor the new color of the grid lines
  690. * @exception IllegalArgumentException if <code>gridColor</code> is <code>null</code>
  691. * @see #getGridColor
  692. * @beaninfo
  693. * bound: true
  694. * description: The grid color.
  695. */
  696. public void setGridColor(Color gridColor) {
  697. if (gridColor == null) {
  698. throw new IllegalArgumentException("New color is null");
  699. }
  700. Color old = this.gridColor;
  701. this.gridColor = gridColor;
  702. firePropertyChange("gridColor", old, gridColor);
  703. // Redraw
  704. repaint();
  705. }
  706. /**
  707. * Returns the color used to draw grid lines.
  708. * The default color is look and feel dependent.
  709. *
  710. * @return the color used to draw grid lines
  711. * @see #setGridColor
  712. */
  713. public Color getGridColor() {
  714. return gridColor;
  715. }
  716. /**
  717. * Sets whether the table draws grid lines around cells.
  718. * If <code>showGrid</code> is true it does; if it is false it doesn't.
  719. * There is no <code>getShowGrid</code> method as this state is held
  720. * in two variables -- <code>showHorizontalLines</code> and <code>showVerticalLines</code> --
  721. * each of which can be queried independently.
  722. *
  723. * @param showGrid true if table view should draw grid lines
  724. *
  725. * @see #setShowVerticalLines
  726. * @see #setShowHorizontalLines
  727. * @beaninfo
  728. * description: The color used to draw the grid lines.
  729. */
  730. public void setShowGrid(boolean showGrid) {
  731. setShowHorizontalLines(showGrid);
  732. setShowVerticalLines(showGrid);
  733. // Redraw
  734. repaint();
  735. }
  736. /**
  737. * Sets whether the table draws horizontal lines between cells.
  738. * If <code>showHorizontalLines</code> is true it does; if it is false it doesn't.
  739. *
  740. * @param showHorizontalLines true if table view should draw horizontal lines
  741. * @see #getShowHorizontalLines
  742. * @see #setShowGrid
  743. * @see #setShowVerticalLines
  744. * @beaninfo
  745. * bound: true
  746. * description: Whether horizontal lines should be drawn in between the cells.
  747. */
  748. public void setShowHorizontalLines(boolean showHorizontalLines) {
  749. boolean old = this.showHorizontalLines;
  750. this.showHorizontalLines = showHorizontalLines;
  751. firePropertyChange("showHorizontalLines", old, showHorizontalLines);
  752. // Redraw
  753. repaint();
  754. }
  755. /**
  756. * Sets whether the table draws vertical lines between cells.
  757. * If <code>showVerticalLines</code> is true it does; if it is false it doesn't.
  758. *
  759. * @param showVerticalLines true if table view should draw vertical lines
  760. * @see #getShowVerticalLines
  761. * @see #setShowGrid
  762. * @see #setShowHorizontalLines
  763. * @beaninfo
  764. * bound: true
  765. * description: Whether vertical lines should be drawn in between the cells.
  766. */
  767. public void setShowVerticalLines(boolean showVerticalLines) {
  768. boolean old = this.showVerticalLines;
  769. this.showVerticalLines = showVerticalLines;
  770. firePropertyChange("showVerticalLines", old, showVerticalLines);
  771. // Redraw
  772. repaint();
  773. }
  774. /**
  775. * Returns true if the table draws horizontal lines between cells, false if it
  776. * doesn't. The default is true.
  777. *
  778. * @return true if the table draws horizontal lines between cells, false if it
  779. * doesn't
  780. * @see #setShowHorizontalLines
  781. */
  782. public boolean getShowHorizontalLines() {
  783. return showHorizontalLines;
  784. }
  785. /**
  786. * Returns true if the table draws vertical lines between cells, false if it
  787. * doesn't. The default is true.
  788. *
  789. * @return true if the table draws vertical lines between cells, false if it
  790. * doesn't
  791. * @see #setShowVerticalLines
  792. */
  793. public boolean getShowVerticalLines() {
  794. return showVerticalLines;
  795. }
  796. /**
  797. * Sets the table's auto resize mode when the table is resized.
  798. *
  799. * @param mode One of 5 legal values:
  800. * AUTO_RESIZE_OFF,
  801. * AUTO_RESIZE_NEXT_COLUMN,
  802. * AUTO_RESIZE_SUBSEQUENT_COLUMNS,
  803. * AUTO_RESIZE_LAST_COLUMN,
  804. * AUTO_RESIZE_ALL_COLUMNS
  805. *
  806. * @see #getAutoResizeMode
  807. * @see #doLayout
  808. * @beaninfo
  809. * bound: true
  810. * description: Whether the columns should adjust themselves automatically.
  811. * enum: AUTO_RESIZE_OFF JTable.AUTO_RESIZE_OFF
  812. * AUTO_RESIZE_NEXT_COLUMN JTable.AUTO_RESIZE_NEXT_COLUMN
  813. * AUTO_RESIZE_SUBSEQUENT_COLUMNS JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS
  814. * AUTO_RESIZE_LAST_COLUMN JTable.AUTO_RESIZE_LAST_COLUMN
  815. * AUTO_RESIZE_ALL_COLUMNS JTable.AUTO_RESIZE_ALL_COLUMNS
  816. */
  817. public void setAutoResizeMode(int mode) {
  818. if ((mode == AUTO_RESIZE_OFF) ||
  819. (mode == AUTO_RESIZE_NEXT_COLUMN) ||
  820. (mode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) ||
  821. (mode == AUTO_RESIZE_LAST_COLUMN) ||
  822. (mode == AUTO_RESIZE_ALL_COLUMNS)) {
  823. int old = autoResizeMode;
  824. autoResizeMode = mode;
  825. resizeAndRepaint();
  826. if (tableHeader != null) {
  827. tableHeader.resizeAndRepaint();
  828. }
  829. firePropertyChange("autoResizeMode", old, autoResizeMode);
  830. }
  831. }
  832. /**
  833. * Returns the auto resize mode of the table. The default mode
  834. * is AUTO_RESIZE_SUBSEQUENT_COLUMNS.
  835. *
  836. * @return the autoResizeMode of the table
  837. *
  838. * @see #setAutoResizeMode
  839. * @see #doLayout
  840. */
  841. public int getAutoResizeMode() {
  842. return autoResizeMode;
  843. }
  844. /**
  845. * Sets this table's <code>autoCreateColumnsFromModel</code> flag.
  846. * This method calls <code>createDefaultColumnsFromModel</code> if
  847. * <code>autoCreateColumnsFromModel</code> changes from false to true.
  848. *
  849. * @param autoCreateColumnsFromModel true if <code>JTable</code> should automatically create columns
  850. * @see #getAutoCreateColumnsFromModel
  851. * @see #createDefaultColumnsFromModel
  852. * @beaninfo
  853. * bound: true
  854. * description: Automatically populates the columnModel when a new TableModel is submitted.
  855. */
  856. public void setAutoCreateColumnsFromModel(boolean autoCreateColumnsFromModel) {
  857. if (this.autoCreateColumnsFromModel != autoCreateColumnsFromModel) {
  858. boolean old = this.autoCreateColumnsFromModel;
  859. this.autoCreateColumnsFromModel = autoCreateColumnsFromModel;
  860. if (autoCreateColumnsFromModel) {
  861. createDefaultColumnsFromModel();
  862. }
  863. firePropertyChange("autoCreateColumnsFromModel", old, autoCreateColumnsFromModel);
  864. }
  865. }
  866. /**
  867. * Determines whether the table will create default columns from the model.
  868. * If true, <code>setModel</code> will clear any existing columns and
  869. * create new columns from the new model. Also, if the event in
  870. * the <code>tableChanged</code> notification specifies that the
  871. * entire table changed, then the columns will be rebuilt.
  872. * The default is true.
  873. *
  874. * @return the autoCreateColumnsFromModel of the table
  875. * @see #setAutoCreateColumnsFromModel
  876. * @see #createDefaultColumnsFromModel
  877. */
  878. public boolean getAutoCreateColumnsFromModel() {
  879. return autoCreateColumnsFromModel;
  880. }
  881. /**
  882. * Creates default columns for the table from
  883. * the data model using the <code>getColumnCount</code> method
  884. * defined in the <code>TableModel</code> interface.
  885. * <p>
  886. * Clears any existing columns before creating the
  887. * new columns based on information from the model.
  888. *
  889. * @see #getAutoCreateColumnsFromModel
  890. */
  891. public void createDefaultColumnsFromModel() {
  892. TableModel m = getModel();
  893. if (m != null) {
  894. // Remove any current columns
  895. TableColumnModel cm = getColumnModel();
  896. while (cm.getColumnCount() > 0) {
  897. cm.removeColumn(cm.getColumn(0));
  898. }
  899. // Create new columns from the data model info
  900. for (int i = 0; i < m.getColumnCount(); i++) {
  901. TableColumn newColumn = new TableColumn(i);
  902. addColumn(newColumn);
  903. }
  904. }
  905. }
  906. /**
  907. * Sets a default cell renderer to be used if no renderer has been set in
  908. * a <code>TableColumn</code>. If renderer is <code>null</code>,
  909. * removes the default renderer for this column class.
  910. *
  911. * @param columnClass set the default cell renderer for this columnClass
  912. * @param renderer default cell renderer to be used for this
  913. * columnClass
  914. * @see #getDefaultRenderer
  915. * @see #setDefaultEditor
  916. */
  917. public void setDefaultRenderer(Class<?> columnClass, TableCellRenderer renderer) {
  918. if (renderer != null) {
  919. defaultRenderersByColumnClass.put(columnClass, renderer);
  920. }
  921. else {
  922. defaultRenderersByColumnClass.remove(columnClass);
  923. }
  924. }
  925. /**
  926. * Returns the cell renderer to be used when no renderer has been set in
  927. * a <code>TableColumn</code>. During the rendering of cells the renderer 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 renderer
  935. * for this columnClass
  936. * @return the renderer for this columnClass
  937. * @see #setDefaultRenderer
  938. * @see #getColumnClass
  939. */
  940. public TableCellRenderer getDefaultRenderer(Class<?> columnClass) {
  941. if (columnClass == null) {
  942. return null;
  943. }
  944. else {
  945. Object renderer = defaultRenderersByColumnClass.get(columnClass);
  946. if (renderer != null) {
  947. return (TableCellRenderer)renderer;
  948. }
  949. else {
  950. return getDefaultRenderer(columnClass.getSuperclass());
  951. }
  952. }
  953. }
  954. /**
  955. * Sets a default cell editor to be used if no editor has been set in
  956. * a <code>TableColumn</code>. If no editing is required in a table, or a
  957. * particular column in a table, uses the <code>isCellEditable</code>
  958. * method in the <code>TableModel</code> interface to ensure that this
  959. * <code>JTable</code> will not start an editor in these columns.
  960. * If editor is <code>null</code>, removes the default editor for this
  961. * column class.
  962. *
  963. * @param columnClass set the default cell editor for this columnClass
  964. * @param editor default cell editor to be used for this columnClass
  965. * @see TableModel#isCellEditable
  966. * @see #getDefaultEditor
  967. * @see #setDefaultRenderer
  968. */
  969. public void setDefaultEditor(Class<?> columnClass, TableCellEditor editor) {
  970. if (editor != null) {
  971. defaultEditorsByColumnClass.put(columnClass, editor);
  972. }
  973. else {
  974. defaultEditorsByColumnClass.remove(columnClass);
  975. }
  976. }
  977. /**
  978. * Returns the editor to be used when no editor has been set in
  979. * a <code>TableColumn</code>. During the editing of cells the editor is fetched from
  980. * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
  981. * there is no entry for this <code>columnClass</code> the method returns
  982. * the entry for the most specific superclass. The <code>JTable</code> installs entries
  983. * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
  984. * or replaced.
  985. *
  986. * @param columnClass return the default cell editor for this columnClass
  987. * @return the default cell editor to be used for this columnClass
  988. * @see #setDefaultEditor
  989. * @see #getColumnClass
  990. */
  991. public TableCellEditor getDefaultEditor(Class<?> columnClass) {
  992. if (columnClass == null) {
  993. return null;
  994. }
  995. else {
  996. Object editor = defaultEditorsByColumnClass.get(columnClass);
  997. if (editor != null) {
  998. return (TableCellEditor)editor;
  999. }
  1000. else {
  1001. return getDefaultEditor(columnClass.getSuperclass());
  1002. }
  1003. }
  1004. }
  1005. /**
  1006. * Sets the <code>dragEnabled</code> property,
  1007. * which must be <code>true</code> to enable
  1008. * automatic drag handling (the first part of drag and drop)
  1009. * on this component.
  1010. * The <code>transferHandler</code> property needs to be set
  1011. * to a non-<code>null</code> value for the drag to do
  1012. * anything. The default value of the <code>dragEnabled</code
  1013. * property
  1014. * is <code>false</code>.
  1015. *
  1016. * <p>
  1017. *
  1018. * When automatic drag handling is enabled,
  1019. * most look and feels begin a drag-and-drop operation
  1020. * whenever the user presses the mouse button over a selection
  1021. * and then moves the mouse a few pixels.
  1022. * Setting this property to <code>true</code>
  1023. * can therefore have a subtle effect on
  1024. * how selections behave.
  1025. *
  1026. * <p>
  1027. *
  1028. * Some look and feels might not support automatic drag and drop;
  1029. * they will ignore this property. You can work around such
  1030. * look and feels by modifying the component
  1031. * to directly call the <code>exportAsDrag</code> method of a
  1032. * <code>TransferHandler</code>.
  1033. *
  1034. * @param b the value to set the <code>dragEnabled</code> property to
  1035. * @exception HeadlessException if
  1036. * <code>b</code> is <code>true</code> and
  1037. * <code>GraphicsEnvironment.isHeadless()</code>
  1038. * returns <code>true</code>
  1039. * @see java.awt.GraphicsEnvironment#isHeadless
  1040. * @see #getDragEnabled
  1041. * @see #setTransferHandler
  1042. * @see TransferHandler
  1043. * @since 1.4
  1044. *
  1045. * @beaninfo
  1046. * description: determines whether automatic drag handling is enabled
  1047. * bound: false
  1048. */
  1049. public void setDragEnabled(boolean b) {
  1050. if (b && GraphicsEnvironment.isHeadless()) {
  1051. throw new HeadlessException();
  1052. }
  1053. dragEnabled = b;
  1054. }
  1055. /**
  1056. * Gets the value of the <code>dragEnabled</code> property.
  1057. *
  1058. * @return the value of the <code>dragEnabled</code> property
  1059. * @see #setDragEnabled
  1060. * @since 1.4
  1061. */
  1062. public boolean getDragEnabled() {
  1063. return dragEnabled;
  1064. }
  1065. //
  1066. // Selection methods
  1067. //
  1068. /**
  1069. * Sets the table's selection mode to allow only single selections, a single
  1070. * contiguous interval, or multiple intervals.
  1071. * <P>
  1072. * <bold>Note:</bold>
  1073. * <code>JTable</code> provides all the methods for handling
  1074. * column and row selection. When setting states,
  1075. * such as <code>setSelectionMode</code>, it not only
  1076. * updates the mode for the row selection model but also sets similar
  1077. * values in the selection model of the <code>columnModel</code>.
  1078. * If you want to have the row and column selection models operating
  1079. * in different modes, set them both directly.
  1080. * <p>
  1081. * Both the row and column selection models for <code>JTable</code>
  1082. * default to using a <code>DefaultListSelectionModel</code>
  1083. * so that <code>JTable</code> works the same way as the
  1084. * <code>JList</code>. See the <code>setSelectionMode</code> method
  1085. * in <code>JList</code> for details about the modes.
  1086. *
  1087. * @see JList#setSelectionMode
  1088. * @beaninfo
  1089. * description: The selection mode used by the row and column selection models.
  1090. * enum: SINGLE_SELECTION ListSelectionModel.SINGLE_SELECTION
  1091. * SINGLE_INTERVAL_SELECTION ListSelectionModel.SINGLE_INTERVAL_SELECTION
  1092. * MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
  1093. */
  1094. public void setSelectionMode(int selectionMode) {
  1095. clearSelection();
  1096. getSelectionModel().setSelectionMode(selectionMode);
  1097. getColumnModel().getSelectionModel().setSelectionMode(selectionMode);
  1098. }
  1099. /**
  1100. * Sets whether the rows in this model can be selected.
  1101. *
  1102. * @param rowSelectionAllowed true if this model will allow row selection
  1103. * @see #getRowSelectionAllowed
  1104. * @beaninfo
  1105. * bound: true
  1106. * attribute: visualUpdate true
  1107. * description: If true, an entire row is selected for each selected cell.
  1108. */
  1109. public void setRowSelectionAllowed(boolean rowSelectionAllowed) {
  1110. boolean old = this.rowSelectionAllowed;
  1111. this.rowSelectionAllowed = rowSelectionAllowed;
  1112. if (old != rowSelectionAllowed) {
  1113. repaint();
  1114. }
  1115. firePropertyChange("rowSelectionAllowed", old, rowSelectionAllowed);
  1116. }
  1117. /**
  1118. * Returns true if rows can be selected.
  1119. *
  1120. * @return true if rows can be selected, otherwise false
  1121. * @see #setRowSelectionAllowed
  1122. */
  1123. public boolean getRowSelectionAllowed() {
  1124. return rowSelectionAllowed;
  1125. }
  1126. /**
  1127. * Sets whether the columns in this model can be selected.
  1128. *
  1129. * @param columnSelectionAllowed true if this model will allow column selection
  1130. * @see #getColumnSelectionAllowed
  1131. * @beaninfo
  1132. * bound: true
  1133. * attribute: visualUpdate true
  1134. * description: If true, an entire column is selected for each selected cell.
  1135. */
  1136. public void setColumnSelectionAllowed(boolean columnSelectionAllowed) {
  1137. boolean old = columnModel.getColumnSelectionAllowed();
  1138. columnModel.setColumnSelectionAllowed(columnSelectionAllowed);
  1139. if (old != columnSelectionAllowed) {
  1140. repaint();
  1141. }
  1142. firePropertyChange("columnSelectionAllowed", old, columnSelectionAllowed);
  1143. }
  1144. /**
  1145. * Returns true if columns can be selected.
  1146. *
  1147. * @return true if columns can be selected, otherwise false
  1148. * @see #setColumnSelectionAllowed
  1149. */
  1150. public boolean getColumnSelectionAllowed() {
  1151. return columnModel.getColumnSelectionAllowed();
  1152. }
  1153. /**
  1154. * Sets whether this table allows both a column selection and a
  1155. * row selection to exist simultaneously. When set,
  1156. * the table treats the intersection of the row and column selection
  1157. * models as the selected cells. Override <code>isCellSelected</code> to
  1158. * change this default behavior. This method is equivalent to setting
  1159. * both the <code>rowSelectionAllowed</code> property and
  1160. * <code>columnSelectionAllowed</code> property of the
  1161. * <code>columnModel</code> to the supplied value.
  1162. *
  1163. * @param cellSelectionEnabled true if simultaneous row and column
  1164. * selection is allowed
  1165. * @see #getCellSelectionEnabled
  1166. * @see #isCellSelected
  1167. * @beaninfo
  1168. * bound: true
  1169. * attribute: visualUpdate true
  1170. * description: Select a rectangular region of cells rather than
  1171. * rows or columns.
  1172. */
  1173. public void setCellSelectionEnabled(boolean cellSelectionEnabled) {
  1174. setRowSelectionAllowed(cellSelectionEnabled);
  1175. setColumnSelectionAllowed(cellSelectionEnabled);
  1176. boolean old = this.cellSelectionEnabled;
  1177. this.cellSelectionEnabled = cellSelectionEnabled;
  1178. firePropertyChange("cellSelectionEnabled", old, cellSelectionEnabled);
  1179. }
  1180. /**
  1181. * Returns true if both row and column selection models are enabled.
  1182. * Equivalent to <code>getRowSelectionAllowed() &&
  1183. * getColumnSelectionAllowed()</code>.
  1184. *
  1185. * @return true if both row and column selection models are enabled
  1186. *
  1187. * @see #setCellSelectionEnabled
  1188. */
  1189. public boolean getCellSelectionEnabled() {
  1190. return getRowSelectionAllowed() && getColumnSelectionAllowed();
  1191. }
  1192. /**
  1193. * Selects all rows, columns, and cells in the table.
  1194. */
  1195. public void selectAll() {
  1196. // If I'm currently editing, then I should stop editing
  1197. if (isEditing()) {
  1198. removeEditor();
  1199. }
  1200. if (getRowCount() > 0 && getColumnCount() > 0) {
  1201. int oldLead;
  1202. int oldAnchor;
  1203. ListSelectionModel selModel;
  1204. selModel = selectionModel;
  1205. selModel.setValueIsAdjusting(true);
  1206. oldLead = selModel.getLeadSelectionIndex();
  1207. oldAnchor = selModel.getAnchorSelectionIndex();
  1208. setRowSelectionInterval(0, getRowCount()-1);
  1209. // this is done only to restore the anchor and lead
  1210. selModel.addSelectionInterval(oldAnchor, oldLead);
  1211. selModel.setValueIsAdjusting(false);
  1212. selModel = columnModel.getSelectionModel();
  1213. selModel.setValueIsAdjusting(true);
  1214. oldLead = selModel.getLeadSelectionIndex();
  1215. oldAnchor = selModel.getAnchorSelectionIndex();
  1216. setColumnSelectionInterval(0, getColumnCount()-1);
  1217. // this is done only to restore the anchor and lead
  1218. selModel.addSelectionInterval(oldAnchor, oldLead);
  1219. selModel.setValueIsAdjusting(false);
  1220. }
  1221. }
  1222. /**
  1223. * Deselects all selected columns and rows.
  1224. */
  1225. public void clearSelection() {
  1226. selectionModel.clearSelection();
  1227. columnModel.getSelectionModel().clearSelection();
  1228. }
  1229. private int boundRow(int row) throws IllegalArgumentException {
  1230. if (row < 0 || row >= getRowCount()) {
  1231. throw new IllegalArgumentException("Row index out of range");
  1232. }
  1233. return row;
  1234. }
  1235. private int boundColumn(int col) {
  1236. if (col< 0 || col >= getColumnCount()) {
  1237. throw new IllegalArgumentException("Column index out of range");
  1238. }
  1239. return col;
  1240. }
  1241. /**
  1242. * Selects the rows from <code>index0</code> to <code>index1</code>,
  1243. * inclusive.
  1244. *
  1245. * @exception IllegalArgumentException if <code>index0</code> or
  1246. * <code>index1</code> lie outside
  1247. * [0, <code>getRowCount()</code>-1]
  1248. * @param index0 one end of the interval
  1249. * @param index1 the other end of the interval
  1250. */
  1251. public void setRowSelectionInterval(int index0, int index1) {
  1252. selectionModel.setSelectionInterval(boundRow(index0), boundRow(index1));
  1253. }
  1254. /**
  1255. * Selects the columns from <code>index0</code> to <code>index1</code>,
  1256. * inclusive.
  1257. *
  1258. * @exception IllegalArgumentException if <code>index0</code> or
  1259. * <code>index1</code> lie outside
  1260. * [0, <code>getColumnCount()</code>-1]
  1261. * @param index0 one end of the interval
  1262. * @param index1 the other end of the interval
  1263. */
  1264. public void setColumnSelectionInterval(int index0, int index1) {
  1265. columnModel.getSelectionModel().setSelectionInterval(boundColumn(index0), boundColumn(index1));
  1266. }
  1267. /**
  1268. * Adds the rows from <code>index0</code> to <code>index1</code>, inclusive, to
  1269. * the current selection.
  1270. *
  1271. * @exception IllegalArgumentException if <code>index0</code> or <code>index1</code>
  1272. * lie outside [0, <code>getRowCount()</code>-1]
  1273. * @param index0 one end of the interval
  1274. * @param index1 the other end of the interval
  1275. */
  1276. public void addRowSelectionInterval(int index0, int index1) {
  1277. selectionModel.addSelectionInterval(boundRow(index0), boundRow(index1));
  1278. }
  1279. /**
  1280. * Adds the columns from <code>index0</code> to <code>index1</code>,
  1281. * inclusive, to the current selection.
  1282. *
  1283. * @exception IllegalArgumentException if <code>index0</code> or
  1284. * <code>index1</code> lie outside
  1285. * [0, <code>getColumnCount()</code>-1]
  1286. * @param index0 one end of the interval
  1287. * @param index1 the other end of the interval
  1288. */
  1289. public void addColumnSelectionInterval(int index0, int index1) {
  1290. columnModel.getSelectionModel().addSelectionInterval(boundColumn(index0), boundColumn(index1));
  1291. }
  1292. /**
  1293. * Deselects the rows from <code>index0</code> to <code>index1</code>, inclusive.
  1294. *
  1295. * @exception IllegalArgumentException if <code>index0</code> or
  1296. * <code>index1</code> lie outside
  1297. * [0, <code>getRowCount()</code>-1]
  1298. * @param index0 one end of the interval
  1299. * @param index1 the other end of the interval
  1300. */
  1301. public void removeRowSelectionInterval(int index0, int index1) {
  1302. selectionModel.removeSelectionInterval(boundRow(index0), boundRow(index1));
  1303. }
  1304. /**
  1305. * Deselects the columns from <code>index0</code> to <code>index1</code>, inclusive.
  1306. *
  1307. * @exception IllegalArgumentException if <code>index0</code> or
  1308. * <code>index1</code> lie outside
  1309. * [0, <code>getColumnCount()</code>-1]
  1310. * @param index0 one end of the interval
  1311. * @param index1 the other end of the interval
  1312. */
  1313. public void removeColumnSelectionInterval(int index0, int index1) {
  1314. columnModel.getSelectionModel().removeSelectionInterval(boundColumn(index0), boundColumn(index1));
  1315. }
  1316. /**
  1317. * Returns the index of the first selected row, -1 if no row is selected.
  1318. * @return the index of the first selected row
  1319. */
  1320. public int getSelectedRow() {
  1321. return selectionModel.getMinSelectionIndex();
  1322. }
  1323. /**
  1324. * Returns the index of the first selected column,
  1325. * -1 if no column is selected.
  1326. * @return the index of the first selected column
  1327. */
  1328. public int getSelectedColumn() {
  1329. return columnModel.getSelectionModel().getMinSelectionIndex();
  1330. }
  1331. /**
  1332. * Returns the indices of all selected rows.
  1333. *
  1334. * @return an array of integers containing the indices of all selected rows,
  1335. * or an empty array if no row is selected
  1336. * @see #getSelectedRow
  1337. */
  1338. public int[] getSelectedRows() {
  1339. int iMin = selectionModel.getMinSelectionIndex();
  1340. int iMax = selectionModel.getMaxSelectionIndex();
  1341. if ((iMin == -1) || (iMax == -1)) {
  1342. return new int[0];
  1343. }
  1344. int[] rvTmp = new int[1+ (iMax - iMin)];
  1345. int n = 0;
  1346. for(int i = iMin; i <= iMax; i++) {
  1347. if (selectionModel.isSelectedIndex(i)) {
  1348. rvTmp[n++] = i;
  1349. }
  1350. }
  1351. int[] rv = new int[n];
  1352. System.arraycopy(rvTmp, 0, rv, 0, n);
  1353. return rv;
  1354. }
  1355. /**
  1356. * Returns the indices of all selected columns.
  1357. *
  1358. * @return an array of integers containing the indices of all selected columns,
  1359. * or an empty array if no column is selected
  1360. * @see #getSelectedColumn
  1361. */
  1362. public int[] getSelectedColumns() {
  1363. return columnModel.getSelectedColumns();
  1364. }
  1365. /**
  1366. * Returns the number of selected rows.
  1367. *
  1368. * @return the number of selected rows, 0 if no rows are selected
  1369. */
  1370. public int getSelectedRowCount() {
  1371. int iMin = selectionModel.getMinSelectionIndex();
  1372. int iMax = selectionModel.getMaxSelectionIndex();
  1373. int count = 0;
  1374. for(int i = iMin; i <= iMax; i++) {
  1375. if (selectionModel.isSelectedIndex(i)) {
  1376. count++;
  1377. }
  1378. }
  1379. return count;
  1380. }
  1381. /**
  1382. * Returns the number of selected columns.
  1383. *
  1384. * @return the number of selected columns, 0 if no columns are selected
  1385. */
  1386. public int getSelectedColumnCount() {
  1387. return columnModel.getSelectedColumnCount();
  1388. }
  1389. /**
  1390. * Returns true if the specified index is in the valid range of rows,
  1391. * and the row at that index is selected.
  1392. *
  1393. * @return true if <code>row</code> is a valid index and the row at
  1394. * that index is selected (where 0 is the first row)
  1395. */
  1396. public boolean isRowSelected(int row) {
  1397. return selectionModel.isSelectedIndex(row);
  1398. }
  1399. /**
  1400. * Returns true if the specified index is in the valid range of columns,
  1401. * and the column at that index is selected.
  1402. *
  1403. * @param column the column in the column model
  1404. * @return true if <code>column</code> is a valid index and the column at
  1405. * that index is selected (where 0 is the first column)
  1406. */
  1407. public boolean isColumnSelected(int column) {
  1408. return columnModel.getSelectionModel().isSelectedIndex(column);
  1409. }
  1410. /**
  1411. * Returns true if the specified indices are in the valid range of rows
  1412. * and columns and the cell at the specified position is selected.
  1413. * @param row the row being queried
  1414. * @param column the column being queried
  1415. *
  1416. * @return true if <code>row</code> and <code>column</code> are valid indices
  1417. * and the cell at index <code>(row, column)</code> is selected,
  1418. * where the first row and first column are at index 0
  1419. */
  1420. public boolean isCellSelected(int row, int column) {
  1421. if (!getRowSelectionAllowed() && !getColumnSelectionAllowed()) {
  1422. return false;
  1423. }
  1424. return (!getRowSelectionAllowed() || isRowSelected(row)) &&
  1425. (!getColumnSelectionAllowed() || isColumnSelected(column));
  1426. }
  1427. private void changeSelectionModel(ListSelectionModel sm, int index,
  1428. boolean toggle, boolean extend, boolean selected) {
  1429. if (extend) {
  1430. if (toggle) {
  1431. sm.setAnchorSelectionIndex(index);
  1432. }
  1433. else {
  1434. sm.setSelectionInterval(sm.getAnchorSelectionIndex(), index);
  1435. }
  1436. }
  1437. else {
  1438. if (toggle) {
  1439. if (selected) {
  1440. sm.removeSelectionInterval(index, index);
  1441. }
  1442. else {
  1443. sm.addSelectionInterval(index, index);
  1444. }
  1445. }
  1446. else {
  1447. sm.setSelectionInterval(index, index);
  1448. }
  1449. }
  1450. }
  1451. /**
  1452. * Updates the selection models of the table, depending on the state of the
  1453. * two flags: <code>toggle</code> and <code>extend</code>. Most changes
  1454. * to the selection that are the result of keyboard or mouse events received
  1455. * by the UI are channeled through this method so that the behavior may be
  1456. * overridden by a subclass. Some UIs may need more functionality than
  1457. * this method provides, such as when manipulating the lead for discontiguous
  1458. * selection, and may not call into this method for some selection changes.
  1459. * <p>
  1460. * This implementation uses the following conventions:
  1461. * <ul>
  1462. * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>false</em>.
  1463. * Clear the previous selection and ensure the new cell is selected.
  1464. * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>true</em>.
  1465. * Extend the previous selection from the anchor to the specified cell,
  1466. * clearing all other selections.
  1467. * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>false</em>.
  1468. * If the specified cell is selected, deselect it. If it is not selected, select it.
  1469. * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>true</em>.
  1470. * Leave the selection state as it is, but move the anchor index to the specified location.
  1471. * </ul>
  1472. * @param rowIndex affects the selection at <code>row</code>
  1473. * @param columnIndex affects the selection at <code>column</code>
  1474. * @param toggle see description above
  1475. * @param extend if true, extend the current selection
  1476. *
  1477. */
  1478. public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
  1479. ListSelectionModel rsm = getSelectionModel();
  1480. ListSelectionModel csm = getColumnModel().getSelectionModel();
  1481. // Check the selection here rather than in each selection model.
  1482. // This is significant in cell selection mode if we are supposed
  1483. // to be toggling the selection. In this case it is better to
  1484. // ensure that the cell's selection state will indeed be changed.
  1485. // If this were done in the code for the selection model it
  1486. // might leave a cell in selection state if the row was
  1487. // selected but the column was not - as it would toggle them both.
  1488. boolean selected = isCellSelected(rowIndex, columnIndex);
  1489. changeSelectionModel(csm, columnIndex, toggle, extend, selected);
  1490. changeSelectionModel(rsm, rowIndex, toggle, extend, selected);
  1491. // Scroll after changing the selection as blit scrolling is immediate,
  1492. // so that if we cause the repaint after the scroll we end up painting
  1493. // everything!
  1494. if (getAutoscrolls()) {
  1495. Rectangle cellRect = getCellRect(rowIndex, columnIndex, false);
  1496. if (cellRect != null) {
  1497. scrollRectToVisible(cellRect);
  1498. }
  1499. }
  1500. }
  1501. /**
  1502. * Returns the foreground color for selected cells.
  1503. *
  1504. * @return the <code>Color</code> object for the foreground property
  1505. * @see #setSelectionForeground
  1506. * @see #setSelectionBackground
  1507. */
  1508. public Color getSelectionForeground() {
  1509. return selectionForeground;
  1510. }
  1511. /**
  1512. * Sets the foreground color for selected cells. Cell renderers
  1513. * can use this color to render text and graphics for selected
  1514. * cells.
  1515. * <p>
  1516. * The default value of this property is defined by the look
  1517. * and feel implementation.
  1518. * <p>
  1519. * This is a <a href="http://java.sun.com/docs/books/tutorial/javabeans/whatis/beanDefinition.html">JavaBeans</a> bound property.
  1520. *
  1521. * @param selectionForeground the <code>Color</code> to use in the foreground
  1522. * for selected list items
  1523. * @see #getSelectionForeground
  1524. * @see #setSelectionBackground
  1525. * @see #setForeground
  1526. * @see #setBackground
  1527. * @see #setFont
  1528. * @beaninfo
  1529. * bound: true
  1530. * description: A default foreground color for selected cells.
  1531. */
  1532. public void setSelectionForeground(Color selectionForeground) {
  1533. Color old = this.selectionForeground;
  1534. this.selectionForeground = selectionForeground;
  1535. firePropertyChange("selectionForeground", old, selectionForeground);
  1536. if ( !selectionForeground.equals(old) )
  1537. {
  1538. repaint();
  1539. }
  1540. }
  1541. /**
  1542. * Returns the background color for selected cells.
  1543. *
  1544. * @return the <code>Color</code> used for the background of selected list items
  1545. * @see #setSelectionBackground
  1546. * @see #setSelectionForeground
  1547. */
  1548. public Color getSelectionBackground() {
  1549. return selectionBackground;
  1550. }
  1551. /**
  1552. * Sets the background color for selected cells. Cell renderers
  1553. * can use this color to the fill selected cells.
  1554. * <p>
  1555. * The default value of this property is defined by the look
  1556. * and feel implementation.
  1557. * <p>
  1558. * This is a <a href="http://java.sun.com/docs/books/tutorial/javabeans/whatis/beanDefinition.html">JavaBeans</a> bound property.
  1559. *
  1560. * @param selectionBackground the <code>Color</code> to use for the background
  1561. * of selected cells
  1562. * @see #getSelectionBackground
  1563. * @see #setSelectionForeground
  1564. * @see #setForeground
  1565. * @see #setBackground
  1566. * @see #setFont
  1567. * @beaninfo
  1568. * bound: true
  1569. * description: A default background color for selected cells.
  1570. */
  1571. public void setSelectionBackground(Color selectionBackground) {
  1572. Color old = this.selectionBackground;
  1573. this.selectionBackground = selectionBackground;
  1574. firePropertyChange("selectionBackground", old, selectionBackground);
  1575. if ( !selectionBackground.equals(old) )
  1576. {
  1577. repaint();
  1578. }
  1579. }
  1580. /**
  1581. * Returns the <code>TableColumn</code> object for the column in the table
  1582. * whose identifier is equal to <code>identifier</code>, when compared using
  1583. * <code>equals</code>.
  1584. *
  1585. * @return the <code>TableColumn</code> object that matches the identifier
  1586. * @exception IllegalArgumentException if <code>identifier</code> is <code>null</code> or no <code>TableColumn</code> has this identifier
  1587. *
  1588. * @param identifier the identifier object
  1589. */
  1590. public TableColumn getColumn(Object identifier) {
  1591. TableColumnModel cm = getColumnModel();
  1592. int columnIndex = cm.getColumnIndex(identifier);
  1593. return cm.getColumn(columnIndex);
  1594. }
  1595. //
  1596. // Informally implement the TableModel interface.
  1597. //
  1598. /**
  1599. * Maps the index of the column in the view at
  1600. * <code>viewColumnIndex</code> to the index of the column
  1601. * in the table model. Returns the index of the corresponding
  1602. * column in the model. If <code>viewColumnIndex</code>
  1603. * is less than zero, returns <code>viewColumnIndex</code>.
  1604. *
  1605. * @param viewColumnIndex the index of the column in the view
  1606. * @return the index of the corresponding column in the model
  1607. *
  1608. * @see #convertColumnIndexToView
  1609. */
  1610. public int convertColumnIndexToModel(int viewColumnIndex) {
  1611. if (viewColumnIndex < 0) {
  1612. return viewColumnIndex;
  1613. }
  1614. return getColumnModel().getColumn(viewColumnIndex).getModelIndex();
  1615. }
  1616. /**
  1617. * Maps the index of the column in the table model at
  1618. * <code>modelColumnIndex</code> to the index of the column
  1619. * in the view. Returns the index of the
  1620. * corresponding column in the view; returns -1 if this column is not
  1621. * being displayed. If <code>modelColumnIndex</code> is less than zero,
  1622. * returns <code>modelColumnIndex</code>.
  1623. *
  1624. * @param modelColumnIndex the index of the column in the model
  1625. * @return the index of the corresponding column in the view
  1626. *
  1627. * @see #convertColumnIndexToModel
  1628. */
  1629. public int convertColumnIndexToView(int modelColumnIndex) {
  1630. if (modelColumnIndex < 0) {
  1631. return modelColumnIndex;
  1632. }
  1633. TableColumnModel cm = getColumnModel();
  1634. for (int column = 0; column < getColumnCount(); column++) {
  1635. if (cm.getColumn(column).getModelIndex() == modelColumnIndex) {
  1636. return column;
  1637. }
  1638. }
  1639. return -1;
  1640. }
  1641. /**
  1642. * Returns the number of rows in this table's model.
  1643. * @return the number of rows in this table's model
  1644. *
  1645. * @see #getColumnCount
  1646. */
  1647. public int getRowCount() {
  1648. return getModel().getRowCount();
  1649. }
  1650. /**
  1651. * Returns the number of columns in the column model. Note that this may
  1652. * be different from the number of columns in the table model.
  1653. *
  1654. * @return the number of columns in the table
  1655. * @see #getRowCount
  1656. * @see #removeColumn
  1657. */
  1658. public int getColumnCount() {
  1659. return getColumnModel().getColumnCount();
  1660. }
  1661. /**
  1662. * Returns the name of the column appearing in the view at
  1663. * column position <code>column</code>.
  1664. *
  1665. * @param column the column in the view being queried
  1666. * @return the name of the column at position <code>column</code>
  1667. in the view where the first column is column 0
  1668. */
  1669. public String getColumnName(int column) {
  1670. return getModel().getColumnName(convertColumnIndexToModel(column));
  1671. }
  1672. /**
  1673. * Returns the type of the column appearing in the view at
  1674. * column position <code>column</code>.
  1675. *
  1676. * @param column the column in the view being queried
  1677. * @return the type of the column at position <code>column</code>
  1678. * in the view where the first column is column 0
  1679. */
  1680. public Class<?> getColumnClass(int column) {
  1681. return getModel().getColumnClass(convertColumnIndexToModel(column));
  1682. }
  1683. /**
  1684. * Returns the cell value at <code>row</code> and <code>column</code>.
  1685. * <p>
  1686. * <b>Note</b>: The column is specified in the table view's display
  1687. * order, and not in the <code>TableModel</code>'s column
  1688. * order. This is an important distinction because as the
  1689. * user rearranges the columns in the table,
  1690. * the column at a given index in the view will change.
  1691. * Meanwhile the user's actions never affect the model's
  1692. * column ordering.
  1693. *
  1694. * @param row the row whose value is to be queried
  1695. * @param column the column whose value is to be queried
  1696. * @return the Object at the specified cell
  1697. */
  1698. public Object getValueAt(int row, int column) {
  1699. return getModel().getValueAt(row, convertColumnIndexToModel(column));
  1700. }
  1701. /**
  1702. * Sets the value for the cell in the table model at <code>row</code>
  1703. * and <code>column</code>.
  1704. * <p>
  1705. * <b>Note</b>: The column is specified in the table view's display
  1706. * order, and not in the <code>TableModel</code>'s column
  1707. * order. This is an important distinction because as the
  1708. * user rearranges the columns in the table,
  1709. * the column at a given index in the view will change.
  1710. * Meanwhile the user's actions never affect the model's
  1711. * column ordering.
  1712. *
  1713. * <code>aValue</code> is the new value.
  1714. *
  1715. * @param aValue the new value
  1716. * @param row the row of the cell to be changed
  1717. * @param column the column of the cell to be changed
  1718. * @see #getValueAt
  1719. */
  1720. public void setValueAt(Object aValue, int row, int column) {
  1721. getModel().setValueAt(aValue, row, convertColumnIndexToModel(column));
  1722. }
  1723. /**
  1724. * Returns true if the cell at <code>row</code> and <code>column</code>
  1725. * is editable. Otherwise, invoking <code>setValueAt</code> on the cell
  1726. * will have no effect.
  1727. * <p>
  1728. * <b>Note</b>: The column is specified in the table view's display
  1729. * order, and not in the <code>TableModel</code>'s column
  1730. * order. This is an important distinction because as the
  1731. * user rearranges the columns in the table,
  1732. * the column at a given index in the view will change.
  1733. * Meanwhile the user's actions never affect the model's
  1734. * column ordering.
  1735. *
  1736. *
  1737. * @param row the row whose value is to be queried
  1738. * @param column the column whose value is to be queried
  1739. * @return true if the cell is editable
  1740. * @see #setValueAt
  1741. */
  1742. public boolean isCellEditable(int row, int column) {
  1743. return getModel().isCellEditable(row, convertColumnIndexToModel(column));
  1744. }
  1745. //
  1746. // Adding and removing columns in the view
  1747. //
  1748. /**
  1749. * Appends <code>aColumn</code> to the end of the array of columns held by
  1750. * this <code>JTable</code>'s column model.
  1751. * If the column name of <code>aColumn</code> is <code>null</code>,
  1752. * sets the column name of <code>aColumn</code> to the name
  1753. * returned by <code>getModel().getColumnName()</code>.
  1754. * <p>
  1755. * To add a column to this <code>JTable</code> to display the
  1756. * <code>modelColumn</code>'th column of data in the model with a
  1757. * given <code>width</code>, <code>cellRenderer</code>,
  1758. * and <code>cellEditor</code> you can use:
  1759. * <pre>
  1760. *
  1761. * addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
  1762. *
  1763. * </pre>
  1764. * [Any of the <code>TableColumn</code> constructors can be used
  1765. * instead of this one.]
  1766. * The model column number is stored inside the <code>TableColumn</code>
  1767. * and is used during rendering and editing to locate the appropriates
  1768. * data values in the model. The model column number does not change
  1769. * when columns are reordered in the view.
  1770. *
  1771. * @param aColumn the <code>TableColumn</code> to be added
  1772. * @see #removeColumn
  1773. */
  1774. public void addColumn(TableColumn aColumn) {
  1775. if (aColumn.getHeaderValue() == null) {
  1776. int modelColumn = aColumn.getModelIndex();
  1777. String columnName = getModel().getColumnName(modelColumn);
  1778. aColumn.setHeaderValue(columnName);
  1779. }
  1780. getColumnModel().addColumn(aColumn);
  1781. }
  1782. /**
  1783. * Removes <code>aColumn</code> from this <code>JTable</code>'s
  1784. * array of columns. Note: this method does not remove the column
  1785. * of data from the model; it just removes the <code>TableColumn</code>
  1786. * that was responsible for displaying it.
  1787. *
  1788. * @param aColumn the <code>TableColumn</code> to be removed
  1789. * @see #addColumn
  1790. */
  1791. public void removeColumn(TableColumn aColumn) {
  1792. getColumnModel().removeColumn(aColumn);
  1793. }
  1794. /**
  1795. * Moves the column <code>column</code> to the position currently
  1796. * occupied by the column <code>targetColumn</code> in the view.
  1797. * The old column at <code>targetColumn</code> is
  1798. * shifted left or right to make room.
  1799. *
  1800. * @param column the index of column to be moved
  1801. * @param targetColumn the new index of the column
  1802. */
  1803. public void moveColumn(int column, int targetColumn) {
  1804. getColumnModel().moveColumn(column, targetColumn);
  1805. }
  1806. //
  1807. // Cover methods for various models and helper methods
  1808. //
  1809. /**
  1810. * Returns the index of the column that <code>point</code> lies in,
  1811. * or -1 if the result is not in the range
  1812. * [0, <code>getColumnCount()</code>-1].
  1813. *
  1814. * @param point the location of interest
  1815. * @return the index of the column that <code>point</code> lies in,
  1816. * or -1 if the result is not in the range
  1817. * [0, <code>getColumnCount()</code>-1]
  1818. * @see #rowAtPoint
  1819. */
  1820. public int columnAtPoint(Point point) {
  1821. int x = point.x;
  1822. if( !getComponentOrientation().isLeftToRight() ) {
  1823. x = getWidth() - x;
  1824. }
  1825. return getColumnModel().getColumnIndexAtX(x);
  1826. }
  1827. /**
  1828. * Returns the index of the row that <code>point</code> lies in,
  1829. * or -1 if the result is not in the range
  1830. * [0, <code>getRowCount()</code>-1].
  1831. *
  1832. * @param point the location of interest
  1833. * @return the index of the row that <code>point</code> lies in,
  1834. * or -1 if the result is not in the range
  1835. * [0, <code>getRowCount()</code>-1]
  1836. * @see #columnAtPoint
  1837. */
  1838. public int rowAtPoint(Point point) {
  1839. int y = point.y;
  1840. int result = (rowModel == null) ? ygetRowHeight() : rowModel.getIndex(y);
  1841. if (result < 0) {
  1842. return -1;
  1843. }
  1844. else if (result >= getRowCount()) {
  1845. return -1;
  1846. }
  1847. else {
  1848. return result;
  1849. }
  1850. }
  1851. /**
  1852. * Returns a rectangle for the cell that lies at the intersection of
  1853. * <code>row</code> and <code>column</code>.
  1854. * If <code>includeSpacing</code> is true then the value returned
  1855. * has the full height and width of the row and column
  1856. * specified. If it is false, the returned rectangle is inset by the
  1857. * intercell spacing to return the true bounds of the rendering or
  1858. * editing component as it will be set during rendering.
  1859. * <p>
  1860. * If the column index is valid but the row index is less
  1861. * than zero the method returns a rectangle with the
  1862. * <code>y</code> and <code>height</code> values set appropriately
  1863. * and the <code>x</code> and <code>width</code> values both set
  1864. * to zero. In general, when either the row or column indices indicate a
  1865. * cell outside the appropriate range, the method returns a rectangle
  1866. * depicting the closest edge of the closest cell that is within
  1867. * the table's range. When both row and column indices are out
  1868. * of range the returned rectangle covers the closest
  1869. * point of the closest cell.
  1870. * <p>
  1871. * In all cases, calculations that use this method to calculate
  1872. * results along one axis will not fail because of anomalies in
  1873. * calculations along the other axis. When the cell is not valid
  1874. * the <code>includeSpacing</code> parameter is ignored.
  1875. *
  1876. * @param row the row index where the desired cell
  1877. * is located
  1878. * @param column the column index where the desired cell
  1879. * is located in the display; this is not
  1880. * necessarily the same as the column index
  1881. * in the data model for the table; the
  1882. * {@link #convertColumnIndexToView(int)}
  1883. * method may be used to convert a data
  1884. * model column index to a display
  1885. * column index
  1886. * @param includeSpacing if false, return the true cell bounds -
  1887. * computed by subtracting the intercell
  1888. * spacing from the height and widths of
  1889. * the column and row models
  1890. *
  1891. * @return the rectangle containing the cell at location
  1892. * <code>row</code>,<code>column</code>
  1893. */
  1894. public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
  1895. Rectangle r = new Rectangle();
  1896. boolean valid = true;
  1897. if (row < 0) {
  1898. // y = height = 0;
  1899. valid = false;
  1900. }
  1901. else if (row >= getRowCount()) {
  1902. r.y = getHeight();
  1903. valid = false;
  1904. }
  1905. else {
  1906. r.height = getRowHeight(row);
  1907. r.y = (rowModel == null) ? row * r.height : rowModel.getPosition(row);
  1908. }
  1909. if (column < 0) {
  1910. if( !getComponentOrientation().isLeftToRight() ) {
  1911. r.x = getWidth();
  1912. }
  1913. // otherwise, x = width = 0;
  1914. valid = false;
  1915. }
  1916. else if (column >= getColumnCount()) {
  1917. if( getComponentOrientation().isLeftToRight() ) {
  1918. r.x = getWidth();
  1919. }
  1920. // otherwise, x = width = 0;
  1921. valid = false;
  1922. }
  1923. else {
  1924. TableColumnModel cm = getColumnModel();
  1925. if( getComponentOrientation().isLeftToRight() ) {
  1926. for(int i = 0; i < column; i++) {
  1927. r.x += cm.getColumn(i).getWidth();
  1928. }
  1929. } else {
  1930. for(int i = cm.getColumnCount()-1; i > column; i--) {
  1931. r.x += cm.getColumn(i).getWidth();
  1932. }
  1933. }
  1934. r.width = cm.getColumn(column).getWidth();
  1935. }
  1936. if (valid && !includeSpacing) {
  1937. int rm = getRowMargin();
  1938. int cm = getColumnModel().getColumnMargin();
  1939. // This is not the same as grow(), it rounds differently.
  1940. r.setBounds(r.x + cm2, r.y + rm2, r.width - cm, r.height - rm);
  1941. }
  1942. return r;
  1943. }
  1944. private int viewIndexForColumn(TableColumn aColumn) {
  1945. TableColumnModel cm = getColumnModel();
  1946. for (int column = 0; column < cm.getColumnCount(); column++) {
  1947. if (cm.getColumn(column) == aColumn) {
  1948. return column;
  1949. }
  1950. }
  1951. return -1;
  1952. }
  1953. /**
  1954. * Causes this table to lay out its rows and columns. Overridden so
  1955. * that columns can be resized to accomodate a change in the size of
  1956. * a containing parent.
  1957. * Resizes one or more of the columns in the table
  1958. * so that the total width of all of this <code>JTable</code>'s
  1959. * columns is equal to the width of the table.
  1960. * <p>
  1961. * Before the layout begins the method gets the
  1962. * <code>resizingColumn</code> of the <code>tableHeader</code>.
  1963. * When the method is called as a result of the resizing of an enclosing window,
  1964. * the <code>resizingColumn</code> is <code>null</code>. This means that resizing
  1965. * has taken place "outside" the <code>JTable</code> and the change -
  1966. * or "delta" - should be distributed to all of the columns regardless
  1967. * of this <code>JTable</code>'s automatic resize mode.
  1968. * <p>
  1969. * If the <code>resizingColumn</code> is not <code>null</code>, it is one of
  1970. * the columns in the table that has changed size rather than
  1971. * the table itself. In this case the auto-resize modes govern
  1972. * the way the extra (or deficit) space is distributed
  1973. * amongst the available columns.
  1974. * <p>
  1975. * The modes are:
  1976. * <ul>
  1977. * <li> AUTO_RESIZE_OFF: Don't automatically adjust the column's
  1978. * widths at all. Use a horizontal scrollbar to accomodate the
  1979. * columns when their sum exceeds the width of the
  1980. * <code>Viewport</code>. If the <code>JTable</code> is not
  1981. * enclosed in a <code>JScrollPane</code> this may
  1982. * leave parts of the table invisible.
  1983. * <li> AUTO_RESIZE_NEXT_COLUMN: Use just the column after the
  1984. * resizing column. This results in the "boundary" or divider
  1985. * between adjacent cells being independently adjustable.
  1986. * <li> AUTO_RESIZE_SUBSEQUENT_COLUMNS: Use all columns after the
  1987. * one being adjusted to absorb the changes. This is the
  1988. * default behavior.
  1989. * <li> AUTO_RESIZE_LAST_COLUMN: Automatically adjust the
  1990. * size of the last column only. If the bounds of the last column
  1991. * prevent the desired size from being allocated, set the
  1992. * width of the last column to the appropriate limit and make
  1993. * no further adjustments.
  1994. * <li> AUTO_RESIZE_ALL_COLUMNS: Spread the delta amongst all the columns
  1995. * in the <code>JTable</code>, including the one that is being
  1996. * adjusted.
  1997. * </ul>
  1998. * <p>
  1999. * <bold>Note:</bold> When a <code>JTable</code> makes adjustments
  2000. * to the widths of the columns it respects their minimum and
  2001. * maximum values absolutely. It is therefore possible that,
  2002. * even after this method is called, the total width of the columns
  2003. * is still not equal to the width of the table. When this happens
  2004. * the <code>JTable</code> does not put itself
  2005. * in AUTO_RESIZE_OFF mode to bring up a scroll bar, or break other
  2006. * commitments of its current auto-resize mode -- instead it
  2007. * allows its bounds to be set larger (or smaller) than the total of the
  2008. * column minimum or maximum, meaning, either that there
  2009. * will not be enough room to display all of the columns, or that the
  2010. * columns will not fill the <code>JTable</code>'s bounds.
  2011. * These respectively, result in the clipping of some columns
  2012. * or an area being painted in the <code>JTable</code>'s
  2013. * background color during painting.
  2014. * <p>
  2015. * The mechanism for distributing the delta amongst the available
  2016. * columns is provided in a private method in the <code>JTable</code>
  2017. * class:
  2018. * <pre>
  2019. * adjustSizes(long targetSize, final Resizable3 r, boolean inverse)
  2020. * </pre>
  2021. * an explanation of which is provided in the following section.
  2022. * <code>Resizable3</code> is a private
  2023. * interface that allows any data structure containing a collection
  2024. * of elements with a size, preferred size, maximum size and minimum size
  2025. * to have its elements manipulated by the algorithm.
  2026. * <p>
  2027. * <H3> Distributing the delta </H3>
  2028. * <p>
  2029. * <H4> Overview </H4>
  2030. * <P>
  2031. * Call "DELTA" the difference between the target size and the
  2032. * sum of the preferred sizes of the elements in r. The individual
  2033. * sizes are calculated by taking the original preferred
  2034. * sizes and adding a share of the DELTA - that share being based on
  2035. * how far each preferred size is from its limiting bound (minimum or
  2036. * maximum).
  2037. * <p>
  2038. * <H4>Definition</H4>
  2039. * <P>
  2040. * Call the individual constraints min[i], max[i], and pref[i].
  2041. * <p>
  2042. * Call their respective sums: MIN, MAX, and PREF.
  2043. * <p>
  2044. * Each new size will be calculated using:
  2045. * <p>
  2046. * <pre>
  2047. * size[i] = pref[i] + delta[i]
  2048. * </pre>
  2049. * where each individual delta[i] is calculated according to:
  2050. * <p>
  2051. * If (DELTA < 0) we are in shrink mode where:
  2052. * <p>
  2053. * <PRE>
  2054. * DELTA
  2055. * delta[i] = ------------ * (pref[i] - min[i])
  2056. * (PREF - MIN)
  2057. * </PRE>
  2058. * If (DELTA > 0) we are in expand mode where:
  2059. * <p>
  2060. * <PRE>
  2061. * DELTA
  2062. * delta[i] = ------------ * (max[i] - pref[i])
  2063. * (MAX - PREF)
  2064. * </PRE>
  2065. * <P>
  2066. * The overall effect is that the total size moves that same percentage,
  2067. * k, towards the total minimum or maximum and that percentage guarantees
  2068. * accomodation of the required space, DELTA.
  2069. *
  2070. * <H4>Details</H4>
  2071. * <P>
  2072. * Naive evaluation of the formulae presented here would be subject to
  2073. * the aggregated rounding errors caused by doing this operation in finite
  2074. * precision (using ints). To deal with this, the multiplying factor above,
  2075. * is constantly recalculated and this takes account of the rounding
  2076. * errors in the previous iterations. The result is an algorithm that
  2077. * produces a set of integers whose values exactly sum to the supplied
  2078. * <code>targetSize</code>, and does so by spreading the rounding
  2079. * errors evenly over the given elements.
  2080. *
  2081. * <H4>When the MAX and MIN bounds are hit</H4>
  2082. * <P>
  2083. * When <code>targetSize</code> is outside the [MIN, MAX] range,
  2084. * the algorithm sets all sizes to their appropriate limiting value
  2085. * (maximum or minimum).
  2086. *
  2087. */
  2088. public void doLayout() {
  2089. TableColumn resizingColumn = getResizingColumn();
  2090. if (resizingColumn == null) {
  2091. setWidthsFromPreferredWidths(false);
  2092. }
  2093. else {
  2094. // JTable behaves like a layout manger - but one in which the
  2095. // user can come along and dictate how big one of the children
  2096. // (columns) is supposed to be.
  2097. // A column has been resized and JTable may need to distribute
  2098. // any overall delta to other columns, according to the resize mode.
  2099. int columnIndex = viewIndexForColumn(resizingColumn);
  2100. int delta = getWidth() - getColumnModel().getTotalColumnWidth();
  2101. accommodateDelta(columnIndex, delta);
  2102. delta = getWidth() - getColumnModel().getTotalColumnWidth();
  2103. // If the delta cannot be completely accomodated, then the
  2104. // resizing column will have to take any remainder. This means
  2105. // that the column is not being allowed to take the requested
  2106. // width. This happens under many circumstances: For example,
  2107. // AUTO_RESIZE_NEXT_COLUMN specifies that any delta be distributed
  2108. // to the column after the resizing column. If one were to attempt
  2109. // to resize the last column of the table, there would be no
  2110. // columns after it, and hence nowhere to distribute the delta.
  2111. // It would then be given entirely back to the resizing column,
  2112. // preventing it from changing size.
  2113. if (delta != 0) {
  2114. resizingColumn.setWidth(resizingColumn.getWidth() + delta);
  2115. }
  2116. // At this point the JTable has to work out what preferred sizes
  2117. // would have resulted in the layout the user has chosen.
  2118. // Thereafter, during window resizing etc. it has to work off
  2119. // the preferred sizes as usual - the idea being that, whatever
  2120. // the user does, everything stays in synch and things don't jump
  2121. // around.
  2122. setWidthsFromPreferredWidths(true);
  2123. }
  2124. super.doLayout();
  2125. }
  2126. private TableColumn getResizingColumn() {
  2127. return (tableHeader == null) ? null
  2128. : tableHeader.getResizingColumn();
  2129. }
  2130. /**
  2131. * Sizes the table columns to fit the available space.
  2132. * @deprecated As of Swing version 1.0.3,
  2133. * replaced by <code>doLayout()</code>.
  2134. * @see #doLayout
  2135. */
  2136. @Deprecated
  2137. public void sizeColumnsToFit(boolean lastColumnOnly) {
  2138. int oldAutoResizeMode = autoResizeMode;
  2139. setAutoResizeMode(lastColumnOnly ? AUTO_RESIZE_LAST_COLUMN
  2140. : AUTO_RESIZE_ALL_COLUMNS);
  2141. sizeColumnsToFit(-1);
  2142. setAutoResizeMode(oldAutoResizeMode);
  2143. }
  2144. /**
  2145. * Obsolete as of Java 2 platform v1.4. Please use the
  2146. * <code>doLayout()</code> method instead.
  2147. * @param resizingColumn the column whose resizing made this adjustment
  2148. * necessary or -1 if there is no such column
  2149. * @see #doLayout
  2150. */
  2151. public void sizeColumnsToFit(int resizingColumn) {
  2152. if (resizingColumn == -1) {
  2153. setWidthsFromPreferredWidths(false);
  2154. }
  2155. else {
  2156. if (autoResizeMode == AUTO_RESIZE_OFF) {
  2157. TableColumn aColumn = getColumnModel().getColumn(resizingColumn);
  2158. aColumn.setPreferredWidth(aColumn.getWidth());
  2159. }
  2160. else {
  2161. int delta = getWidth() - getColumnModel().getTotalColumnWidth();
  2162. accommodateDelta(resizingColumn, delta);
  2163. setWidthsFromPreferredWidths(true);
  2164. }
  2165. }
  2166. }
  2167. private void setWidthsFromPreferredWidths(final boolean inverse) {
  2168. int totalWidth = getWidth();
  2169. int totalPreferred = getPreferredSize().width;
  2170. int target = !inverse ? totalWidth : totalPreferred;
  2171. final TableColumnModel cm = columnModel;
  2172. Resizable3 r = new Resizable3() {
  2173. public int getElementCount() { return cm.getColumnCount(); }
  2174. public int getLowerBoundAt(int i) { return cm.getColumn(i).getMinWidth(); }
  2175. public int getUpperBoundAt(int i) { return cm.getColumn(i).getMaxWidth(); }
  2176. public int getMidPointAt(int i) {
  2177. if (!inverse) {
  2178. return cm.getColumn(i).getPreferredWidth();
  2179. }
  2180. else {
  2181. return cm.getColumn(i).getWidth();
  2182. }
  2183. }
  2184. public void setSizeAt(int s, int i) {
  2185. if (!inverse) {
  2186. cm.getColumn(i).setWidth(s);
  2187. }
  2188. else {
  2189. cm.getColumn(i).setPreferredWidth(s);
  2190. }
  2191. }
  2192. };
  2193. adjustSizes(target, r, inverse);
  2194. }
  2195. // Distribute delta over columns, as indicated by the autoresize mode.
  2196. private void accommodateDelta(int resizingColumnIndex, int delta) {
  2197. int columnCount = getColumnCount();
  2198. int from = resizingColumnIndex;
  2199. int to = columnCount;
  2200. // Use the mode to determine how to absorb the changes.
  2201. switch(autoResizeMode) {
  2202. case AUTO_RESIZE_NEXT_COLUMN:
  2203. from = from + 1;
  2204. to = Math.min(from + 1, columnCount); break;
  2205. case AUTO_RESIZE_SUBSEQUENT_COLUMNS:
  2206. from = from + 1;
  2207. to = columnCount; break;
  2208. case AUTO_RESIZE_LAST_COLUMN:
  2209. from = columnCount - 1;
  2210. to = from + 1; break;
  2211. case AUTO_RESIZE_ALL_COLUMNS:
  2212. from = 0;
  2213. to = columnCount; break;
  2214. default:
  2215. return;
  2216. }
  2217. final int start = from;
  2218. final int end = to;
  2219. final TableColumnModel cm = columnModel;
  2220. Resizable3 r = new Resizable3() {
  2221. public int getElementCount() { return end-start; }
  2222. public int getLowerBoundAt(int i) { return cm.getColumn(i+start).getMinWidth(); }
  2223. public int getUpperBoundAt(int i) { return cm.getColumn(i+start).getMaxWidth(); }
  2224. public int getMidPointAt(int i) { return cm.getColumn(i+start).getWidth(); }
  2225. public void setSizeAt(int s, int i) { cm.getColumn(i+start).setWidth(s); }
  2226. };
  2227. int totalWidth = 0;
  2228. for(int i = from; i < to; i++) {
  2229. TableColumn aColumn = columnModel.getColumn(i);
  2230. int input = aColumn.getWidth();
  2231. totalWidth = totalWidth + input;
  2232. }
  2233. adjustSizes(totalWidth + delta, r, false);
  2234. return;
  2235. }
  2236. private interface Resizable2 {
  2237. public int getElementCount();
  2238. public int getLowerBoundAt(int i);
  2239. public int getUpperBoundAt(int i);
  2240. public void setSizeAt(int newSize, int i);
  2241. }
  2242. private interface Resizable3 extends Resizable2 {
  2243. public int getMidPointAt(int i);
  2244. }
  2245. private void adjustSizes(long target, final Resizable3 r, boolean inverse) {
  2246. int N = r.getElementCount();
  2247. long totalPreferred = 0;
  2248. for(int i = 0; i < N; i++) {
  2249. totalPreferred += r.getMidPointAt(i);
  2250. }
  2251. Resizable2 s;
  2252. if ((target < totalPreferred) == !inverse) {
  2253. s = new Resizable2() {
  2254. public int getElementCount() { return r.getElementCount(); }
  2255. public int getLowerBoundAt(int i) { return r.getLowerBoundAt(i); }
  2256. public int getUpperBoundAt(int i) { return r.getMidPointAt(i); }
  2257. public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
  2258. };
  2259. }
  2260. else {
  2261. s = new Resizable2() {
  2262. public int getElementCount() { return r.getElementCount(); }
  2263. public int getLowerBoundAt(int i) { return r.getMidPointAt(i); }
  2264. public int getUpperBoundAt(int i) { return r.getUpperBoundAt(i); }
  2265. public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
  2266. };
  2267. }
  2268. adjustSizes(target, s, !inverse);
  2269. }
  2270. private void adjustSizes(long target, Resizable2 r, boolean limitToRange) {
  2271. long totalLowerBound = 0;
  2272. long totalUpperBound = 0;
  2273. for(int i = 0; i < r.getElementCount(); i++) {
  2274. totalLowerBound += r.getLowerBoundAt(i);
  2275. totalUpperBound += r.getUpperBoundAt(i);
  2276. }
  2277. if (limitToRange) {
  2278. target = Math.min(Math.max(totalLowerBound, target), totalUpperBound);
  2279. }
  2280. for(int i = 0; i < r.getElementCount(); i++) {
  2281. int lowerBound = r.getLowerBoundAt(i);
  2282. int upperBound = r.getUpperBoundAt(i);
  2283. // Check for zero. This happens when the distribution of the delta
  2284. // finishes early due to a series of "fixed" entries at the end.
  2285. // In this case, lowerBound == upperBound, for all subsequent terms.
  2286. int newSize;
  2287. if (totalLowerBound == totalUpperBound) {
  2288. newSize = lowerBound;
  2289. }
  2290. else {
  2291. double f = (double)(target - totalLowerBound)/(totalUpperBound - totalLowerBound);
  2292. newSize = (int)Math.round(lowerBound+f*(upperBound - lowerBound));
  2293. // We'd need to round manually in an all integer version.
  2294. // size[i] = (int)(((totalUpperBound - target) * lowerBound +
  2295. // (target - totalLowerBound) * upperBound)/(totalUpperBound-totalLowerBound));
  2296. }
  2297. r.setSizeAt(newSize, i);
  2298. target -= newSize;
  2299. totalLowerBound -= lowerBound;
  2300. totalUpperBound -= upperBound;
  2301. }
  2302. }
  2303. /**
  2304. * Overrides <code>JComponent</code>'s <code>getToolTipText</code>
  2305. * method in order to allow the renderer's tips to be used
  2306. * if it has text set.
  2307. * <p>
  2308. * <bold>Note:</bold> For <code>JTable</code> to properly display
  2309. * tooltips of its renderers
  2310. * <code>JTable</code> must be a registered component with the
  2311. * <code>ToolTipManager</code>.
  2312. * This is done automatically in <code>initializeLocalVars</code>,
  2313. * but if at a later point <code>JTable</code> is told
  2314. * <code>setToolTipText(null)</code> it will unregister the table
  2315. * component, and no tips from renderers will display anymore.
  2316. *
  2317. * @see JComponent#getToolTipText
  2318. */
  2319. public String getToolTipText(MouseEvent event) {
  2320. String tip = null;
  2321. Point p = event.getPoint();
  2322. // Locate the renderer under the event location
  2323. int hitColumnIndex = columnAtPoint(p);
  2324. int hitRowIndex = rowAtPoint(p);
  2325. if ((hitColumnIndex != -1) && (hitRowIndex != -1)) {
  2326. TableCellRenderer renderer = getCellRenderer(hitRowIndex, hitColumnIndex);
  2327. Component component = prepareRenderer(renderer, hitRowIndex, hitColumnIndex);
  2328. // Now have to see if the component is a JComponent before
  2329. // getting the tip
  2330. if (component instanceof JComponent) {
  2331. // Convert the event to the renderer's coordinate system
  2332. Rectangle cellRect = getCellRect(hitRowIndex, hitColumnIndex, false);
  2333. p.translate(-cellRect.x, -cellRect.y);
  2334. MouseEvent newEvent = new MouseEvent(component, event.getID(),
  2335. event.getWhen(), event.getModifiers(),
  2336. p.x, p.y, event.getClickCount(),
  2337. event.isPopupTrigger());
  2338. tip = ((JComponent)component).getToolTipText(newEvent);
  2339. }
  2340. }
  2341. // No tip from the renderer get our own tip
  2342. if (tip == null)
  2343. tip = getToolTipText();
  2344. return tip;
  2345. }
  2346. //
  2347. // Editing Support
  2348. //
  2349. /**
  2350. * Sets whether editors in this JTable get the keyboard focus
  2351. * when an editor is activated as a result of the JTable
  2352. * forwarding keyboard events for a cell.
  2353. * By default, this property is false, and the JTable
  2354. * retains the focus unless the cell is clicked.
  2355. *
  2356. * @param surrendersFocusOnKeystroke true if the editor should get the focus
  2357. * when keystrokes cause the editor to be
  2358. * activated
  2359. *
  2360. *
  2361. * @see #getSurrendersFocusOnKeystroke
  2362. */
  2363. public void setSurrendersFocusOnKeystroke(boolean surrendersFocusOnKeystroke) {
  2364. this.surrendersFocusOnKeystroke = surrendersFocusOnKeystroke;
  2365. }
  2366. /**
  2367. * Returns true if the editor should get the focus
  2368. * when keystrokes cause the editor to be activated
  2369. *
  2370. * @return true if the editor should get the focus
  2371. * when keystrokes cause the editor to be
  2372. * activated
  2373. *
  2374. * @see #setSurrendersFocusOnKeystroke
  2375. */
  2376. public boolean getSurrendersFocusOnKeystroke() {
  2377. return surrendersFocusOnKeystroke;
  2378. }
  2379. /**
  2380. * Programmatically starts editing the cell at <code>row</code> and
  2381. * <code>column</code>, if those indices are in the valid range, and
  2382. * the cell at those indices is editable.
  2383. * Note that this is a convenience method for
  2384. * <code>editCellAt(int, int, null)</code>.
  2385. *
  2386. * @param row the row to be edited
  2387. * @param column the column to be edited
  2388. * @return false if for any reason the cell cannot be edited,
  2389. * or if the indices are invalid
  2390. */
  2391. public boolean editCellAt(int row, int column) {
  2392. return editCellAt(row, column, null);
  2393. }
  2394. /**
  2395. * Programmatically starts editing the cell at <code>row</code> and
  2396. * <code>column</code>, if those indices are in the valid range, and
  2397. * the cell at those indices is editable.
  2398. * To prevent the <code>JTable</code> from
  2399. * editing a particular table, column or cell value, return false from
  2400. * the <code>isCellEditable</code> method in the <code>TableModel</code>
  2401. * interface.
  2402. *
  2403. * @param row the row to be edited
  2404. * @param column the column to be edited
  2405. * @param e event to pass into <code>shouldSelectCell</code>
  2406. * note that as of Java 2 platform v1.2, the call to
  2407. * <code>shouldSelectCell</code> is no longer made
  2408. * @return false if for any reason the cell cannot be edited,
  2409. * or if the indices are invalid
  2410. */
  2411. public boolean editCellAt(int row, int column, EventObject e){
  2412. if (cellEditor != null && !cellEditor.stopCellEditing()) {
  2413. return false;
  2414. }
  2415. if (row < 0 || row >= getRowCount() ||
  2416. column < 0 || column >= getColumnCount()) {
  2417. return false;
  2418. }
  2419. if (!isCellEditable(row, column))
  2420. return false;
  2421. if (editorRemover == null) {
  2422. KeyboardFocusManager fm =
  2423. KeyboardFocusManager.getCurrentKeyboardFocusManager();
  2424. editorRemover = new CellEditorRemover(fm);
  2425. fm.addPropertyChangeListener("permanentFocusOwner", editorRemover);
  2426. }
  2427. TableCellEditor editor = getCellEditor(row, column);
  2428. if (editor != null && editor.isCellEditable(e)) {
  2429. editorComp = prepareEditor(editor, row, column);
  2430. if (editorComp == null) {
  2431. removeEditor();
  2432. return false;
  2433. }
  2434. editorComp.setBounds(getCellRect(row, column, false));
  2435. add(editorComp);
  2436. editorComp.validate();
  2437. setCellEditor(editor);
  2438. setEditingRow(row);
  2439. setEditingColumn(column);
  2440. editor.addCellEditorListener(this);
  2441. return true;
  2442. }
  2443. return false;
  2444. }
  2445. /**
  2446. * Returns true if a cell is being edited.
  2447. *
  2448. * @return true if the table is editing a cell
  2449. * @see #editingColumn
  2450. * @see #editingRow
  2451. */
  2452. public boolean isEditing() {
  2453. return (cellEditor == null)? false : true;
  2454. }
  2455. /**
  2456. * Returns the component that is handling the editing session.
  2457. * If nothing is being edited, returns null.
  2458. *
  2459. * @return Component handling editing session
  2460. */
  2461. public Component getEditorComponent() {
  2462. return editorComp;
  2463. }
  2464. /**
  2465. * Returns the index of the column that contains the cell currently
  2466. * being edited. If nothing is being edited, returns -1.
  2467. *
  2468. * @return the index of the column that contains the cell currently
  2469. * being edited; returns -1 if nothing being edited
  2470. * @see #editingRow
  2471. */
  2472. public int getEditingColumn() {
  2473. return editingColumn;
  2474. }
  2475. /**
  2476. * Returns the index of the row that contains the cell currently
  2477. * being edited. If nothing is being edited, returns -1.
  2478. *
  2479. * @return the index of the row that contains the cell currently
  2480. * being edited; returns -1 if nothing being edited
  2481. * @see #editingColumn
  2482. */
  2483. public int getEditingRow() {
  2484. return editingRow;
  2485. }
  2486. //
  2487. // Managing TableUI
  2488. //
  2489. /**
  2490. * Returns the L&F object that renders this component.
  2491. *
  2492. * @return the <code>TableUI</code> object that renders this component
  2493. */
  2494. public TableUI getUI() {
  2495. return (TableUI)ui;
  2496. }
  2497. /**
  2498. * Sets the L&F object that renders this component and repaints.
  2499. *
  2500. * @param ui the TableUI L&F object
  2501. * @see UIDefaults#getUI
  2502. * @beaninfo
  2503. * bound: true
  2504. * hidden: true
  2505. * attribute: visualUpdate true
  2506. * description: The UI object that implements the Component's LookAndFeel.
  2507. */
  2508. public void setUI(TableUI ui) {
  2509. if (this.ui != ui) {
  2510. super.setUI(ui);
  2511. repaint();
  2512. }
  2513. }
  2514. private void updateSubComponentUI(Object componentShell) {
  2515. if (componentShell == null) {
  2516. return;
  2517. }
  2518. Component component = null;
  2519. if (componentShell instanceof Component) {
  2520. component = (Component)componentShell;
  2521. }
  2522. if (componentShell instanceof DefaultCellEditor) {
  2523. component = ((DefaultCellEditor)componentShell).getComponent();
  2524. }
  2525. if (component != null && component instanceof JComponent) {
  2526. ((JComponent)component).updateUI();
  2527. }
  2528. }
  2529. /**
  2530. * Notification from the <code>UIManager</code> that the L&F has changed.
  2531. * Replaces the current UI object with the latest version from the
  2532. * <code>UIManager</code>.
  2533. *
  2534. * @see JComponent#updateUI
  2535. */
  2536. public void updateUI() {
  2537. // Update the UIs of the cell renderers, cell editors and header renderers.
  2538. TableColumnModel cm = getColumnModel();
  2539. for(int column = 0; column < cm.getColumnCount(); column++) {
  2540. TableColumn aColumn = cm.getColumn(column);
  2541. updateSubComponentUI(aColumn.getCellRenderer());
  2542. updateSubComponentUI(aColumn.getCellEditor());
  2543. updateSubComponentUI(aColumn.getHeaderRenderer());
  2544. }
  2545. // Update the UIs of all the default renderers.
  2546. Enumeration defaultRenderers = defaultRenderersByColumnClass.elements();
  2547. while (defaultRenderers.hasMoreElements()) {
  2548. updateSubComponentUI(defaultRenderers.nextElement());
  2549. }
  2550. // Update the UIs of all the default editors.
  2551. Enumeration defaultEditors = defaultEditorsByColumnClass.elements();
  2552. while (defaultEditors.hasMoreElements()) {
  2553. updateSubComponentUI(defaultEditors.nextElement());
  2554. }
  2555. // Update the UI of the table header
  2556. if (tableHeader != null && tableHeader.getParent() == null) {
  2557. tableHeader.updateUI();
  2558. }
  2559. setUI((TableUI)UIManager.getUI(this));
  2560. resizeAndRepaint();
  2561. }
  2562. /**
  2563. * Returns the suffix used to construct the name of the L&F class used to
  2564. * render this component.
  2565. *
  2566. * @return the string "TableUI"
  2567. * @see JComponent#getUIClassID
  2568. * @see UIDefaults#getUI
  2569. */
  2570. public String getUIClassID() {
  2571. return uiClassID;
  2572. }
  2573. //
  2574. // Managing models
  2575. //
  2576. /**
  2577. * Sets the data model for this table to <code>newModel</code> and registers
  2578. * with it for listener notifications from the new data model.
  2579. *
  2580. * @param dataModel the new data source for this table
  2581. * @exception IllegalArgumentException if <code>newModel</code> is <code>null</code>
  2582. * @see #getModel
  2583. * @beaninfo
  2584. * bound: true
  2585. * description: The model that is the source of the data for this view.
  2586. */
  2587. public void setModel(TableModel dataModel) {
  2588. if (dataModel == null) {
  2589. throw new IllegalArgumentException("Cannot set a null TableModel");
  2590. }
  2591. if (this.dataModel != dataModel) {
  2592. TableModel old = this.dataModel;
  2593. if (old != null) {
  2594. old.removeTableModelListener(this);
  2595. }
  2596. this.dataModel = dataModel;
  2597. dataModel.addTableModelListener(this);
  2598. tableChanged(new TableModelEvent(dataModel, TableModelEvent.HEADER_ROW));
  2599. firePropertyChange("model", old, dataModel);
  2600. }
  2601. }
  2602. /**
  2603. * Returns the <code>TableModel</code> that provides the data displayed by this
  2604. * <code>JTable</code>.
  2605. *
  2606. * @return the <code>TableModel</code> that provides the data displayed by this <code>JTable</code>
  2607. * @see #setModel
  2608. */
  2609. public TableModel getModel() {
  2610. return dataModel;
  2611. }
  2612. /**
  2613. * Sets the column model for this table to <code>newModel</code> and registers
  2614. * for listener notifications from the new column model. Also sets
  2615. * the column model of the <code>JTableHeader</code> to <code>columnModel</code>.
  2616. *
  2617. * @param columnModel the new data source for this table
  2618. * @exception IllegalArgumentException if <code>columnModel</code> is <code>null</code>
  2619. * @see #getColumnModel
  2620. * @beaninfo
  2621. * bound: true
  2622. * description: The object governing the way columns appear in the view.
  2623. */
  2624. public void setColumnModel(TableColumnModel columnModel) {
  2625. if (columnModel == null) {
  2626. throw new IllegalArgumentException("Cannot set a null ColumnModel");
  2627. }
  2628. TableColumnModel old = this.columnModel;
  2629. if (columnModel != old) {
  2630. if (old != null) {
  2631. old.removeColumnModelListener(this);
  2632. }
  2633. this.columnModel = columnModel;
  2634. columnModel.addColumnModelListener(this);
  2635. // Set the column model of the header as well.
  2636. if (tableHeader != null) {
  2637. tableHeader.setColumnModel(columnModel);
  2638. }
  2639. firePropertyChange("columnModel", old, columnModel);
  2640. resizeAndRepaint();
  2641. }
  2642. }
  2643. /**
  2644. * Returns the <code>TableColumnModel</code> that contains all column information
  2645. * of this table.
  2646. *
  2647. * @return the object that provides the column state of the table
  2648. * @see #setColumnModel
  2649. */
  2650. public TableColumnModel getColumnModel() {
  2651. return columnModel;
  2652. }
  2653. /**
  2654. * Sets the row selection model for this table to <code>newModel</code>
  2655. * and registers for listener notifications from the new selection model.
  2656. *
  2657. * @param newModel the new selection model
  2658. * @exception IllegalArgumentException if <code>newModel</code> is <code>null</code>
  2659. * @see #getSelectionModel
  2660. * @beaninfo
  2661. * bound: true
  2662. * description: The selection model for rows.
  2663. */
  2664. public void setSelectionModel(ListSelectionModel newModel) {
  2665. if (newModel == null) {
  2666. throw new IllegalArgumentException("Cannot set a null SelectionModel");
  2667. }
  2668. ListSelectionModel oldModel = selectionModel;
  2669. if (newModel != oldModel) {
  2670. if (oldModel != null) {
  2671. oldModel.removeListSelectionListener(this);
  2672. }
  2673. selectionModel = newModel;
  2674. newModel.addListSelectionListener(this);
  2675. firePropertyChange("selectionModel", oldModel, newModel);
  2676. repaint();
  2677. checkLeadAnchor();
  2678. }
  2679. }
  2680. /**
  2681. * Returns the <code>ListSelectionModel</code> that is used to maintain row
  2682. * selection state.
  2683. *
  2684. * @return the object that provides row selection state, <code>null</code>
  2685. * if row selection is not allowed
  2686. * @see #setSelectionModel
  2687. */
  2688. public ListSelectionModel getSelectionModel() {
  2689. return selectionModel;
  2690. }
  2691. /**
  2692. * Initialize the lead and anchor of the selection model
  2693. * based on what the table model contains.
  2694. */
  2695. private void checkLeadAnchor() {
  2696. TableModel model = getModel();
  2697. // Setting the selection model in the constructor will cause
  2698. // this to be invoked before the data model has been set.
  2699. // Bail in this case.
  2700. if (model == null) {
  2701. return;
  2702. }
  2703. int lead = selectionModel.getLeadSelectionIndex();
  2704. int count = model.getRowCount();
  2705. if (count == 0) {
  2706. if (lead != -1) {
  2707. // no rows left, set the lead and anchor to -1
  2708. selectionModel.setValueIsAdjusting(true);
  2709. selectionModel.setAnchorSelectionIndex(-1);
  2710. selectionModel.setLeadSelectionIndex(-1);
  2711. selectionModel.setValueIsAdjusting(false);
  2712. }
  2713. } else {
  2714. if (lead == -1) {
  2715. // set the lead and anchor to the first row
  2716. // (without changing the selection)
  2717. if (selectionModel.isSelectedIndex(0)) {
  2718. selectionModel.addSelectionInterval(0, 0);
  2719. } else {
  2720. selectionModel.removeSelectionInterval(0, 0);
  2721. }
  2722. }
  2723. }
  2724. }
  2725. //
  2726. // Implementing TableModelListener interface
  2727. //
  2728. /**
  2729. * Invoked when this table's <code>TableModel</code> generates
  2730. * a <code>TableModelEvent</code>.
  2731. * The <code>TableModelEvent</code> should be constructed in the
  2732. * coordinate system of the model; the appropriate mapping to the
  2733. * view coordinate system is performed by this <code>JTable</code>
  2734. * when it receives the event.
  2735. * <p>
  2736. * Application code will not use these methods explicitly, they
  2737. * are used internally by <code>JTable</code>.
  2738. * <p>
  2739. * Note that as of 1.3, this method clears the selection, if any.
  2740. */
  2741. public void tableChanged(TableModelEvent e) {
  2742. if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
  2743. // The whole thing changed
  2744. clearSelection();
  2745. checkLeadAnchor();
  2746. rowModel = null;
  2747. if (getAutoCreateColumnsFromModel()) {
  2748. // This will effect invalidation of the JTable and JTableHeader.
  2749. createDefaultColumnsFromModel();
  2750. return;
  2751. }
  2752. resizeAndRepaint();
  2753. return;
  2754. }
  2755. // The totalRowHeight calculated below will be incorrect if
  2756. // there are variable height rows. Repaint the visible region,
  2757. // but don't return as a revalidate may be necessary as well.
  2758. if (rowModel != null) {
  2759. repaint();
  2760. }
  2761. if (e.getType() == TableModelEvent.INSERT) {
  2762. tableRowsInserted(e);
  2763. return;
  2764. }
  2765. if (e.getType() == TableModelEvent.DELETE) {
  2766. tableRowsDeleted(e);
  2767. return;
  2768. }
  2769. int modelColumn = e.getColumn();
  2770. int start = e.getFirstRow();
  2771. int end = e.getLastRow();
  2772. Rectangle dirtyRegion;
  2773. if (modelColumn == TableModelEvent.ALL_COLUMNS) {
  2774. // 1 or more rows changed
  2775. dirtyRegion = new Rectangle(0, start * getRowHeight(),
  2776. getColumnModel().getTotalColumnWidth(), 0);
  2777. }
  2778. else {
  2779. // A cell or column of cells has changed.
  2780. // Unlike the rest of the methods in the JTable, the TableModelEvent
  2781. // uses the coordinate system of the model instead of the view.
  2782. // This is the only place in the JTable where this "reverse mapping"
  2783. // is used.
  2784. int column = convertColumnIndexToView(modelColumn);
  2785. dirtyRegion = getCellRect(start, column, false);
  2786. }
  2787. // Now adjust the height of the dirty region according to the value of "end".
  2788. // Check for Integer.MAX_VALUE as this will cause an overflow.
  2789. if (end != Integer.MAX_VALUE) {
  2790. dirtyRegion.height = (end-start+1)*getRowHeight();
  2791. repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
  2792. }
  2793. // In fact, if the end is Integer.MAX_VALUE we need to revalidate anyway
  2794. // because the scrollbar may need repainting.
  2795. else {
  2796. clearSelection();
  2797. resizeAndRepaint();
  2798. rowModel = null;
  2799. }
  2800. }
  2801. /*
  2802. * Invoked when rows have been inserted into the table.
  2803. * <p>
  2804. * Application code will not use these methods explicitly, they
  2805. * are used internally by JTable.
  2806. *
  2807. * @param e the TableModelEvent encapsulating the insertion
  2808. */
  2809. private void tableRowsInserted(TableModelEvent e) {
  2810. int start = e.getFirstRow();
  2811. int end = e.getLastRow();
  2812. if (start < 0) {
  2813. start = 0;
  2814. }
  2815. if (end < 0) {
  2816. end = getRowCount()-1;
  2817. }
  2818. // Adjust the selection to account for the new rows.
  2819. int length = end - start + 1;
  2820. selectionModel.insertIndexInterval(start, length, true);
  2821. checkLeadAnchor();
  2822. // If we have variable height rows, adjust the row model.
  2823. if (rowModel != null) {
  2824. rowModel.insertEntries(start, length, getRowHeight());
  2825. }
  2826. int rh = getRowHeight() ;
  2827. Rectangle drawRect = new Rectangle(0, start * rh,
  2828. getColumnModel().getTotalColumnWidth(),
  2829. (getRowCount()-start) * rh);
  2830. revalidate();
  2831. // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
  2832. // repaint still required in the unusual case where there is no ScrollPane
  2833. repaint(drawRect);
  2834. }
  2835. /*
  2836. * Invoked when rows have been removed from the table.
  2837. * <p>
  2838. * Application code will not use these methods explicitly, they
  2839. * are used internally by JTable.
  2840. *
  2841. * @param e the TableModelEvent encapsulating the deletion
  2842. */
  2843. private void tableRowsDeleted(TableModelEvent e) {
  2844. int start = e.getFirstRow();
  2845. int end = e.getLastRow();
  2846. if (start < 0) {
  2847. start = 0;
  2848. }
  2849. if (end < 0) {
  2850. end = getRowCount()-1;
  2851. }
  2852. int deletedCount = end - start + 1;
  2853. int previousRowCount = getRowCount() + deletedCount;
  2854. // Adjust the selection to account for the new rows
  2855. selectionModel.removeIndexInterval(start, end);
  2856. checkLeadAnchor();
  2857. // If we have variable height rows, adjust the row model.
  2858. if (rowModel != null) {
  2859. rowModel.removeEntries(start, deletedCount);
  2860. }
  2861. int rh = getRowHeight();
  2862. Rectangle drawRect = new Rectangle(0, start * rh,
  2863. getColumnModel().getTotalColumnWidth(),
  2864. (previousRowCount - start) * rh);
  2865. revalidate();
  2866. // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
  2867. // repaint still required in the unusual case where there is no ScrollPane
  2868. repaint(drawRect);
  2869. }
  2870. //
  2871. // Implementing TableColumnModelListener interface
  2872. //
  2873. /**
  2874. * Invoked when a column is added to the table column model.
  2875. * <p>
  2876. * Application code will not use these methods explicitly, they
  2877. * are used internally by JTable.
  2878. *
  2879. * @see TableColumnModelListener
  2880. */
  2881. public void columnAdded(TableColumnModelEvent e) {
  2882. // If I'm currently editing, then I should stop editing
  2883. if (isEditing()) {
  2884. removeEditor();
  2885. }
  2886. resizeAndRepaint();
  2887. }
  2888. /**
  2889. * Invoked when a column is removed from the table column model.
  2890. * <p>
  2891. * Application code will not use these methods explicitly, they
  2892. * are used internally by JTable.
  2893. *
  2894. * @see TableColumnModelListener
  2895. */
  2896. public void columnRemoved(TableColumnModelEvent e) {
  2897. // If I'm currently editing, then I should stop editing
  2898. if (isEditing()) {
  2899. removeEditor();
  2900. }
  2901. resizeAndRepaint();
  2902. }
  2903. /**
  2904. * Invoked when a column is repositioned. If a cell is being
  2905. * edited, then editing is stopped and the cell is redrawn.
  2906. * <p>
  2907. * Application code will not use these methods explicitly, they
  2908. * are used internally by JTable.
  2909. *
  2910. * @param e the event received
  2911. * @see TableColumnModelListener
  2912. */
  2913. public void columnMoved(TableColumnModelEvent e) {
  2914. // If I'm currently editing, then I should stop editing
  2915. if (isEditing()) {
  2916. removeEditor();
  2917. }
  2918. repaint();
  2919. }
  2920. /**
  2921. * Invoked when a column is moved due to a margin change.
  2922. * If a cell is being edited, then editing is stopped and the cell
  2923. * is redrawn.
  2924. * <p>
  2925. * Application code will not use these methods explicitly, they
  2926. * are used internally by JTable.
  2927. *
  2928. * @param e the event received
  2929. * @see TableColumnModelListener
  2930. */
  2931. public void columnMarginChanged(ChangeEvent e) {
  2932. if (isEditing()) {
  2933. removeEditor();
  2934. }
  2935. TableColumn resizingColumn = getResizingColumn();
  2936. // Need to do this here, before the parent's
  2937. // layout manager calls getPreferredSize().
  2938. if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF) {
  2939. resizingColumn.setPreferredWidth(resizingColumn.getWidth());
  2940. }
  2941. resizeAndRepaint();
  2942. }
  2943. private int limit(int i, int a, int b) {
  2944. return Math.min(b, Math.max(i, a));
  2945. }
  2946. /**
  2947. * Invoked when the selection model of the <code>TableColumnModel</code>
  2948. * is changed.
  2949. * <p>
  2950. * Application code will not use these methods explicitly, they
  2951. * are used internally by JTable.
  2952. *
  2953. * @param e the event received
  2954. * @see TableColumnModelListener
  2955. */
  2956. public void columnSelectionChanged(ListSelectionEvent e) {
  2957. boolean isAdjusting = e.getValueIsAdjusting();
  2958. if (columnSelectionAdjusting && !isAdjusting) {
  2959. // The assumption is that when the model is no longer adjusting
  2960. // we will have already gotten all the changes, and therefore
  2961. // don't need to do an additional paint.
  2962. columnSelectionAdjusting = false;
  2963. return;
  2964. }
  2965. columnSelectionAdjusting = isAdjusting;
  2966. // The getCellRect() call will fail unless there is at least one row.
  2967. if (getRowCount() <= 0 || getColumnCount() <= 0) {
  2968. return;
  2969. }
  2970. int firstIndex = limit(e.getFirstIndex(), 0, getColumnCount()-1);
  2971. int lastIndex = limit(e.getLastIndex(), 0, getColumnCount()-1);
  2972. int minRow = 0;
  2973. int maxRow = getRowCount() - 1;
  2974. if (getRowSelectionAllowed()) {
  2975. minRow = selectionModel.getMinSelectionIndex();
  2976. maxRow = selectionModel.getMaxSelectionIndex();
  2977. int leadRow = selectionModel.getLeadSelectionIndex();
  2978. if (minRow == -1 || maxRow == -1) {
  2979. if (leadRow == -1) {
  2980. // nothing to repaint, return
  2981. return;
  2982. }
  2983. // only thing to repaint is the lead
  2984. minRow = maxRow = leadRow;
  2985. } else {
  2986. // We need to consider more than just the range between
  2987. // the min and max selected index. The lead row, which could
  2988. // be outside this range, should be considered also.
  2989. if (leadRow != -1) {
  2990. minRow = Math.min(minRow, leadRow);
  2991. maxRow = Math.max(maxRow, leadRow);
  2992. }
  2993. }
  2994. }
  2995. Rectangle firstColumnRect = getCellRect(minRow, firstIndex, false);
  2996. Rectangle lastColumnRect = getCellRect(maxRow, lastIndex, false);
  2997. Rectangle dirtyRegion = firstColumnRect.union(lastColumnRect);
  2998. repaint(dirtyRegion);
  2999. }
  3000. //
  3001. // Implementing ListSelectionListener interface
  3002. //
  3003. /**
  3004. * Invoked when the row selection changes -- repaints to show the new
  3005. * selection.
  3006. * <p>
  3007. * Application code will not use these methods explicitly, they
  3008. * are used internally by JTable.
  3009. *
  3010. * @param e the event received
  3011. * @see ListSelectionListener
  3012. */
  3013. public void valueChanged(ListSelectionEvent e) {
  3014. boolean isAdjusting = e.getValueIsAdjusting();
  3015. if (rowSelectionAdjusting && !isAdjusting) {
  3016. // The assumption is that when the model is no longer adjusting
  3017. // we will have already gotten all the changes, and therefore
  3018. // don't need to do an additional paint.
  3019. rowSelectionAdjusting = false;
  3020. return;
  3021. }
  3022. rowSelectionAdjusting = isAdjusting;
  3023. // The getCellRect() calls will fail unless there is at least one column.
  3024. if (getRowCount() <= 0 || getColumnCount() <= 0) {
  3025. return;
  3026. }
  3027. int firstIndex = limit(e.getFirstIndex(), 0, getRowCount()-1);
  3028. int lastIndex = limit(e.getLastIndex(), 0, getRowCount()-1);
  3029. Rectangle firstRowRect = getCellRect(firstIndex, 0, false);
  3030. Rectangle lastRowRect = getCellRect(lastIndex, getColumnCount()-1, false);
  3031. Rectangle dirtyRegion = firstRowRect.union(lastRowRect);
  3032. repaint(dirtyRegion);
  3033. }
  3034. //
  3035. // Implementing the CellEditorListener interface
  3036. //
  3037. /**
  3038. * Invoked when editing is finished. The changes are saved and the
  3039. * editor is discarded.
  3040. * <p>
  3041. * Application code will not use these methods explicitly, they
  3042. * are used internally by JTable.
  3043. *
  3044. * @param e the event received
  3045. * @see CellEditorListener
  3046. */
  3047. public void editingStopped(ChangeEvent e) {
  3048. // Take in the new value
  3049. TableCellEditor editor = getCellEditor();
  3050. if (editor != null) {
  3051. Object value = editor.getCellEditorValue();
  3052. setValueAt(value, editingRow, editingColumn);
  3053. removeEditor();
  3054. }
  3055. }
  3056. /**
  3057. * Invoked when editing is canceled. The editor object is discarded
  3058. * and the cell is rendered once again.
  3059. * <p>
  3060. * Application code will not use these methods explicitly, they
  3061. * are used internally by JTable.
  3062. *
  3063. * @param e the event received
  3064. * @see CellEditorListener
  3065. */
  3066. public void editingCanceled(ChangeEvent e) {
  3067. removeEditor();
  3068. }
  3069. //
  3070. // Implementing the Scrollable interface
  3071. //
  3072. /**
  3073. * Sets the preferred size of the viewport for this table.
  3074. *
  3075. * @param size a <code>Dimension</code> object specifying the <code>preferredSize</code> of a
  3076. * <code>JViewport</code> whose view is this table
  3077. * @see Scrollable#getPreferredScrollableViewportSize
  3078. * @beaninfo
  3079. * description: The preferred size of the viewport.
  3080. */
  3081. public void setPreferredScrollableViewportSize(Dimension size) {
  3082. preferredViewportSize = size;
  3083. }
  3084. /**
  3085. * Returns the preferred size of the viewport for this table.
  3086. *
  3087. * @return a <code>Dimension</code> object containing the <code>preferredSize</code> of the <code>JViewport</code>
  3088. * which displays this table
  3089. * @see Scrollable#getPreferredScrollableViewportSize
  3090. */
  3091. public Dimension getPreferredScrollableViewportSize() {
  3092. return preferredViewportSize;
  3093. }
  3094. /**
  3095. * Returns the scroll increment (in pixels) that completely exposes one new
  3096. * row or column (depending on the orientation).
  3097. * <p>
  3098. * This method is called each time the user requests a unit scroll.
  3099. *
  3100. * @param visibleRect the view area visible within the viewport
  3101. * @param orientation either <code>SwingConstants.VERTICAL</code>
  3102. * or <code>SwingConstants.HORIZONTAL</code>
  3103. * @param direction less than zero to scroll up/left,
  3104. * greater than zero for down/right
  3105. * @return the "unit" increment for scrolling in the specified direction
  3106. * @see Scrollable#getScrollableUnitIncrement
  3107. */
  3108. public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
  3109. int direction) {
  3110. // PENDING(alan): do something smarter
  3111. if (orientation == SwingConstants.HORIZONTAL) {
  3112. return 100;
  3113. }
  3114. return getRowHeight();
  3115. }
  3116. /**
  3117. * Returns <code>visibleRect.height</code> or
  3118. * <code>visibleRect.width</code>,
  3119. * depending on this table's orientation. Note that as of Swing 1.1.1
  3120. * (Java 2 v 1.2.2) the value
  3121. * returned will ensure that the viewport is cleanly aligned on
  3122. * a row boundary.
  3123. *
  3124. * @return <code>visibleRect.height</code> or
  3125. * <code>visibleRect.width</code>
  3126. * per the orientation
  3127. * @see Scrollable#getScrollableBlockIncrement
  3128. */
  3129. public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation,
  3130. int direction) {
  3131. if (orientation == SwingConstants.VERTICAL) {
  3132. int rh = getRowHeight();
  3133. return (rh > 0) ? Math.max(rh, (visibleRect.height / rh) * rh) : visibleRect.height;
  3134. }
  3135. else {
  3136. return visibleRect.width;
  3137. }
  3138. }
  3139. /**
  3140. * Returns false if <code>autoResizeMode</code> is set to
  3141. * <code>AUTO_RESIZE_OFF</code>, which indicates that the
  3142. * width of the viewport does not determine the width
  3143. * of the table. Otherwise returns true.
  3144. *
  3145. * @return false if <code>autoResizeMode</code> is set
  3146. * to <code>AUTO_RESIZE_OFF</code>, otherwise returns true
  3147. * @see Scrollable#getScrollableTracksViewportWidth
  3148. */
  3149. public boolean getScrollableTracksViewportWidth() {
  3150. return !(autoResizeMode == AUTO_RESIZE_OFF);
  3151. }
  3152. /**
  3153. * Returns false to indicate that the height of the viewport does not
  3154. * determine the height of the table.
  3155. *
  3156. * @return false
  3157. * @see Scrollable#getScrollableTracksViewportHeight
  3158. */
  3159. public boolean getScrollableTracksViewportHeight() {
  3160. return false;
  3161. }
  3162. //
  3163. // Protected Methods
  3164. //
  3165. protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
  3166. int condition, boolean pressed) {
  3167. boolean retValue = super.processKeyBinding(ks, e, condition, pressed);
  3168. // Start editing when a key is typed. UI classes can disable this behavior
  3169. // by setting the client property JTable.autoStartsEdit to Boolean.FALSE.
  3170. if (!retValue && condition == WHEN_ANCESTOR_OF_FOCUSED_COMPONENT &&
  3171. isFocusOwner() &&
  3172. !Boolean.FALSE.equals((Boolean)getClientProperty("JTable.autoStartsEdit"))) {
  3173. // We do not have a binding for the event.
  3174. Component editorComponent = getEditorComponent();
  3175. if (editorComponent == null) {
  3176. // Only attempt to install the editor on a KEY_PRESSED,
  3177. if (e == null || e.getID() != KeyEvent.KEY_PRESSED) {
  3178. return false;
  3179. }
  3180. // Don't start when just a modifier is pressed
  3181. int code = e.getKeyCode();
  3182. if (code == KeyEvent.VK_SHIFT || code == KeyEvent.VK_CONTROL ||
  3183. code == KeyEvent.VK_ALT) {
  3184. return false;
  3185. }
  3186. // Try to install the editor
  3187. int leadRow = getSelectionModel().getLeadSelectionIndex();
  3188. int leadColumn = getColumnModel().getSelectionModel().
  3189. getLeadSelectionIndex();
  3190. if (leadRow != -1 && leadColumn != -1 && !isEditing()) {
  3191. if (!editCellAt(leadRow, leadColumn)) {
  3192. return false;
  3193. }
  3194. }
  3195. editorComponent = getEditorComponent();
  3196. if (editorComponent == null) {
  3197. return false;
  3198. }
  3199. }
  3200. // If the editorComponent is a JComponent, pass the event to it.
  3201. if (editorComponent instanceof JComponent) {
  3202. retValue = ((JComponent)editorComponent).processKeyBinding
  3203. (ks, e, WHEN_FOCUSED, pressed);
  3204. // If we have started an editor as a result of the user
  3205. // pressing a key and the surrendersFocusOnKeystroke property
  3206. // is true, give the focus to the new editor.
  3207. if (getSurrendersFocusOnKeystroke()) {
  3208. editorComponent.requestFocus();
  3209. }
  3210. }
  3211. }
  3212. return retValue;
  3213. }
  3214. private void setLazyValue(Hashtable h, Class c, String s) {
  3215. h.put(c, new UIDefaults.ProxyLazyValue(s));
  3216. }
  3217. private void setLazyRenderer(Class c, String s) {
  3218. setLazyValue(defaultRenderersByColumnClass, c, s);
  3219. }
  3220. /**
  3221. * Creates default cell renderers for objects, numbers, doubles, dates,
  3222. * booleans, and icons.
  3223. * @see javax.swing.table.DefaultTableCellRenderer
  3224. *
  3225. */
  3226. protected void createDefaultRenderers() {
  3227. defaultRenderersByColumnClass = new UIDefaults();
  3228. // Objects
  3229. setLazyRenderer(Object.class, "javax.swing.table.DefaultTableCellRenderer$UIResource");
  3230. // Numbers
  3231. setLazyRenderer(Number.class, "javax.swing.JTable$NumberRenderer");
  3232. // Doubles and Floats
  3233. setLazyRenderer(Float.class, "javax.swing.JTable$DoubleRenderer");
  3234. setLazyRenderer(Double.class, "javax.swing.JTable$DoubleRenderer");
  3235. // Dates
  3236. setLazyRenderer(Date.class, "javax.swing.JTable$DateRenderer");
  3237. // Icons and ImageIcons
  3238. setLazyRenderer(Icon.class, "javax.swing.JTable$IconRenderer");
  3239. setLazyRenderer(ImageIcon.class, "javax.swing.JTable$IconRenderer");
  3240. // Booleans
  3241. setLazyRenderer(Boolean.class, "javax.swing.JTable$BooleanRenderer");
  3242. }
  3243. /**
  3244. * Default Renderers
  3245. **/
  3246. static class NumberRenderer extends DefaultTableCellRenderer.UIResource {
  3247. public NumberRenderer() {
  3248. super();
  3249. setHorizontalAlignment(JLabel.RIGHT);
  3250. }
  3251. }
  3252. static class DoubleRenderer extends NumberRenderer {
  3253. NumberFormat formatter;
  3254. public DoubleRenderer() { super(); }
  3255. public void setValue(Object value) {
  3256. if (formatter == null) {
  3257. formatter = NumberFormat.getInstance();
  3258. }
  3259. setText((value == null) ? "" : formatter.format(value));
  3260. }
  3261. }
  3262. static class DateRenderer extends DefaultTableCellRenderer.UIResource {
  3263. DateFormat formatter;
  3264. public DateRenderer() { super(); }
  3265. public void setValue(Object value) {
  3266. if (formatter==null) {
  3267. formatter = DateFormat.getDateInstance();
  3268. }
  3269. setText((value == null) ? "" : formatter.format(value));
  3270. }
  3271. }
  3272. static class IconRenderer extends DefaultTableCellRenderer.UIResource {
  3273. public IconRenderer() {
  3274. super();
  3275. setHorizontalAlignment(JLabel.CENTER);
  3276. }
  3277. public void setValue(Object value) { setIcon((value instanceof Icon) ? (Icon)value : null); }
  3278. }
  3279. static class BooleanRenderer extends JCheckBox implements TableCellRenderer, UIResource
  3280. {
  3281. private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
  3282. public BooleanRenderer() {
  3283. super();
  3284. setHorizontalAlignment(JLabel.CENTER);
  3285. setBorderPainted(true);
  3286. }
  3287. public Component getTableCellRendererComponent(JTable table, Object value,
  3288. boolean isSelected, boolean hasFocus, int row, int column) {
  3289. if (isSelected) {
  3290. setForeground(table.getSelectionForeground());
  3291. super.setBackground(table.getSelectionBackground());
  3292. }
  3293. else {
  3294. setForeground(table.getForeground());
  3295. setBackground(table.getBackground());
  3296. }
  3297. setSelected((value != null && ((Boolean)value).booleanValue()));
  3298. if (hasFocus) {
  3299. setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
  3300. } else {
  3301. setBorder(noFocusBorder);
  3302. }
  3303. return this;
  3304. }
  3305. }
  3306. private void setLazyEditor(Class c, String s) {
  3307. setLazyValue(defaultEditorsByColumnClass, c, s);
  3308. }
  3309. /**
  3310. * Creates default cell editors for objects, numbers, and boolean values.
  3311. * @see DefaultCellEditor
  3312. */
  3313. protected void createDefaultEditors() {
  3314. defaultEditorsByColumnClass = new UIDefaults();
  3315. // Objects
  3316. setLazyEditor(Object.class, "javax.swing.JTable$GenericEditor");
  3317. // Numbers
  3318. setLazyEditor(Number.class, "javax.swing.JTable$NumberEditor");
  3319. // Booleans
  3320. setLazyEditor(Boolean.class, "javax.swing.JTable$BooleanEditor");
  3321. }
  3322. /**
  3323. * Default Editors
  3324. */
  3325. static class GenericEditor extends DefaultCellEditor {
  3326. Class[] argTypes = new Class[]{String.class};
  3327. java.lang.reflect.Constructor constructor;
  3328. Object value;
  3329. public GenericEditor() {
  3330. super(new JTextField());
  3331. getComponent().setName("Table.editor");
  3332. }
  3333. public boolean stopCellEditing() {
  3334. String s = (String)super.getCellEditorValue();
  3335. // Here we are dealing with the case where a user
  3336. // has deleted the string value in a cell, possibly
  3337. // after a failed validation. Return null, so that
  3338. // they have the option to replace the value with
  3339. // null or use escape to restore the original.
  3340. // For Strings, return "" for backward compatibility.
  3341. if ("".equals(s)) {
  3342. if (constructor.getDeclaringClass() == String.class) {
  3343. value = s;
  3344. }
  3345. super.stopCellEditing();
  3346. }
  3347. try {
  3348. value = constructor.newInstance(new Object[]{s});
  3349. }
  3350. catch (Exception e) {
  3351. ((JComponent)getComponent()).setBorder(new LineBorder(Color.red));
  3352. return false;
  3353. }
  3354. return super.stopCellEditing();
  3355. }
  3356. public Component getTableCellEditorComponent(JTable table, Object value,
  3357. boolean isSelected,
  3358. int row, int column) {
  3359. this.value = null;
  3360. ((JComponent)getComponent()).setBorder(new LineBorder(Color.black));
  3361. try {
  3362. Class type = table.getColumnClass(column);
  3363. // Since our obligation is to produce a value which is
  3364. // assignable for the required type it is OK to use the
  3365. // String constructor for columns which are declared
  3366. // to contain Objects. A String is an Object.
  3367. if (type == Object.class) {
  3368. type = String.class;
  3369. }
  3370. constructor = type.getConstructor(argTypes);
  3371. }
  3372. catch (Exception e) {
  3373. return null;
  3374. }
  3375. return super.getTableCellEditorComponent(table, value, isSelected, row, column);
  3376. }
  3377. public Object getCellEditorValue() {
  3378. return value;
  3379. }
  3380. }
  3381. static class NumberEditor extends GenericEditor {
  3382. public NumberEditor() {
  3383. ((JTextField)getComponent()).setHorizontalAlignment(JTextField.RIGHT);
  3384. }
  3385. }
  3386. static class BooleanEditor extends DefaultCellEditor {
  3387. public BooleanEditor() {
  3388. super(new JCheckBox());
  3389. JCheckBox checkBox = (JCheckBox)getComponent();
  3390. checkBox.setHorizontalAlignment(JCheckBox.CENTER);
  3391. }
  3392. }
  3393. /**
  3394. * Initializes table properties to their default values.
  3395. */
  3396. protected void initializeLocalVars() {
  3397. setOpaque(true);
  3398. createDefaultRenderers();
  3399. createDefaultEditors();
  3400. setTableHeader(createDefaultTableHeader());
  3401. setShowGrid(true);
  3402. setAutoResizeMode(AUTO_RESIZE_SUBSEQUENT_COLUMNS);
  3403. setRowHeight(16);
  3404. isRowHeightSet = false;
  3405. setRowMargin(1);
  3406. setRowSelectionAllowed(true);
  3407. setCellEditor(null);
  3408. setEditingColumn(-1);
  3409. setEditingRow(-1);
  3410. setSurrendersFocusOnKeystroke(false);
  3411. setPreferredScrollableViewportSize(new Dimension(450, 400));
  3412. // I'm registered to do tool tips so we can draw tips for the renderers
  3413. ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
  3414. toolTipManager.registerComponent(this);
  3415. setAutoscrolls(true);
  3416. }
  3417. /**
  3418. * Returns the default table model object, which is
  3419. * a <code>DefaultTableModel</code>. A subclass can override this
  3420. * method to return a different table model object.
  3421. *
  3422. * @return the default table model object
  3423. * @see javax.swing.table.DefaultTableModel
  3424. */
  3425. protected TableModel createDefaultDataModel() {
  3426. return new DefaultTableModel();
  3427. }
  3428. /**
  3429. * Returns the default column model object, which is
  3430. * a <code>DefaultTableColumnModel</code>. A subclass can override this
  3431. * method to return a different column model object.
  3432. *
  3433. * @return the default column model object
  3434. * @see javax.swing.table.DefaultTableColumnModel
  3435. */
  3436. protected TableColumnModel createDefaultColumnModel() {
  3437. return new DefaultTableColumnModel();
  3438. }
  3439. /**
  3440. * Returns the default selection model object, which is
  3441. * a <code>DefaultListSelectionModel</code>. A subclass can override this
  3442. * method to return a different selection model object.
  3443. *
  3444. * @return the default selection model object
  3445. * @see javax.swing.DefaultListSelectionModel
  3446. */
  3447. protected ListSelectionModel createDefaultSelectionModel() {
  3448. return new DefaultListSelectionModel();
  3449. }
  3450. /**
  3451. * Returns the default table header object, which is
  3452. * a <code>JTableHeader</code>. A subclass can override this
  3453. * method to return a different table header object.
  3454. *
  3455. * @return the default table header object
  3456. * @see javax.swing.table.JTableHeader
  3457. */
  3458. protected JTableHeader createDefaultTableHeader() {
  3459. return new JTableHeader(columnModel);
  3460. }
  3461. /**
  3462. * Equivalent to <code>revalidate</code> followed by <code>repaint</code>.
  3463. */
  3464. protected void resizeAndRepaint() {
  3465. revalidate();
  3466. repaint();
  3467. }
  3468. /**
  3469. * Returns the cell editor.
  3470. *
  3471. * @return the <code>TableCellEditor</code> that does the editing
  3472. * @see #cellEditor
  3473. */
  3474. public TableCellEditor getCellEditor() {
  3475. return cellEditor;
  3476. }
  3477. /**
  3478. * Sets the <code>cellEditor</code> variable.
  3479. *
  3480. * @param anEditor the TableCellEditor that does the editing
  3481. * @see #cellEditor
  3482. * @beaninfo
  3483. * bound: true
  3484. * description: The table's active cell editor, if one exists.
  3485. */
  3486. public void setCellEditor(TableCellEditor anEditor) {
  3487. TableCellEditor oldEditor = cellEditor;
  3488. cellEditor = anEditor;
  3489. firePropertyChange("tableCellEditor", oldEditor, anEditor);
  3490. }
  3491. /**
  3492. * Sets the <code>editingColumn</code> variable.
  3493. * @param aColumn the column of the cell to be edited
  3494. *
  3495. * @see #editingColumn
  3496. */
  3497. public void setEditingColumn(int aColumn) {
  3498. editingColumn = aColumn;
  3499. }
  3500. /**
  3501. * Sets the <code>editingRow</code> variable.
  3502. * @param aRow the row of the cell to be edited
  3503. *
  3504. * @see #editingRow
  3505. */
  3506. public void setEditingRow(int aRow) {
  3507. editingRow = aRow;
  3508. }
  3509. /**
  3510. * Returns an appropriate renderer for the cell specified by this row and
  3511. * column. If the <code>TableColumn</code> for this column has a non-null
  3512. * renderer, returns that. If not, finds the class of the data in
  3513. * this column (using <code>getColumnClass</code>)
  3514. * and returns the default renderer for this type of data.
  3515. * <p>
  3516. * <b>Note:</b>
  3517. * Throughout the table package, the internal implementations always
  3518. * use this method to provide renderers so that this default behavior
  3519. * can be safely overridden by a subclass.
  3520. *
  3521. * @param row the row of the cell to render, where 0 is the first row
  3522. * @param column the column of the cell to render,
  3523. * where 0 is the first column
  3524. * @return the assigned renderer; if <code>null</code>
  3525. * returns the default renderer
  3526. * for this type of object
  3527. * @see javax.swing.table.DefaultTableCellRenderer
  3528. * @see javax.swing.table.TableColumn#setCellRenderer
  3529. * @see #setDefaultRenderer
  3530. */
  3531. public TableCellRenderer getCellRenderer(int row, int column) {
  3532. TableColumn tableColumn = getColumnModel().getColumn(column);
  3533. TableCellRenderer renderer = tableColumn.getCellRenderer();
  3534. if (renderer == null) {
  3535. renderer = getDefaultRenderer(getColumnClass(column));
  3536. }
  3537. return renderer;
  3538. }
  3539. /**
  3540. * Prepares the renderer by querying the data model for the
  3541. * value and selection state
  3542. * of the cell at <code>row</code>, <code>column</code>.
  3543. * Returns the component (may be a <code>Component</code>
  3544. * or a <code>JComponent</code>) under the event location.
  3545. * <p>
  3546. * <b>Note:</b>
  3547. * Throughout the table package, the internal implementations always
  3548. * use this method to prepare renderers so that this default behavior
  3549. * can be safely overridden by a subclass.
  3550. *
  3551. * @param renderer the <code>TableCellRenderer</code> to prepare
  3552. * @param row the row of the cell to render, where 0 is the first row
  3553. * @param column the column of the cell to render,
  3554. * where 0 is the first column
  3555. * @return the <code>Component</code> under the event location
  3556. */
  3557. public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
  3558. Object value = getValueAt(row, column);
  3559. boolean isSelected = false;
  3560. boolean hasFocus = false;
  3561. // Only indicate the selection and focused cell if not printing
  3562. if (!isPrinting) {
  3563. isSelected = isCellSelected(row, column);
  3564. boolean rowIsLead =
  3565. (selectionModel.getLeadSelectionIndex() == row);
  3566. boolean colIsLead =
  3567. (columnModel.getSelectionModel().getLeadSelectionIndex() == column);
  3568. hasFocus = (rowIsLead && colIsLead) && isFocusOwner();
  3569. }
  3570. return renderer.getTableCellRendererComponent(this, value,
  3571. isSelected, hasFocus,
  3572. row, column);
  3573. }
  3574. /**
  3575. * Returns an appropriate editor for the cell specified by
  3576. * <code>row</code> and <code>column</code>. If the
  3577. * <code>TableColumn</code> for this column has a non-null editor,
  3578. * returns that. If not, finds the class of the data in this
  3579. * column (using <code>getColumnClass</code>)
  3580. * and returns the default editor for this type of data.
  3581. * <p>
  3582. * <b>Note:</b>
  3583. * Throughout the table package, the internal implementations always
  3584. * use this method to provide editors so that this default behavior
  3585. * can be safely overridden by a subclass.
  3586. *
  3587. * @param row the row of the cell to edit, where 0 is the first row
  3588. * @param column the column of the cell to edit,
  3589. * where 0 is the first column
  3590. * @return the editor for this cell;
  3591. * if <code>null</code> return the default editor for
  3592. * this type of cell
  3593. * @see DefaultCellEditor
  3594. */
  3595. public TableCellEditor getCellEditor(int row, int column) {
  3596. TableColumn tableColumn = getColumnModel().getColumn(column);
  3597. TableCellEditor editor = tableColumn.getCellEditor();
  3598. if (editor == null) {
  3599. editor = getDefaultEditor(getColumnClass(column));
  3600. }
  3601. return editor;
  3602. }
  3603. /**
  3604. * Prepares the editor by querying the data model for the value and
  3605. * selection state of the cell at <code>row</code>, <code>column</code>.
  3606. * <p>
  3607. * <b>Note:</b>
  3608. * Throughout the table package, the internal implementations always
  3609. * use this method to prepare editors so that this default behavior
  3610. * can be safely overridden by a subclass.
  3611. *
  3612. * @param editor the <code>TableCellEditor</code> to set up
  3613. * @param row the row of the cell to edit,
  3614. * where 0 is the first row
  3615. * @param column the column of the cell to edit,
  3616. * where 0 is the first column
  3617. * @return the <code>Component</code> being edited
  3618. */
  3619. public Component prepareEditor(TableCellEditor editor, int row, int column) {
  3620. Object value = getValueAt(row, column);
  3621. boolean isSelected = isCellSelected(row, column);
  3622. Component comp = editor.getTableCellEditorComponent(this, value, isSelected,
  3623. row, column);
  3624. if (comp instanceof JComponent) {
  3625. JComponent jComp = (JComponent)comp;
  3626. if (jComp.getNextFocusableComponent() == null) {
  3627. jComp.setNextFocusableComponent(this);
  3628. }
  3629. }
  3630. return comp;
  3631. }
  3632. /**
  3633. * Discards the editor object and frees the real estate it used for
  3634. * cell rendering.
  3635. */
  3636. public void removeEditor() {
  3637. KeyboardFocusManager.getCurrentKeyboardFocusManager().
  3638. removePropertyChangeListener("permanentFocusOwner", editorRemover);
  3639. editorRemover = null;
  3640. TableCellEditor editor = getCellEditor();
  3641. if(editor != null) {
  3642. editor.removeCellEditorListener(this);
  3643. if (editorComp != null) {
  3644. remove(editorComp);
  3645. }
  3646. Rectangle cellRect = getCellRect(editingRow, editingColumn, false);
  3647. setCellEditor(null);
  3648. setEditingColumn(-1);
  3649. setEditingRow(-1);
  3650. editorComp = null;
  3651. repaint(cellRect);
  3652. }
  3653. }
  3654. //
  3655. // Serialization
  3656. //
  3657. /**
  3658. * See readObject() and writeObject() in JComponent for more
  3659. * information about serialization in Swing.
  3660. */
  3661. private void writeObject(ObjectOutputStream s) throws IOException {
  3662. s.defaultWriteObject();
  3663. if (getUIClassID().equals(uiClassID)) {
  3664. byte count = JComponent.getWriteObjCounter(this);
  3665. JComponent.setWriteObjCounter(this, --count);
  3666. if (count == 0 && ui != null) {
  3667. ui.installUI(this);
  3668. }
  3669. }
  3670. }
  3671. private void readObject(ObjectInputStream s)
  3672. throws IOException, ClassNotFoundException
  3673. {
  3674. s.defaultReadObject();
  3675. if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  3676. ui.installUI(this);
  3677. }
  3678. createDefaultRenderers();
  3679. createDefaultEditors();
  3680. // If ToolTipText != null, then the tooltip has already been
  3681. // registered by JComponent.readObject() and we don't want
  3682. // to re-register here
  3683. if (getToolTipText() == null) {
  3684. ToolTipManager.sharedInstance().registerComponent(this);
  3685. }
  3686. }
  3687. /* Called from the JComponent's EnableSerializationFocusListener to
  3688. * do any Swing-specific pre-serialization configuration.
  3689. */
  3690. void compWriteObjectNotify() {
  3691. super.compWriteObjectNotify();
  3692. // If ToolTipText != null, then the tooltip has already been
  3693. // unregistered by JComponent.compWriteObjectNotify()
  3694. if (getToolTipText() == null) {
  3695. ToolTipManager.sharedInstance().unregisterComponent(this);
  3696. }
  3697. }
  3698. /**
  3699. * Returns a string representation of this table. This method
  3700. * is intended to be used only for debugging purposes, and the
  3701. * content and format of the returned string may vary between
  3702. * implementations. The returned string may be empty but may not
  3703. * be <code>null</code>.
  3704. *
  3705. * @return a string representation of this table
  3706. */
  3707. protected String paramString() {
  3708. String gridColorString = (gridColor != null ?
  3709. gridColor.toString() : "");
  3710. String showHorizontalLinesString = (showHorizontalLines ?
  3711. "true" : "false");
  3712. String showVerticalLinesString = (showVerticalLines ?
  3713. "true" : "false");
  3714. String autoResizeModeString;
  3715. if (autoResizeMode == AUTO_RESIZE_OFF) {
  3716. autoResizeModeString = "AUTO_RESIZE_OFF";
  3717. } else if (autoResizeMode == AUTO_RESIZE_NEXT_COLUMN) {
  3718. autoResizeModeString = "AUTO_RESIZE_NEXT_COLUMN";
  3719. } else if (autoResizeMode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) {
  3720. autoResizeModeString = "AUTO_RESIZE_SUBSEQUENT_COLUMNS";
  3721. } else if (autoResizeMode == AUTO_RESIZE_LAST_COLUMN) {
  3722. autoResizeModeString = "AUTO_RESIZE_LAST_COLUMN";
  3723. } else if (autoResizeMode == AUTO_RESIZE_ALL_COLUMNS) {
  3724. autoResizeModeString = "AUTO_RESIZE_ALL_COLUMNS";
  3725. } else autoResizeModeString = "";
  3726. String autoCreateColumnsFromModelString = (autoCreateColumnsFromModel ?
  3727. "true" : "false");
  3728. String preferredViewportSizeString = (preferredViewportSize != null ?
  3729. preferredViewportSize.toString()
  3730. : "");
  3731. String rowSelectionAllowedString = (rowSelectionAllowed ?
  3732. "true" : "false");
  3733. String cellSelectionEnabledString = (cellSelectionEnabled ?
  3734. "true" : "false");
  3735. String selectionForegroundString = (selectionForeground != null ?
  3736. selectionForeground.toString() :
  3737. "");
  3738. String selectionBackgroundString = (selectionBackground != null ?
  3739. selectionBackground.toString() :
  3740. "");
  3741. return super.paramString() +
  3742. ",autoCreateColumnsFromModel=" + autoCreateColumnsFromModelString +
  3743. ",autoResizeMode=" + autoResizeModeString +
  3744. ",cellSelectionEnabled=" + cellSelectionEnabledString +
  3745. ",editingColumn=" + editingColumn +
  3746. ",editingRow=" + editingRow +
  3747. ",gridColor=" + gridColorString +
  3748. ",preferredViewportSize=" + preferredViewportSizeString +
  3749. ",rowHeight=" + rowHeight +
  3750. ",rowMargin=" + rowMargin +
  3751. ",rowSelectionAllowed=" + rowSelectionAllowedString +
  3752. ",selectionBackground=" + selectionBackgroundString +
  3753. ",selectionForeground=" + selectionForegroundString +
  3754. ",showHorizontalLines=" + showHorizontalLinesString +
  3755. ",showVerticalLines=" + showVerticalLinesString;
  3756. }
  3757. // This class tracks changes in the keyboard focus state. It is used
  3758. // when the JTable is editing to determine when to cancel the edit.
  3759. // If focus switches to a component outside of the jtable, but in the
  3760. // same window, this will cancel editing.
  3761. class CellEditorRemover implements PropertyChangeListener {
  3762. KeyboardFocusManager focusManager;
  3763. public CellEditorRemover(KeyboardFocusManager fm) {
  3764. this.focusManager = fm;
  3765. }
  3766. public void propertyChange(PropertyChangeEvent ev) {
  3767. if (!isEditing() || getClientProperty("terminateEditOnFocusLost") != Boolean.TRUE) {
  3768. return;
  3769. }
  3770. Component c = focusManager.getPermanentFocusOwner();
  3771. while (c != null) {
  3772. if (c == JTable.this) {
  3773. // focus remains inside the table
  3774. return;
  3775. } else if ((c instanceof Window) ||
  3776. (c instanceof Applet && c.getParent() == null)) {
  3777. if (c == SwingUtilities.getRoot(JTable.this)) {
  3778. if (!getCellEditor().stopCellEditing()) {
  3779. getCellEditor().cancelCellEditing();
  3780. }
  3781. }
  3782. break;
  3783. }
  3784. c = c.getParent();
  3785. }
  3786. }
  3787. }
  3788. /////////////////
  3789. // Printing Support
  3790. /////////////////
  3791. /**
  3792. * A convenience method that displays a printing dialog, and then prints
  3793. * this <code>JTable</code> in mode <code>PrintMode.FIT_WIDTH</code>,
  3794. * with no header or footer text. A modal progress dialog, with an abort
  3795. * option, will be shown for the duration of printing.
  3796. * <p>
  3797. * Note: In headless mode, no dialogs will be shown.
  3798. *
  3799. * @return true, unless printing is cancelled by the user
  3800. * @throws PrinterException if an error in the print system causes the job
  3801. * to be aborted
  3802. * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
  3803. * boolean, PrintRequestAttributeSet, boolean)
  3804. * @see #getPrintable
  3805. *
  3806. * @since 1.5
  3807. */
  3808. public boolean print() throws PrinterException {
  3809. return print(PrintMode.FIT_WIDTH);
  3810. }
  3811. /**
  3812. * A convenience method that displays a printing dialog, and then prints
  3813. * this <code>JTable</code> in the given printing mode,
  3814. * with no header or footer text. A modal progress dialog, with an abort
  3815. * option, will be shown for the duration of printing.
  3816. * <p>
  3817. * Note: In headless mode, no dialogs will be shown.
  3818. *
  3819. * @param printMode the printing mode that the printable should use
  3820. * @return true, unless printing is cancelled by the user
  3821. * @throws PrinterException if an error in the print system causes the job
  3822. * to be aborted
  3823. * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
  3824. * boolean, PrintRequestAttributeSet, boolean)
  3825. * @see #getPrintable
  3826. *
  3827. * @since 1.5
  3828. */
  3829. public boolean print(PrintMode printMode) throws PrinterException {
  3830. return print(printMode, null, null);
  3831. }
  3832. /**
  3833. * A convenience method that displays a printing dialog, and then prints
  3834. * this <code>JTable</code> in the given printing mode,
  3835. * with the specified header and footer text. A modal progress dialog,
  3836. * with an abort option, will be shown for the duration of printing.
  3837. * <p>
  3838. * Note: In headless mode, no dialogs will be shown.
  3839. *
  3840. * @param printMode the printing mode that the printable should use
  3841. * @param headerFormat a <code>MessageFormat</code> specifying the text
  3842. * to be used in printing a header,
  3843. * or null for none
  3844. * @param footerFormat a <code>MessageFormat</code> specifying the text
  3845. * to be used in printing a footer,
  3846. * or null for none
  3847. * @return true, unless printing is cancelled by the user
  3848. * @throws PrinterException if an error in the print system causes the job
  3849. * to be aborted
  3850. * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
  3851. * boolean, PrintRequestAttributeSet, boolean)
  3852. * @see #getPrintable
  3853. *
  3854. * @since 1.5
  3855. */
  3856. public boolean print(PrintMode printMode,
  3857. MessageFormat headerFormat,
  3858. MessageFormat footerFormat) throws PrinterException {
  3859. boolean showDialogs = !GraphicsEnvironment.isHeadless();
  3860. return print(printMode, headerFormat, footerFormat,
  3861. showDialogs, null, showDialogs);
  3862. }
  3863. /**
  3864. * Print this <code>JTable</code>. Takes steps that the majority of
  3865. * developers would take in order to print a <code>JTable</code>.
  3866. * In short, it prepares the table, calls <code>getPrintable</code> to
  3867. * fetch an appropriate <code>Printable</code>, and then sends it to the
  3868. * printer.
  3869. * <p>
  3870. * A <code>boolean</code> parameter allows you to specify whether or not
  3871. * a printing dialog is displayed to the user. When it is, the user may
  3872. * use the dialog to change printing attributes or even cancel the print.
  3873. * Another parameter allows for printing attributes to be specified
  3874. * directly. This can be used either to provide the initial values for the
  3875. * print dialog, or to supply any needed attributes when the dialog is not
  3876. * shown.
  3877. * <p>
  3878. * A second <code>boolean</code> parameter allows you to specify whether
  3879. * or not to perform printing in an interactive mode. If <code>true</code>,
  3880. * a modal progress dialog, with an abort option, is displayed for the
  3881. * duration of printing . This dialog also prevents any user action which
  3882. * may affect the table. However, it can not prevent the table from being
  3883. * modified by code (for example, another thread that posts updates using
  3884. * <code>SwingUtilities.invokeLater</code>). It is therefore the
  3885. * responsibility of the developer to ensure that no other code modifies
  3886. * the table in any way during printing (invalid modifications include
  3887. * changes in: size, renderers, or underlying data). Printing behavior is
  3888. * undefined when the table is changed during printing.
  3889. * <p>
  3890. * If <code>false</code> is specified for this parameter, no dialog will
  3891. * be displayed and printing will begin immediately on the event-dispatch
  3892. * thread. This blocks any other events, including repaints, from being
  3893. * processed until printing is complete. Although this effectively prevents
  3894. * the table from being changed, it doesn't provide a good user experience.
  3895. * For this reason, specifying <code>false</code> is only recommended when
  3896. * printing from an application with no visible GUI.
  3897. * <p>
  3898. * Note: Attempting to show the printing dialog or run interactively, while
  3899. * in headless mode, will result in a <code>HeadlessException</code>.
  3900. * <p>
  3901. * Before fetching the printable, this method prepares the table in order
  3902. * to get the most desirable printed result. If the table is currently
  3903. * in an editing mode, it terminates the editing as gracefully as
  3904. * possible. It also ensures that the the table's current selection and
  3905. * focused cell are not indicated in the printed output. This is handled on
  3906. * the view level, and only for the duration of the printing, thus no
  3907. * notification needs to be sent to the selection models.
  3908. * <p>
  3909. * See {@link #getPrintable} for further description on how the
  3910. * table is printed.
  3911. *
  3912. * @param printMode the printing mode that the printable should use
  3913. * @param headerFormat a <code>MessageFormat</code> specifying the text
  3914. * to be used in printing a header,
  3915. * or null for none
  3916. * @param footerFormat a <code>MessageFormat</code> specifying the text
  3917. * to be used in printing a footer,
  3918. * or null for none
  3919. * @param showPrintDialog whether or not to display a print dialog
  3920. * @param attr a <code>PrintRequestAttributeSet</code>
  3921. * specifying any printing attributes,
  3922. * or null for none
  3923. * @param interactive whether or not to print in an interactive mode
  3924. * @return true, unless printing is cancelled by the user
  3925. * @throws PrinterException if an error in the print system causes the job
  3926. * to be aborted
  3927. * @throws HeadlessException if the method is asked to show a printing
  3928. * dialog or run interactively, and
  3929. * <code>GraphicsEnvironment.isHeadless</code>
  3930. * returns true
  3931. * @see #getPrintable
  3932. * @see java.awt.GraphicsEnvironment#isHeadless
  3933. *
  3934. * @since 1.5
  3935. */
  3936. public boolean print(PrintMode printMode,
  3937. MessageFormat headerFormat,
  3938. MessageFormat footerFormat,
  3939. boolean showPrintDialog,
  3940. PrintRequestAttributeSet attr,
  3941. boolean interactive) throws PrinterException,
  3942. HeadlessException {
  3943. // complain early if an invalid parameter is specified for headless mode
  3944. boolean isHeadless = GraphicsEnvironment.isHeadless();
  3945. if (isHeadless) {
  3946. if (showPrintDialog) {
  3947. throw new HeadlessException("Can't show print dialog.");
  3948. }
  3949. if (interactive) {
  3950. throw new HeadlessException("Can't run interactively.");
  3951. }
  3952. }
  3953. if (isEditing()) {
  3954. // try to stop cell editing, and failing that, cancel it
  3955. if (!getCellEditor().stopCellEditing()) {
  3956. getCellEditor().cancelCellEditing();
  3957. }
  3958. }
  3959. if (attr == null) {
  3960. attr = new HashPrintRequestAttributeSet();
  3961. }
  3962. // get a PrinterJob
  3963. final PrinterJob job = PrinterJob.getPrinterJob();
  3964. // fetch the Printable
  3965. Printable printable =
  3966. getPrintable(printMode, headerFormat, footerFormat);
  3967. if (interactive) {
  3968. // wrap the Printable so that we can print on another thread
  3969. printable = new ThreadSafePrintable(printable);
  3970. }
  3971. // set the printable on the PrinterJob
  3972. job.setPrintable(printable);
  3973. // if requested, show the print dialog
  3974. if (showPrintDialog && !job.printDialog(attr)) {
  3975. // the user cancelled the print dialog
  3976. return false;
  3977. }
  3978. // if not interactive, just print on this thread (no dialog)
  3979. if (!interactive) {
  3980. // set a flag to hide the selection and focused cell
  3981. isPrinting = true;
  3982. try {
  3983. // do the printing
  3984. job.print(attr);
  3985. } finally {
  3986. // restore the flag
  3987. isPrinting = false;
  3988. }
  3989. // we're done
  3990. return true;
  3991. }
  3992. // interactive, drive printing from another thread
  3993. // and show a modal status dialog for the duration
  3994. // prepare the status JOptionPane
  3995. String progressTitle =
  3996. UIManager.getString("PrintingDialog.titleProgressText");
  3997. String dialogInitialContent =
  3998. UIManager.getString("PrintingDialog.contentInitialText");
  3999. // this one's a MessageFormat since it must include the page
  4000. // number in its text
  4001. MessageFormat statusFormat =
  4002. new MessageFormat(
  4003. UIManager.getString("PrintingDialog.contentProgressText"));
  4004. String abortText =
  4005. UIManager.getString("PrintingDialog.abortButtonText");
  4006. String abortTooltip =
  4007. UIManager.getString("PrintingDialog.abortButtonToolTipText");
  4008. int abortMnemonic =
  4009. UIManager.getInt("PrintingDialog.abortButtonMnemonic", -1);
  4010. int abortMnemonicIndex =
  4011. UIManager.getInt("PrintingDialog.abortButtonDisplayedMnemonicIndex", -1);
  4012. final JButton abortButton = new JButton(abortText);
  4013. abortButton.setToolTipText(abortTooltip);
  4014. if (abortMnemonic != -1) {
  4015. abortButton.setMnemonic(abortMnemonic);
  4016. }
  4017. if (abortMnemonicIndex != -1) {
  4018. abortButton.setDisplayedMnemonicIndex(abortMnemonicIndex);
  4019. }
  4020. final JLabel statusLabel = new JLabel(dialogInitialContent);
  4021. JOptionPane abortPane = new JOptionPane(statusLabel,
  4022. JOptionPane.INFORMATION_MESSAGE,
  4023. JOptionPane.DEFAULT_OPTION,
  4024. null, new Object[] {abortButton},
  4025. abortButton);
  4026. // need a final reference to the printable for later
  4027. final ThreadSafePrintable wrappedPrintable =
  4028. (ThreadSafePrintable)printable;
  4029. // set the label which the wrapped printable will update
  4030. wrappedPrintable.startUpdatingStatus(statusFormat, statusLabel);
  4031. // The dialog should be centered over the viewport if the table is in one
  4032. Container parentComp = getParent() instanceof JViewport ? getParent() : this;
  4033. // create the dialog to display the JOptionPane
  4034. final JDialog abortDialog = abortPane.createDialog(parentComp, progressTitle);
  4035. // clicking the X button should not hide the dialog
  4036. abortDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
  4037. // the action that will abort printing
  4038. final Action abortAction = new AbstractAction() {
  4039. boolean isAborted = false;
  4040. public void actionPerformed(ActionEvent ae) {
  4041. if (!isAborted) {
  4042. isAborted = true;
  4043. // update the status dialog to indicate aborting
  4044. abortButton.setEnabled(false);
  4045. abortDialog.setTitle(
  4046. UIManager.getString("PrintingDialog.titleAbortingText"));
  4047. statusLabel.setText(
  4048. UIManager.getString("PrintingDialog.contentAbortingText"));
  4049. // we don't want the aborting status message to be clobbered
  4050. wrappedPrintable.stopUpdatingStatus();
  4051. // cancel the PrinterJob
  4052. job.cancel();
  4053. }
  4054. }
  4055. };
  4056. // clicking the abort button should abort printing
  4057. abortButton.addActionListener(abortAction);
  4058. // the look and feels set up a close action (typically bound
  4059. // to ESCAPE) that also needs to be modified to simply abort
  4060. // printing
  4061. abortPane.getActionMap().put("close", abortAction);
  4062. // clicking the X button should also abort printing
  4063. final WindowAdapter closeListener = new WindowAdapter() {
  4064. public void windowClosing(WindowEvent we) {
  4065. abortAction.actionPerformed(null);
  4066. }
  4067. };
  4068. abortDialog.addWindowListener(closeListener);
  4069. // make sure this is clear since we'll check it after
  4070. printError = null;
  4071. // to synchronize on
  4072. final Object lock = new Object();
  4073. // copied so we can access from the inner class
  4074. final PrintRequestAttributeSet copyAttr = attr;
  4075. // this runnable will be used to do the printing
  4076. // (and save any throwables) on another thread
  4077. Runnable runnable = new Runnable() {
  4078. public void run() {
  4079. try {
  4080. // do the printing
  4081. job.print(copyAttr);
  4082. } catch (Throwable t) {
  4083. // save any Throwable to be rethrown
  4084. synchronized(lock) {
  4085. printError = t;
  4086. }
  4087. } finally {
  4088. // we're finished - hide the dialog, allowing
  4089. // processing in the original EDT to continue
  4090. SwingUtilities.invokeLater(new Runnable() {
  4091. public void run() {
  4092. // don't want to notify the abort action
  4093. abortDialog.removeWindowListener(closeListener);
  4094. abortDialog.dispose();
  4095. }
  4096. });
  4097. }
  4098. }
  4099. };
  4100. // start printing on another thread
  4101. Thread th = new Thread(runnable);
  4102. th.start();
  4103. // show the modal status dialog (and wait for it to be hidden)
  4104. abortDialog.setVisible(true);
  4105. // dialog has been hidden
  4106. // look for any error that the printing may have generated
  4107. Throwable pe;
  4108. synchronized(lock) {
  4109. pe = printError;
  4110. printError = null;
  4111. }
  4112. // check the type of error and handle it
  4113. if (pe != null) {
  4114. // a subclass of PrinterException meaning the job was aborted,
  4115. // in this case, by the user
  4116. if (pe instanceof PrinterAbortException) {
  4117. return false;
  4118. } else if (pe instanceof PrinterException) {
  4119. throw (PrinterException)pe;
  4120. } else if (pe instanceof RuntimeException) {
  4121. throw (RuntimeException)pe;
  4122. } else if (pe instanceof Error) {
  4123. throw (Error)pe;
  4124. }
  4125. // can not happen
  4126. throw new AssertionError(pe);
  4127. }
  4128. return true;
  4129. }
  4130. /**
  4131. * Return a <code>Printable</code> for use in printing this JTable.
  4132. * <p>
  4133. * The <code>Printable</code> can be requested in one of two printing modes.
  4134. * In both modes, it spreads table rows naturally in sequence across
  4135. * multiple pages, fitting as many rows as possible per page.
  4136. * <code>PrintMode.NORMAL</code> specifies that the table be
  4137. * printed at its current size. In this mode, there may be a need to spread
  4138. * columns across pages in a similar manner to that of the rows. When the
  4139. * need arises, columns are distributed in an order consistent with the
  4140. * table's <code>ComponentOrientation</code>.
  4141. * <code>PrintMode.FIT_WIDTH</code> specifies that the output be
  4142. * scaled smaller, if necessary, to fit the table's entire width
  4143. * (and thereby all columns) on each page. Width and height are scaled
  4144. * equally, maintaining the aspect ratio of the output.
  4145. * <p>
  4146. * The <code>Printable</code> heads the portion of table on each page
  4147. * with the appropriate section from the table's <code>JTableHeader</code>,
  4148. * if it has one.
  4149. * <p>
  4150. * Header and footer text can be added to the output by providing
  4151. * <code>MessageFormat</code> arguments. The printing code requests
  4152. * Strings from the formats, providing a single item which may be included
  4153. * in the formatted string: an <code>Integer</code> representing the current
  4154. * page number.
  4155. * <p>
  4156. * You are encouraged to read the documentation for
  4157. * <code>MessageFormat</code> as some characters, such as single-quote,
  4158. * are special and need to be escaped.
  4159. * <p>
  4160. * Here's an example of creating a <code>MessageFormat</code> that can be
  4161. * used to print "Duke's Table: Page - " and the current page number:
  4162. * <p>
  4163. * <pre>
  4164. * // notice the escaping of the single quote
  4165. * // notice how the page number is included with "{0}"
  4166. * MessageFormat format = new MessageFormat("Duke''s Table: Page - {0}");
  4167. * </pre>
  4168. * <p>
  4169. * The <code>Printable</code> constrains what it draws to the printable
  4170. * area of each page that it prints. Under certain circumstances, it may
  4171. * find it impossible to fit all of a page's content into that area. In
  4172. * these cases the output may be clipped, but the implementation
  4173. * makes an effort to do something reasonable. Here are a few situations
  4174. * where this is known to occur, and how they may be handled by this
  4175. * particular implementation:
  4176. * <ul>
  4177. * <li>In any mode, when the header or footer text is too wide to fit
  4178. * completely in the printable area -- print as much of the text as
  4179. * possible starting from the beginning, as determined by the table's
  4180. * <code>ComponentOrientation</code>.
  4181. * <li>In any mode, when a row is too tall to fit in the
  4182. * printable area -- print the upper-most portion of the row
  4183. * and paint no lower border on the table.
  4184. * <li>In <code>PrintMode.NORMAL</code> when a column
  4185. * is too wide to fit in the printable area -- print the center
  4186. * portion of the column and leave the left and right borders
  4187. * off the table.
  4188. * </ul>
  4189. * <p>
  4190. * It is entirely valid for this <code>Printable</code> to be wrapped
  4191. * inside another in order to create complex reports and documents. You may
  4192. * even request that different pages be rendered into different sized
  4193. * printable areas. The implementation must be prepared to handle this
  4194. * (possibly by doing its layout calculations on the fly). However,
  4195. * providing different heights to each page will likely not work well
  4196. * with <code>PrintMode.NORMAL</code> when it has to spread columns
  4197. * across pages.
  4198. * <p>
  4199. * It is important to note that this <code>Printable</code> prints the
  4200. * table at its current visual state, using the table's existing renderers.
  4201. * <i>Before</i> calling this method, you may wish to <i>first</i> modify
  4202. * the state of the table (such as to change the renderers, cancel editing,
  4203. * or hide the selection).
  4204. * <p>
  4205. * You must not, however, modify the table in any way <i>after</i>
  4206. * this <code>Printable</code> is fetched (invalid modifications include
  4207. * changes in: size, renderers, or underlying data). The behavior of the
  4208. * returned <code>Printable</code> is undefined once the table has been
  4209. * changed.
  4210. * <p>
  4211. * Here's a simple example that calls this method to fetch a
  4212. * <code>Printable</code>, shows a cross-platform print dialog, and then
  4213. * prints the <code>Printable</code> unless the user cancels the dialog:
  4214. * <p>
  4215. * <pre>
  4216. * // prepare the table for printing here first (for example, hide selection)
  4217. *
  4218. * // wrap in a try/finally so table can be restored even if something fails
  4219. * try {
  4220. * // fetch the printable
  4221. * Printable printable = table.getPrintable(JTable.PrintMode.FIT_WIDTH,
  4222. * new MessageFormat("My Table"),
  4223. * new MessageFormat("Page - {0}"));
  4224. *
  4225. * // fetch a PrinterJob
  4226. * PrinterJob job = PrinterJob.getPrinterJob();
  4227. *
  4228. * // set the Printable on the PrinterJob
  4229. * job.setPrintable(printable);
  4230. *
  4231. * // create an attribute set to store attributes from the print dialog
  4232. * PrintRequestAttributeSet attr = new HashPrintRequestAttributeSet();
  4233. *
  4234. * // display a print dialog and record whether or not the user cancels it
  4235. * boolean printAccepted = job.printDialog(attr);
  4236. *
  4237. * // if the user didn't cancel the dialog
  4238. * if (printAccepted) {
  4239. * // do the printing (may need to handle PrinterException)
  4240. * job.print(attr);
  4241. * }
  4242. * } finally {
  4243. * // restore the original table state here (for example, restore selection)
  4244. * }
  4245. * </pre>
  4246. *
  4247. * @param printMode the printing mode that the printable should use
  4248. * @param headerFormat a <code>MessageFormat</code> specifying the text to
  4249. * be used in printing a header, or null for none
  4250. * @param footerFormat a <code>MessageFormat</code> specifying the text to
  4251. * be used in printing a footer, or null for none
  4252. * @return a <code>Printable</code> for printing this JTable
  4253. * @see Printable
  4254. * @see PrinterJob
  4255. *
  4256. * @since 1.5
  4257. */
  4258. public Printable getPrintable(PrintMode printMode,
  4259. MessageFormat headerFormat,
  4260. MessageFormat footerFormat) {
  4261. return new TablePrintable(this, printMode, headerFormat, footerFormat);
  4262. }
  4263. /**
  4264. * A <code>Printable</code> implementation that wraps another
  4265. * <code>Printable</code>, making it safe for printing on another thread.
  4266. * <p>
  4267. * Also performs steps that are specific to this table printing
  4268. * implementation, such as hiding the selection and focus in the table,
  4269. * and updating the given <code>JLabel</code> with the page number
  4270. * based on the specified message format.
  4271. */
  4272. private class ThreadSafePrintable implements Printable {
  4273. /** The delegate <code>Printable</code>. */
  4274. private Printable printDelegate;
  4275. /** The formatter to prepare the status message. */
  4276. private MessageFormat statusFormat;
  4277. /** The <code>JLabel</code> to update with the status. */
  4278. private JLabel statusLabel;
  4279. /**
  4280. * To communicate any return value when delegating.
  4281. */
  4282. private int retVal;
  4283. /**
  4284. * To communicate any <code>Throwable</code> when delegating.
  4285. */
  4286. private Throwable retThrowable;
  4287. /**
  4288. * Construct a <code>ThreadSafePrintable</code> around the given
  4289. * delegate.
  4290. *
  4291. * @param printDelegate the <code>Printable</code> to delegate to
  4292. */
  4293. public ThreadSafePrintable(Printable printDelegate) {
  4294. this.printDelegate = printDelegate;
  4295. }
  4296. /**
  4297. * Provide the <code>MessageFormat</code> and <code>JLabel</code>
  4298. * to use in updating the status.
  4299. *
  4300. * @param statusFormat the format to prepare the status message
  4301. * @param statusPane the JOptionPane to set the status message on
  4302. */
  4303. public void startUpdatingStatus(MessageFormat statusFormat,
  4304. JLabel statusLabel) {
  4305. this.statusFormat = statusFormat;
  4306. this.statusLabel = statusLabel;
  4307. }
  4308. /**
  4309. * Indicate that the <code>JLabel</code> should not be updated
  4310. * any more.
  4311. */
  4312. public void stopUpdatingStatus() {
  4313. statusFormat = null;
  4314. statusLabel = null;
  4315. }
  4316. /**
  4317. * Prints the specified page into the given {@link Graphics}
  4318. * context, in the specified format.
  4319. * <p>
  4320. * Regardless of what thread this method is called on, all calls into
  4321. * the delegate will be done on the event-dispatch thread.
  4322. *
  4323. * @param graphics the context into which the page is drawn
  4324. * @param pageFormat the size and orientation of the page being drawn
  4325. * @param pageIndex the zero based index of the page to be drawn
  4326. * @return PAGE_EXISTS if the page is rendered successfully, or
  4327. * NO_SUCH_PAGE if a non-existent page index is specified
  4328. * @throws PrinterException if an error causes printing to be aborted
  4329. */
  4330. public int print(final Graphics graphics,
  4331. final PageFormat pageFormat,
  4332. final int pageIndex) throws PrinterException {
  4333. // We'll use this Runnable
  4334. Runnable runnable = new Runnable() {
  4335. public synchronized void run() {
  4336. // set a flag to hide the selection and focused cell
  4337. isPrinting = true;
  4338. try {
  4339. if (statusLabel != null) {
  4340. // set the status message on the JOptionPane with
  4341. // the current page number
  4342. Object[] pageNumber = new Object[]{
  4343. new Integer(pageIndex + 1)};
  4344. statusLabel.setText(statusFormat.format(pageNumber));
  4345. }
  4346. // call into the delegate and save the return value
  4347. retVal = printDelegate.print(graphics, pageFormat, pageIndex);
  4348. } catch (Throwable throwable) {
  4349. // save any Throwable to be rethrown
  4350. retThrowable = throwable;
  4351. } finally {
  4352. // restore the flag
  4353. isPrinting = false;
  4354. // notify the caller that we're done
  4355. notifyAll();
  4356. }
  4357. }
  4358. };
  4359. synchronized(runnable) {
  4360. // make sure these are initialized
  4361. retVal = -1;
  4362. retThrowable = null;
  4363. // call into the EDT
  4364. SwingUtilities.invokeLater(runnable);
  4365. // wait for the runnable to finish
  4366. while (retVal == -1 && retThrowable == null) {
  4367. try {
  4368. runnable.wait();
  4369. } catch (InterruptedException ie) {
  4370. // short process, safe to ignore interrupts
  4371. }
  4372. }
  4373. // if the delegate threw a throwable, rethrow it here
  4374. if (retThrowable != null) {
  4375. if (retThrowable instanceof PrinterException) {
  4376. throw (PrinterException)retThrowable;
  4377. } else if (retThrowable instanceof RuntimeException) {
  4378. throw (RuntimeException)retThrowable;
  4379. } else if (retThrowable instanceof Error) {
  4380. throw (Error)retThrowable;
  4381. }
  4382. // can not happen
  4383. throw new AssertionError(retThrowable);
  4384. }
  4385. return retVal;
  4386. }
  4387. }
  4388. }
  4389. /////////////////
  4390. // Accessibility support
  4391. ////////////////
  4392. /**
  4393. * Gets the AccessibleContext associated with this JTable.
  4394. * For tables, the AccessibleContext takes the form of an
  4395. * AccessibleJTable.
  4396. * A new AccessibleJTable instance is created if necessary.
  4397. *
  4398. * @return an AccessibleJTable that serves as the
  4399. * AccessibleContext of this JTable
  4400. */
  4401. public AccessibleContext getAccessibleContext() {
  4402. if (accessibleContext == null) {
  4403. accessibleContext = new AccessibleJTable();
  4404. }
  4405. return accessibleContext;
  4406. }
  4407. //
  4408. // *** should also implement AccessibleSelection?
  4409. // *** and what's up with keyboard navigation/manipulation?
  4410. //
  4411. /**
  4412. * This class implements accessibility support for the
  4413. * <code>JTable</code> class. It provides an implementation of the
  4414. * Java Accessibility API appropriate to table user-interface elements.
  4415. * <p>
  4416. * <strong>Warning:</strong>
  4417. * Serialized objects of this class will not be compatible with
  4418. * future Swing releases. The current serialization support is
  4419. * appropriate for short term storage or RMI between applications running
  4420. * the same version of Swing. As of 1.4, support for long term storage
  4421. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  4422. * has been added to the <code>java.beans</code> package.
  4423. * Please see {@link java.beans.XMLEncoder}.
  4424. */
  4425. protected class AccessibleJTable extends AccessibleJComponent
  4426. implements AccessibleSelection, ListSelectionListener, TableModelListener,
  4427. TableColumnModelListener, CellEditorListener, PropertyChangeListener,
  4428. AccessibleExtendedTable {
  4429. int lastSelectedRow;
  4430. int lastSelectedCol;
  4431. /**
  4432. * AccessibleJTable constructor
  4433. *
  4434. * @since 1.5
  4435. */
  4436. protected AccessibleJTable() {
  4437. super();
  4438. JTable.this.addPropertyChangeListener(this);
  4439. JTable.this.getSelectionModel().addListSelectionListener(this);
  4440. TableColumnModel tcm = JTable.this.getColumnModel();
  4441. tcm.addColumnModelListener(this);
  4442. tcm.getSelectionModel().addListSelectionListener(this);
  4443. JTable.this.getModel().addTableModelListener(this);
  4444. lastSelectedRow = JTable.this.getSelectedRow();
  4445. lastSelectedCol = JTable.this.getSelectedColumn();
  4446. }
  4447. // Listeners to track model, etc. changes to as to re-place the other
  4448. // listeners
  4449. /**
  4450. * Track changes to selection model, column model, etc. so as to
  4451. * be able to re-place listeners on those in order to pass on
  4452. * information to the Accessibility PropertyChange mechanism
  4453. */
  4454. public void propertyChange(PropertyChangeEvent e) {
  4455. String name = e.getPropertyName();
  4456. Object oldValue = e.getOldValue();
  4457. Object newValue = e.getNewValue();
  4458. // re-set tableModel listeners
  4459. if (name.compareTo("model") == 0) {
  4460. if (oldValue != null && oldValue instanceof TableModel) {
  4461. ((TableModel) oldValue).removeTableModelListener(this);
  4462. }
  4463. if (newValue != null && newValue instanceof TableModel) {
  4464. ((TableModel) newValue).addTableModelListener(this);
  4465. }
  4466. // re-set selectionModel listeners
  4467. } else if (name.compareTo("selectionModel") == 0) {
  4468. Object source = e.getSource();
  4469. if (source == JTable.this) { // row selection model
  4470. if (oldValue != null &&
  4471. oldValue instanceof ListSelectionModel) {
  4472. ((ListSelectionModel) oldValue).removeListSelectionListener(this);
  4473. }
  4474. if (newValue != null &&
  4475. newValue instanceof ListSelectionModel) {
  4476. ((ListSelectionModel) newValue).addListSelectionListener(this);
  4477. }
  4478. } else if (source == JTable.this.getColumnModel()) {
  4479. if (oldValue != null &&
  4480. oldValue instanceof ListSelectionModel) {
  4481. ((ListSelectionModel) oldValue).removeListSelectionListener(this);
  4482. }
  4483. if (newValue != null &&
  4484. newValue instanceof ListSelectionModel) {
  4485. ((ListSelectionModel) newValue).addListSelectionListener(this);
  4486. }
  4487. } else {
  4488. // System.out.println("!!! Bug in source of selectionModel propertyChangeEvent");
  4489. }
  4490. // re-set columnModel listeners
  4491. // and column's selection property listener as well
  4492. } else if (name.compareTo("columnModel") == 0) {
  4493. if (oldValue != null && oldValue instanceof TableColumnModel) {
  4494. TableColumnModel tcm = (TableColumnModel) oldValue;
  4495. tcm.removeColumnModelListener(this);
  4496. tcm.getSelectionModel().removeListSelectionListener(this);
  4497. }
  4498. if (newValue != null && newValue instanceof TableColumnModel) {
  4499. TableColumnModel tcm = (TableColumnModel) newValue;
  4500. tcm.addColumnModelListener(this);
  4501. tcm.getSelectionModel().addListSelectionListener(this);
  4502. }
  4503. // re-se cellEditor listeners
  4504. } else if (name.compareTo("tableCellEditor") == 0) {
  4505. if (oldValue != null && oldValue instanceof TableCellEditor) {
  4506. ((TableCellEditor) oldValue).removeCellEditorListener((CellEditorListener) this);
  4507. }
  4508. if (newValue != null && newValue instanceof TableCellEditor) {
  4509. ((TableCellEditor) newValue).addCellEditorListener((CellEditorListener) this);
  4510. }
  4511. }
  4512. }
  4513. // Listeners to echo changes to the AccessiblePropertyChange mechanism
  4514. /*
  4515. * Describes a change in the accessible table model.
  4516. */
  4517. protected class AccessibleJTableModelChange
  4518. implements AccessibleTableModelChange {
  4519. protected int type;
  4520. protected int firstRow;
  4521. protected int lastRow;
  4522. protected int firstColumn;
  4523. protected int lastColumn;
  4524. protected AccessibleJTableModelChange(int type, int firstRow,
  4525. int lastRow, int firstColumn,
  4526. int lastColumn) {
  4527. this.type = type;
  4528. this.firstRow = firstRow;
  4529. this.lastRow = lastRow;
  4530. this.firstColumn = firstColumn;
  4531. this.lastColumn = lastColumn;
  4532. }
  4533. public int getType() {
  4534. return type;
  4535. }
  4536. public int getFirstRow() {
  4537. return firstRow;
  4538. }
  4539. public int getLastRow() {
  4540. return lastRow;
  4541. }
  4542. public int getFirstColumn() {
  4543. return firstColumn;
  4544. }
  4545. public int getLastColumn() {
  4546. return lastColumn;
  4547. }
  4548. }
  4549. /**
  4550. * Track changes to the table contents
  4551. */
  4552. public void tableChanged(TableModelEvent e) {
  4553. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  4554. null, null);
  4555. if (e != null) {
  4556. int firstColumn = e.getColumn();
  4557. int lastColumn = e.getColumn();
  4558. if (firstColumn == TableModelEvent.ALL_COLUMNS) {
  4559. firstColumn = 0;
  4560. lastColumn = getColumnCount() - 1;
  4561. }
  4562. // Fire a property change event indicating the table model
  4563. // has changed.
  4564. AccessibleJTableModelChange change =
  4565. new AccessibleJTableModelChange(e.getType(),
  4566. e.getFirstRow(),
  4567. e.getLastRow(),
  4568. firstColumn,
  4569. lastColumn);
  4570. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  4571. null, change);
  4572. }
  4573. }
  4574. /**
  4575. * Track changes to the table contents (row insertions)
  4576. */
  4577. public void tableRowsInserted(TableModelEvent e) {
  4578. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  4579. null, null);
  4580. // Fire a property change event indicating the table model
  4581. // has changed.
  4582. int firstColumn = e.getColumn();
  4583. int lastColumn = e.getColumn();
  4584. if (firstColumn == TableModelEvent.ALL_COLUMNS) {
  4585. firstColumn = 0;
  4586. lastColumn = getColumnCount() - 1;
  4587. }
  4588. AccessibleJTableModelChange change =
  4589. new AccessibleJTableModelChange(e.getType(),
  4590. e.getFirstRow(),
  4591. e.getLastRow(),
  4592. firstColumn,
  4593. lastColumn);
  4594. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  4595. null, change);
  4596. }
  4597. /**
  4598. * Track changes to the table contents (row deletions)
  4599. */
  4600. public void tableRowsDeleted(TableModelEvent e) {
  4601. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  4602. null, null);
  4603. // Fire a property change event indicating the table model
  4604. // has changed.
  4605. int firstColumn = e.getColumn();
  4606. int lastColumn = e.getColumn();
  4607. if (firstColumn == TableModelEvent.ALL_COLUMNS) {
  4608. firstColumn = 0;
  4609. lastColumn = getColumnCount() - 1;
  4610. }
  4611. AccessibleJTableModelChange change =
  4612. new AccessibleJTableModelChange(e.getType(),
  4613. e.getFirstRow(),
  4614. e.getLastRow(),
  4615. firstColumn,
  4616. lastColumn);
  4617. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  4618. null, change);
  4619. }
  4620. /**
  4621. * Track changes to the table contents (column insertions)
  4622. */
  4623. public void columnAdded(TableColumnModelEvent e) {
  4624. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  4625. null, null);
  4626. // Fire a property change event indicating the table model
  4627. // has changed.
  4628. int type = AccessibleTableModelChange.INSERT;
  4629. AccessibleJTableModelChange change =
  4630. new AccessibleJTableModelChange(type,
  4631. 0,
  4632. 0,
  4633. e.getFromIndex(),
  4634. e.getToIndex());
  4635. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  4636. null, change);
  4637. }
  4638. /**
  4639. * Track changes to the table contents (column deletions)
  4640. */
  4641. public void columnRemoved(TableColumnModelEvent e) {
  4642. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  4643. null, null);
  4644. // Fire a property change event indicating the table model
  4645. // has changed.
  4646. int type = AccessibleTableModelChange.DELETE;
  4647. AccessibleJTableModelChange change =
  4648. new AccessibleJTableModelChange(type,
  4649. 0,
  4650. 0,
  4651. e.getFromIndex(),
  4652. e.getToIndex());
  4653. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  4654. null, change);
  4655. }
  4656. /**
  4657. * Track changes of a column repositioning.
  4658. *
  4659. * @see TableColumnModelListener
  4660. */
  4661. public void columnMoved(TableColumnModelEvent e) {
  4662. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  4663. null, null);
  4664. // Fire property change events indicating the table model
  4665. // has changed.
  4666. int type = AccessibleTableModelChange.DELETE;
  4667. AccessibleJTableModelChange change =
  4668. new AccessibleJTableModelChange(type,
  4669. 0,
  4670. 0,
  4671. e.getFromIndex(),
  4672. e.getFromIndex());
  4673. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  4674. null, change);
  4675. int type2 = AccessibleTableModelChange.INSERT;
  4676. AccessibleJTableModelChange change2 =
  4677. new AccessibleJTableModelChange(type2,
  4678. 0,
  4679. 0,
  4680. e.getToIndex(),
  4681. e.getToIndex());
  4682. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
  4683. null, change2);
  4684. }
  4685. /**
  4686. * Track changes of a column moving due to margin changes.
  4687. *
  4688. * @see TableColumnModelListener
  4689. */
  4690. public void columnMarginChanged(ChangeEvent e) {
  4691. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  4692. null, null);
  4693. }
  4694. /**
  4695. * Track that the selection model of the TableColumnModel changed.
  4696. *
  4697. * @see TableColumnModelListener
  4698. */
  4699. public void columnSelectionChanged(ListSelectionEvent e) {
  4700. // we should now re-place our TableColumn listener
  4701. }
  4702. /**
  4703. * Track changes to a cell's contents.
  4704. *
  4705. * Invoked when editing is finished. The changes are saved, the
  4706. * editor object is discarded, and the cell is rendered once again.
  4707. *
  4708. * @see CellEditorListener
  4709. */
  4710. public void editingStopped(ChangeEvent e) {
  4711. // it'd be great if we could figure out which cell, and pass that
  4712. // somehow as a parameter
  4713. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  4714. null, null);
  4715. }
  4716. /**
  4717. * Invoked when editing is canceled. The editor object is discarded
  4718. * and the cell is rendered once again.
  4719. *
  4720. * @see CellEditorListener
  4721. */
  4722. public void editingCanceled(ChangeEvent e) {
  4723. // nothing to report, 'cause nothing changed
  4724. }
  4725. /**
  4726. * Track changes to table cell selections
  4727. */
  4728. public void valueChanged(ListSelectionEvent e) {
  4729. firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
  4730. Boolean.valueOf(false), Boolean.valueOf(true));
  4731. int selectedRow = JTable.this.getSelectedRow();
  4732. int selectedCol = JTable.this.getSelectedColumn();
  4733. if (selectedRow != lastSelectedRow ||
  4734. selectedCol != lastSelectedCol) {
  4735. Accessible oldA = getAccessibleAt(lastSelectedRow,
  4736. lastSelectedCol);
  4737. Accessible newA = getAccessibleAt(selectedRow, selectedCol);
  4738. firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
  4739. oldA, newA);
  4740. lastSelectedRow = selectedRow;
  4741. lastSelectedCol = selectedCol;
  4742. }
  4743. }
  4744. // AccessibleContext support
  4745. /**
  4746. * Get the AccessibleSelection associated with this object. In the
  4747. * implementation of the Java Accessibility API for this class,
  4748. * return this object, which is responsible for implementing the
  4749. * AccessibleSelection interface on behalf of itself.
  4750. *
  4751. * @return this object
  4752. */
  4753. public AccessibleSelection getAccessibleSelection() {
  4754. return this;
  4755. }
  4756. /**
  4757. * Gets the role of this object.
  4758. *
  4759. * @return an instance of AccessibleRole describing the role of the
  4760. * object
  4761. * @see AccessibleRole
  4762. */
  4763. public AccessibleRole getAccessibleRole() {
  4764. return AccessibleRole.TABLE;
  4765. }
  4766. /**
  4767. * Returns the <code>Accessible</code> child, if one exists,
  4768. * contained at the local coordinate <code>Point</code>.
  4769. *
  4770. * @param p the point defining the top-left corner of the
  4771. * <code>Accessible</code>, given in the coordinate space
  4772. * of the object's parent
  4773. * @return the <code>Accessible</code>, if it exists,
  4774. * at the specified location; else <code>null</code>
  4775. */
  4776. public Accessible getAccessibleAt(Point p) {
  4777. int column = columnAtPoint(p);
  4778. int row = rowAtPoint(p);
  4779. if ((column != -1) && (row != -1)) {
  4780. TableColumn aColumn = getColumnModel().getColumn(column);
  4781. TableCellRenderer renderer = aColumn.getCellRenderer();
  4782. if (renderer == null) {
  4783. Class<?> columnClass = getColumnClass(column);
  4784. renderer = getDefaultRenderer(columnClass);
  4785. }
  4786. Component component = renderer.getTableCellRendererComponent(
  4787. JTable.this, null, false, false,
  4788. row, column);
  4789. return new AccessibleJTableCell(JTable.this, row, column,
  4790. getAccessibleIndexAt(row, column));
  4791. }
  4792. return null;
  4793. }
  4794. /**
  4795. * Returns the number of accessible children in the object. If all
  4796. * of the children of this object implement <code>Accessible</code>,
  4797. * then this method should return the number of children of this object.
  4798. *
  4799. * @return the number of accessible children in the object
  4800. */
  4801. public int getAccessibleChildrenCount() {
  4802. return (JTable.this.getColumnCount() * JTable.this.getRowCount());
  4803. }
  4804. /**
  4805. * Returns the nth <code>Accessible</code> child of the object.
  4806. *
  4807. * @param i zero-based index of child
  4808. * @return the nth Accessible child of the object
  4809. */
  4810. public Accessible getAccessibleChild(int i) {
  4811. if (i < 0 || i >= getAccessibleChildrenCount()) {
  4812. return null;
  4813. } else {
  4814. // children increase across, and then down, for tables
  4815. // (arbitrary decision)
  4816. int column = getAccessibleColumnAtIndex(i);
  4817. int row = getAccessibleRowAtIndex(i);
  4818. TableColumn aColumn = getColumnModel().getColumn(column);
  4819. TableCellRenderer renderer = aColumn.getCellRenderer();
  4820. if (renderer == null) {
  4821. Class<?> columnClass = getColumnClass(column);
  4822. renderer = getDefaultRenderer(columnClass);
  4823. }
  4824. Component component = renderer.getTableCellRendererComponent(
  4825. JTable.this, null, false, false,
  4826. row, column);
  4827. return new AccessibleJTableCell(JTable.this, row, column,
  4828. getAccessibleIndexAt(row, column));
  4829. }
  4830. }
  4831. // AccessibleSelection support
  4832. /**
  4833. * Returns the number of <code>Accessible</code> children
  4834. * currently selected.
  4835. * If no children are selected, the return value will be 0.
  4836. *
  4837. * @return the number of items currently selected
  4838. */
  4839. public int getAccessibleSelectionCount() {
  4840. int rowsSel = JTable.this.getSelectedRowCount();
  4841. int colsSel = JTable.this.getSelectedColumnCount();
  4842. if (JTable.this.cellSelectionEnabled) { // a contiguous block
  4843. return rowsSel * colsSel;
  4844. } else {
  4845. // a column swath and a row swath, with a shared block
  4846. if (JTable.this.getRowSelectionAllowed() &&
  4847. JTable.this.getColumnSelectionAllowed()) {
  4848. return rowsSel * JTable.this.getColumnCount() +
  4849. colsSel * JTable.this.getRowCount() -
  4850. rowsSel * colsSel;
  4851. // just one or more rows in selection
  4852. } else if (JTable.this.getRowSelectionAllowed()) {
  4853. return rowsSel * JTable.this.getColumnCount();
  4854. // just one or more rows in selection
  4855. } else if (JTable.this.getColumnSelectionAllowed()) {
  4856. return colsSel * JTable.this.getRowCount();
  4857. } else {
  4858. return 0; // JTable doesn't allow selections
  4859. }
  4860. }
  4861. }
  4862. /**
  4863. * Returns an <code>Accessible</code> representing the
  4864. * specified selected child in the object. If there
  4865. * isn't a selection, or there are fewer children selected
  4866. * than the integer passed in, the return
  4867. * value will be <code>null</code>.
  4868. * <p>Note that the index represents the i-th selected child, which
  4869. * is different from the i-th child.
  4870. *
  4871. * @param i the zero-based index of selected children
  4872. * @return the i-th selected child
  4873. * @see #getAccessibleSelectionCount
  4874. */
  4875. public Accessible getAccessibleSelection(int i) {
  4876. if (i < 0 || i > getAccessibleSelectionCount()) {
  4877. return (Accessible) null;
  4878. }
  4879. int rowsSel = JTable.this.getSelectedRowCount();
  4880. int colsSel = JTable.this.getSelectedColumnCount();
  4881. int rowIndicies[] = getSelectedRows();
  4882. int colIndicies[] = getSelectedColumns();
  4883. int ttlCols = JTable.this.getColumnCount();
  4884. int ttlRows = JTable.this.getRowCount();
  4885. int r;
  4886. int c;
  4887. if (JTable.this.cellSelectionEnabled) { // a contiguous block
  4888. r = rowIndicies[i / colsSel];
  4889. c = colIndicies[i % colsSel];
  4890. return getAccessibleChild((r * ttlCols) + c);
  4891. } else {
  4892. // a column swath and a row swath, with a shared block
  4893. if (JTable.this.getRowSelectionAllowed() &&
  4894. JTable.this.getColumnSelectionAllowed()) {
  4895. // Situation:
  4896. // We have a table, like the 6x3 table below,
  4897. // wherein three colums and one row selected
  4898. // (selected cells marked with "*", unselected "0"):
  4899. //
  4900. // 0 * 0 * * 0
  4901. // * * * * * *
  4902. // 0 * 0 * * 0
  4903. //
  4904. // State machine below walks through the array of
  4905. // selected rows in two states: in a selected row,
  4906. // and not in one; continuing until we are in a row
  4907. // in which the ith selection exists. Then we return
  4908. // the appropriate cell. In the state machine, we
  4909. // always do rows above the "current" selected row first,
  4910. // then the cells in the selected row. If we're done
  4911. // with the state machine before finding the requested
  4912. // selected child, we handle the rows below the last
  4913. // selected row at the end.
  4914. //
  4915. int curIndex = i;
  4916. final int IN_ROW = 0;
  4917. final int NOT_IN_ROW = 1;
  4918. int state = (rowIndicies[0] == 0 ? IN_ROW : NOT_IN_ROW);
  4919. int j = 0;
  4920. int prevRow = -1;
  4921. while (j < rowIndicies.length) {
  4922. switch (state) {
  4923. case IN_ROW: // on individual row full of selections
  4924. if (curIndex < ttlCols) { // it's here!
  4925. c = curIndex % ttlCols;
  4926. r = rowIndicies[j];
  4927. return getAccessibleChild((r * ttlCols) + c);
  4928. } else { // not here
  4929. curIndex -= ttlCols;
  4930. }
  4931. // is the next row in table selected or not?
  4932. if (j + 1 == rowIndicies.length ||
  4933. rowIndicies[j] != rowIndicies[j+1] - 1) {
  4934. state = NOT_IN_ROW;
  4935. prevRow = rowIndicies[j];
  4936. }
  4937. j++; // we didn't return earlier, so go to next row
  4938. break;
  4939. case NOT_IN_ROW: // sparse bunch of rows of selections
  4940. if (curIndex <
  4941. (colsSel * (rowIndicies[j] -
  4942. (prevRow == -1 ? 0 : (prevRow + 1))))) {
  4943. // it's here!
  4944. c = colIndicies[curIndex % colsSel];
  4945. r = (j > 0 ? rowIndicies[j-1] + 1 : 0)
  4946. + curIndex / colsSel;
  4947. return getAccessibleChild((r * ttlCols) + c);
  4948. } else { // not here
  4949. curIndex -= colsSel * (rowIndicies[j] -
  4950. (prevRow == -1 ? 0 : (prevRow + 1)));
  4951. }
  4952. state = IN_ROW;
  4953. break;
  4954. }
  4955. }
  4956. // we got here, so we didn't find it yet; find it in
  4957. // the last sparse bunch of rows
  4958. if (curIndex <
  4959. (colsSel * (ttlRows -
  4960. (prevRow == -1 ? 0 : (prevRow + 1))))) { // it's here!
  4961. c = colIndicies[curIndex % colsSel];
  4962. r = rowIndicies[j-1] + curIndex / colsSel + 1;
  4963. return getAccessibleChild((r * ttlCols) + c);
  4964. } else { // not here
  4965. // we shouldn't get to this spot in the code!
  4966. // System.out.println("Bug in AccessibleJTable.getAccessibleSelection()");
  4967. }
  4968. // one or more rows selected
  4969. } else if (JTable.this.getRowSelectionAllowed()) {
  4970. c = i % ttlCols;
  4971. r = rowIndicies[i / ttlCols];
  4972. return getAccessibleChild((r * ttlCols) + c);
  4973. // one or more columns selected
  4974. } else if (JTable.this.getColumnSelectionAllowed()) {
  4975. c = colIndicies[i % colsSel];
  4976. r = i / colsSel;
  4977. return getAccessibleChild((r * ttlCols) + c);
  4978. }
  4979. }
  4980. return (Accessible) null;
  4981. }
  4982. /**
  4983. * Determines if the current child of this object is selected.
  4984. *
  4985. * @param i the zero-based index of the child in this
  4986. * <code>Accessible</code> object
  4987. * @return true if the current child of this object is selected
  4988. * @see AccessibleContext#getAccessibleChild
  4989. */
  4990. public boolean isAccessibleChildSelected(int i) {
  4991. int column = getAccessibleColumnAtIndex(i);
  4992. int row = getAccessibleRowAtIndex(i);
  4993. return JTable.this.isCellSelected(row, column);
  4994. }
  4995. /**
  4996. * Adds the specified <code>Accessible</code> child of the
  4997. * object to the object's selection. If the object supports
  4998. * multiple selections, the specified child is added to
  4999. * any existing selection, otherwise
  5000. * it replaces any existing selection in the object. If the
  5001. * specified child is already selected, this method has no effect.
  5002. * <p>
  5003. * This method only works on <code>JTable</code>s which have
  5004. * individual cell selection enabled.
  5005. *
  5006. * @param i the zero-based index of the child
  5007. * @see AccessibleContext#getAccessibleChild
  5008. */
  5009. public void addAccessibleSelection(int i) {
  5010. // TIGER - 4495286
  5011. int column = getAccessibleColumnAtIndex(i);
  5012. int row = getAccessibleRowAtIndex(i);
  5013. JTable.this.changeSelection(row, column, true, false);
  5014. }
  5015. /**
  5016. * Removes the specified child of the object from the object's
  5017. * selection. If the specified item isn't currently selected, this
  5018. * method has no effect.
  5019. * <p>
  5020. * This method only works on <code>JTables</code> which have
  5021. * individual cell selection enabled.
  5022. *
  5023. * @param i the zero-based index of the child
  5024. * @see AccessibleContext#getAccessibleChild
  5025. */
  5026. public void removeAccessibleSelection(int i) {
  5027. if (JTable.this.cellSelectionEnabled) {
  5028. int column = getAccessibleColumnAtIndex(i);
  5029. int row = getAccessibleRowAtIndex(i);
  5030. JTable.this.removeRowSelectionInterval(row, row);
  5031. JTable.this.removeColumnSelectionInterval(column, column);
  5032. }
  5033. }
  5034. /**
  5035. * Clears the selection in the object, so that no children in the
  5036. * object are selected.
  5037. */
  5038. public void clearAccessibleSelection() {
  5039. JTable.this.clearSelection();
  5040. }
  5041. /**
  5042. * Causes every child of the object to be selected, but only
  5043. * if the <code>JTable</code> supports multiple selections,
  5044. * and if individual cell selection is enabled.
  5045. */
  5046. public void selectAllAccessibleSelection() {
  5047. if (JTable.this.cellSelectionEnabled) {
  5048. JTable.this.selectAll();
  5049. }
  5050. }
  5051. // begin AccessibleExtendedTable implementation -------------
  5052. /**
  5053. * Returns the row number of an index in the table.
  5054. *
  5055. * @param index the zero-based index in the table
  5056. * @return the zero-based row of the table if one exists;
  5057. * otherwise -1.
  5058. */
  5059. public int getAccessibleRow(int index) {
  5060. return getAccessibleRowAtIndex(index);
  5061. }
  5062. /**
  5063. * Returns the column number of an index in the table.
  5064. *
  5065. * @param index the zero-based index in the table
  5066. * @return the zero-based column of the table if one exists;
  5067. * otherwise -1.
  5068. */
  5069. public int getAccessibleColumn(int index) {
  5070. return getAccessibleColumnAtIndex(index);
  5071. }
  5072. /**
  5073. * Returns the index at a row and column in the table.
  5074. *
  5075. * @param r zero-based row of the table
  5076. * @param c zero-based column of the table
  5077. * @return the zero-based index in the table if one exists;
  5078. * otherwise -1.
  5079. */
  5080. public int getAccessibleIndex(int r, int c) {
  5081. return getAccessibleIndexAt(r, c);
  5082. }
  5083. // end of AccessibleExtendedTable implementation ------------
  5084. // start of AccessibleTable implementation ------------------
  5085. private Accessible caption;
  5086. private Accessible summary;
  5087. private Accessible [] rowDescription;
  5088. private Accessible [] columnDescription;
  5089. /**
  5090. * Gets the <code>AccessibleTable</code> associated with this
  5091. * object. In the implementation of the Java Accessibility
  5092. * API for this class, return this object, which is responsible
  5093. * for implementing the <code>AccessibleTables</code> interface
  5094. * on behalf of itself.
  5095. *
  5096. * @return this object
  5097. */
  5098. public AccessibleTable getAccessibleTable() {
  5099. return this;
  5100. }
  5101. /**
  5102. * Returns the caption for the table.
  5103. *
  5104. * @return the caption for the table
  5105. */
  5106. public Accessible getAccessibleCaption() {
  5107. return this.caption;
  5108. }
  5109. /**
  5110. * Sets the caption for the table.
  5111. *
  5112. * @param a the caption for the table
  5113. */
  5114. public void setAccessibleCaption(Accessible a) {
  5115. Accessible oldCaption = caption;
  5116. this.caption = a;
  5117. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_CAPTION_CHANGED,
  5118. oldCaption, this.caption);
  5119. }
  5120. /**
  5121. * Returns the summary description of the table.
  5122. *
  5123. * @return the summary description of the table
  5124. */
  5125. public Accessible getAccessibleSummary() {
  5126. return this.summary;
  5127. }
  5128. /**
  5129. * Sets the summary description of the table.
  5130. *
  5131. * @param a the summary description of the table
  5132. */
  5133. public void setAccessibleSummary(Accessible a) {
  5134. Accessible oldSummary = summary;
  5135. this.summary = a;
  5136. firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_SUMMARY_CHANGED,
  5137. oldSummary, this.summary);
  5138. }
  5139. /*
  5140. * Returns the total number of rows in this table.
  5141. *
  5142. * @return the total number of rows in this table
  5143. */
  5144. public int getAccessibleRowCount() {
  5145. return JTable.this.getRowCount();
  5146. }
  5147. /*
  5148. * Returns the total number of columns in the table.
  5149. *
  5150. * @return the total number of columns in the table
  5151. */
  5152. public int getAccessibleColumnCount() {
  5153. return JTable.this.getColumnCount();
  5154. }
  5155. /*
  5156. * Returns the <code>Accessible</code> at a specified row
  5157. * and column in the table.
  5158. *
  5159. * @param r zero-based row of the table
  5160. * @param c zero-based column of the table
  5161. * @return the <code>Accessible</code> at the specified row and column
  5162. * in the table
  5163. */
  5164. public Accessible getAccessibleAt(int r, int c) {
  5165. return getAccessibleChild((r * getAccessibleColumnCount()) + c);
  5166. }
  5167. /**
  5168. * Returns the number of rows occupied by the <code>Accessible</code>
  5169. * at a specified row and column in the table.
  5170. *
  5171. * @return the number of rows occupied by the <code>Accessible</code>
  5172. * at a specified row and column in the table
  5173. */
  5174. public int getAccessibleRowExtentAt(int r, int c) {
  5175. return 1;
  5176. }
  5177. /**
  5178. * Returns the number of columns occupied by the
  5179. * <code>Accessible</code> at a given (row, column).
  5180. *
  5181. * @return the number of columns occupied by the <code>Accessible</code>
  5182. * at a specified row and column in the table
  5183. */
  5184. public int getAccessibleColumnExtentAt(int r, int c) {
  5185. return 1;
  5186. }
  5187. /**
  5188. * Returns the row headers as an <code>AccessibleTable</code>.
  5189. *
  5190. * @return an <code>AccessibleTable</code> representing the row
  5191. * headers
  5192. */
  5193. public AccessibleTable getAccessibleRowHeader() {
  5194. // row headers are not supported
  5195. return null;
  5196. }
  5197. /**
  5198. * Returns the row headers as an <code>AccessibleTable</code>.
  5199. *
  5200. * @return an <code>AccessibleTable</code> representing
  5201. * the row headers
  5202. */
  5203. public void setAccessibleRowHeader(AccessibleTable a) {
  5204. // row headers are not supported
  5205. }
  5206. /**
  5207. * Returns the column headers as an <code>AccessibleTable</code>.
  5208. *
  5209. * @return an <code>AccessibleTable</code> representing the column
  5210. * headers, or <code>null</code> if the table header is
  5211. * <code>null</code>
  5212. */
  5213. public AccessibleTable getAccessibleColumnHeader() {
  5214. JTableHeader header = JTable.this.getTableHeader();
  5215. return header == null ? null : new AccessibleTableHeader(header);
  5216. }
  5217. /*
  5218. * Private class representing a table column header
  5219. */
  5220. private class AccessibleTableHeader implements AccessibleTable {
  5221. private JTableHeader header;
  5222. private TableColumnModel headerModel;
  5223. AccessibleTableHeader(JTableHeader header) {
  5224. this.header = header;
  5225. this.headerModel = header.getColumnModel();
  5226. }
  5227. /**
  5228. * Returns the caption for the table.
  5229. *
  5230. * @return the caption for the table
  5231. */
  5232. public Accessible getAccessibleCaption() { return null; }
  5233. /**
  5234. * Sets the caption for the table.
  5235. *
  5236. * @param a the caption for the table
  5237. */
  5238. public void setAccessibleCaption(Accessible a) {}
  5239. /**
  5240. * Returns the summary description of the table.
  5241. *
  5242. * @return the summary description of the table
  5243. */
  5244. public Accessible getAccessibleSummary() { return null; }
  5245. /**
  5246. * Sets the summary description of the table
  5247. *
  5248. * @param a the summary description of the table
  5249. */
  5250. public void setAccessibleSummary(Accessible a) {}
  5251. /**
  5252. * Returns the number of rows in the table.
  5253. *
  5254. * @return the number of rows in the table
  5255. */
  5256. public int getAccessibleRowCount() { return 1; }
  5257. /**
  5258. * Returns the number of columns in the table.
  5259. *
  5260. * @return the number of columns in the table
  5261. */
  5262. public int getAccessibleColumnCount() {
  5263. return headerModel.getColumnCount();
  5264. }
  5265. /**
  5266. * Returns the Accessible at a specified row and column
  5267. * in the table.
  5268. *
  5269. * @param row zero-based row of the table
  5270. * @param column zero-based column of the table
  5271. * @return the Accessible at the specified row and column
  5272. */
  5273. public Accessible getAccessibleAt(int row, int column) {
  5274. // TIGER - 4715503
  5275. TableColumn aColumn = headerModel.getColumn(column);
  5276. TableCellRenderer renderer = aColumn.getHeaderRenderer();
  5277. if (renderer == null) {
  5278. renderer = header.getDefaultRenderer();
  5279. }
  5280. Component component = renderer.getTableCellRendererComponent(
  5281. header.getTable(),
  5282. aColumn.getHeaderValue(), false, false,
  5283. -1, column);
  5284. return new AccessibleJTableHeaderCell(row, column,
  5285. JTable.this.getTableHeader(),
  5286. component);
  5287. }
  5288. /**
  5289. * Returns the number of rows occupied by the Accessible at
  5290. * a specified row and column in the table.
  5291. *
  5292. * @return the number of rows occupied by the Accessible at a
  5293. * given specified (row, column)
  5294. */
  5295. public int getAccessibleRowExtentAt(int r, int c) { return 1; }
  5296. /**
  5297. * Returns the number of columns occupied by the Accessible at
  5298. * a specified row and column in the table.
  5299. *
  5300. * @return the number of columns occupied by the Accessible at a
  5301. * given specified row and column
  5302. */
  5303. public int getAccessibleColumnExtentAt(int r, int c) { return 1; }
  5304. /**
  5305. * Returns the row headers as an AccessibleTable.
  5306. *
  5307. * @return an AccessibleTable representing the row
  5308. * headers
  5309. */
  5310. public AccessibleTable getAccessibleRowHeader() { return null; }
  5311. /**
  5312. * Sets the row headers.
  5313. *
  5314. * @param table an AccessibleTable representing the
  5315. * row headers
  5316. */
  5317. public void setAccessibleRowHeader(AccessibleTable table) {}
  5318. /**
  5319. * Returns the column headers as an AccessibleTable.
  5320. *
  5321. * @return an AccessibleTable representing the column
  5322. * headers
  5323. */
  5324. public AccessibleTable getAccessibleColumnHeader() { return null; }
  5325. /**
  5326. * Sets the column headers.
  5327. *
  5328. * @param table an AccessibleTable representing the
  5329. * column headers
  5330. */
  5331. public void setAccessibleColumnHeader(AccessibleTable table) {}
  5332. /**
  5333. * Returns the description of the specified row in the table.
  5334. *
  5335. * @param r zero-based row of the table
  5336. * @return the description of the row
  5337. */
  5338. public Accessible getAccessibleRowDescription(int r) { return null; }
  5339. /**
  5340. * Sets the description text of the specified row of the table.
  5341. *
  5342. * @param r zero-based row of the table
  5343. * @param a the description of the row
  5344. */
  5345. public void setAccessibleRowDescription(int r, Accessible a) {}
  5346. /**
  5347. * Returns the description text of the specified column in the table.
  5348. *
  5349. * @param c zero-based column of the table
  5350. * @return the text description of the column
  5351. */
  5352. public Accessible getAccessibleColumnDescription(int c) { return null; }
  5353. /**
  5354. * Sets the description text of the specified column in the table.
  5355. *
  5356. * @param c zero-based column of the table
  5357. * @param a the text description of the column
  5358. */
  5359. public void setAccessibleColumnDescription(int c, Accessible a) {}
  5360. /**
  5361. * Returns a boolean value indicating whether the accessible at
  5362. * a specified row and column is selected.
  5363. *
  5364. * @param r zero-based row of the table
  5365. * @param c zero-based column of the table
  5366. * @return the boolean value true if the accessible at the
  5367. * row and column is selected. Otherwise, the boolean value
  5368. * false
  5369. */
  5370. public boolean isAccessibleSelected(int r, int c) { return false; }
  5371. /**
  5372. * Returns a boolean value indicating whether the specified row
  5373. * is selected.
  5374. *
  5375. * @param r zero-based row of the table
  5376. * @return the boolean value true if the specified row is selected.
  5377. * Otherwise, false.
  5378. */
  5379. public boolean isAccessibleRowSelected(int r) { return false; }
  5380. /**
  5381. * Returns a boolean value indicating whether the specified column
  5382. * is selected.
  5383. *
  5384. * @param r zero-based column of the table
  5385. * @return the boolean value true if the specified column is selected.
  5386. * Otherwise, false.
  5387. */
  5388. public boolean isAccessibleColumnSelected(int c) { return false; }
  5389. /**
  5390. * Returns the selected rows in a table.
  5391. *
  5392. * @return an array of selected rows where each element is a
  5393. * zero-based row of the table
  5394. */
  5395. public int [] getSelectedAccessibleRows() { return new int[0]; }
  5396. /**
  5397. * Returns the selected columns in a table.
  5398. *
  5399. * @return an array of selected columns where each element is a
  5400. * zero-based column of the table
  5401. */
  5402. public int [] getSelectedAccessibleColumns() { return new int[0]; }
  5403. }
  5404. /**
  5405. * Returns the column headers as an <code>AccessibleTable</code>.
  5406. *
  5407. * @return an <code>AccessibleTable</code> representing the column
  5408. * headers
  5409. */
  5410. public void setAccessibleColumnHeader(AccessibleTable a) {
  5411. // XXX not implemented
  5412. }
  5413. /**
  5414. * Returns the description of the specified row in the table.
  5415. *
  5416. * @param r zero-based row of the table
  5417. * @return the description of the row
  5418. */
  5419. public Accessible getAccessibleRowDescription(int r) {
  5420. if (r < 0 || r >= getAccessibleRowCount()) {
  5421. throw new IllegalArgumentException(new Integer(r).toString());
  5422. }
  5423. if (rowDescription == null) {
  5424. return null;
  5425. } else {
  5426. return rowDescription[r];
  5427. }
  5428. }
  5429. /**
  5430. * Sets the description text of the specified row of the table.
  5431. *
  5432. * @param r zero-based row of the table
  5433. * @param a the description of the row
  5434. */
  5435. public void setAccessibleRowDescription(int r, Accessible a) {
  5436. if (r < 0 || r >= getAccessibleRowCount()) {
  5437. throw new IllegalArgumentException(new Integer(r).toString());
  5438. }
  5439. if (rowDescription == null) {
  5440. int numRows = getAccessibleRowCount();
  5441. rowDescription = new Accessible[numRows];
  5442. }
  5443. rowDescription[r] = a;
  5444. }
  5445. /**
  5446. * Returns the description of the specified column in the table.
  5447. *
  5448. * @param c zero-based column of the table
  5449. * @return the description of the column
  5450. */
  5451. public Accessible getAccessibleColumnDescription(int c) {
  5452. if (c < 0 || c >= getAccessibleColumnCount()) {
  5453. throw new IllegalArgumentException(new Integer(c).toString());
  5454. }
  5455. if (columnDescription == null) {
  5456. return null;
  5457. } else {
  5458. return columnDescription[c];
  5459. }
  5460. }
  5461. /**
  5462. * Sets the description text of the specified column of the table.
  5463. *
  5464. * @param c zero-based column of the table
  5465. * @param a the description of the column
  5466. */
  5467. public void setAccessibleColumnDescription(int c, Accessible a) {
  5468. if (c < 0 || c >= getAccessibleColumnCount()) {
  5469. throw new IllegalArgumentException(new Integer(c).toString());
  5470. }
  5471. if (columnDescription == null) {
  5472. int numColumns = getAccessibleColumnCount();
  5473. columnDescription = new Accessible[numColumns];
  5474. }
  5475. columnDescription[c] = a;
  5476. }
  5477. /**
  5478. * Returns a boolean value indicating whether the accessible at a
  5479. * given (row, column) is selected.
  5480. *
  5481. * @param r zero-based row of the table
  5482. * @param c zero-based column of the table
  5483. * @return the boolean value true if the accessible at (row, column)
  5484. * is selected; otherwise, the boolean value false
  5485. */
  5486. public boolean isAccessibleSelected(int r, int c) {
  5487. return JTable.this.isCellSelected(r, c);
  5488. }
  5489. /**
  5490. * Returns a boolean value indicating whether the specified row
  5491. * is selected.
  5492. *
  5493. * @param r zero-based row of the table
  5494. * @return the boolean value true if the specified row is selected;
  5495. * otherwise, false
  5496. */
  5497. public boolean isAccessibleRowSelected(int r) {
  5498. return JTable.this.isRowSelected(r);
  5499. }
  5500. /**
  5501. * Returns a boolean value indicating whether the specified column
  5502. * is selected.
  5503. *
  5504. * @param c zero-based column of the table
  5505. * @return the boolean value true if the specified column is selected;
  5506. * otherwise, false
  5507. */
  5508. public boolean isAccessibleColumnSelected(int c) {
  5509. return JTable.this.isColumnSelected(c);
  5510. }
  5511. /**
  5512. * Returns the selected rows in a table.
  5513. *
  5514. * @return an array of selected rows where each element is a
  5515. * zero-based row of the table
  5516. */
  5517. public int [] getSelectedAccessibleRows() {
  5518. return JTable.this.getSelectedRows();
  5519. }
  5520. /**
  5521. * Returns the selected columns in a table.
  5522. *
  5523. * @return an array of selected columns where each element is a
  5524. * zero-based column of the table
  5525. */
  5526. public int [] getSelectedAccessibleColumns() {
  5527. return JTable.this.getSelectedColumns();
  5528. }
  5529. /**
  5530. * Returns the row at a given index into the table.
  5531. *
  5532. * @param i zero-based index into the table
  5533. * @return the row at a given index
  5534. */
  5535. public int getAccessibleRowAtIndex(int i) {
  5536. int columnCount = getAccessibleColumnCount();
  5537. if (columnCount == 0) {
  5538. return -1;
  5539. } else {
  5540. return (i / columnCount);
  5541. }
  5542. }
  5543. /**
  5544. * Returns the column at a given index into the table.
  5545. *
  5546. * @param i zero-based index into the table
  5547. * @return the column at a given index
  5548. */
  5549. public int getAccessibleColumnAtIndex(int i) {
  5550. int columnCount = getAccessibleColumnCount();
  5551. if (columnCount == 0) {
  5552. return -1;
  5553. } else {
  5554. return (i % columnCount);
  5555. }
  5556. }
  5557. /**
  5558. * Returns the index at a given (row, column) in the table.
  5559. *
  5560. * @param r zero-based row of the table
  5561. * @param c zero-based column of the table
  5562. * @return the index into the table
  5563. */
  5564. public int getAccessibleIndexAt(int r, int c) {
  5565. return ((r * getAccessibleColumnCount()) + c);
  5566. }
  5567. // end of AccessibleTable implementation --------------------
  5568. /**
  5569. * The class provides an implementation of the Java Accessibility
  5570. * API appropriate to table cells.
  5571. */
  5572. protected class AccessibleJTableCell extends AccessibleContext
  5573. implements Accessible, AccessibleComponent {
  5574. private JTable parent;
  5575. private int row;
  5576. private int column;
  5577. private int index;
  5578. /**
  5579. * Constructs an <code>AccessibleJTableHeaderEntry</code>.
  5580. */
  5581. public AccessibleJTableCell(JTable t, int r, int c, int i) {
  5582. parent = t;
  5583. row = r;
  5584. column = c;
  5585. index = i;
  5586. this.setAccessibleParent(parent);
  5587. }
  5588. /**
  5589. * Gets the <code>AccessibleContext</code> associated with this
  5590. * component. In the implementation of the Java Accessibility
  5591. * API for this class, return this object, which is its own
  5592. * <code>AccessibleContext</code>.
  5593. *
  5594. * @return this object
  5595. */
  5596. public AccessibleContext getAccessibleContext() {
  5597. return this;
  5598. }
  5599. private AccessibleContext getCurrentAccessibleContext() {
  5600. TableColumn aColumn = getColumnModel().getColumn(column);
  5601. TableCellRenderer renderer = aColumn.getCellRenderer();
  5602. if (renderer == null) {
  5603. Class<?> columnClass = getColumnClass(column);
  5604. renderer = getDefaultRenderer(columnClass);
  5605. }
  5606. Component component = renderer.getTableCellRendererComponent(
  5607. JTable.this, getValueAt(row, column),
  5608. false, false, row, column);
  5609. if (component instanceof Accessible) {
  5610. return ((Accessible) component).getAccessibleContext();
  5611. } else {
  5612. return null;
  5613. }
  5614. }
  5615. private Component getCurrentComponent() {
  5616. TableColumn aColumn = getColumnModel().getColumn(column);
  5617. TableCellRenderer renderer = aColumn.getCellRenderer();
  5618. if (renderer == null) {
  5619. Class<?> columnClass = getColumnClass(column);
  5620. renderer = getDefaultRenderer(columnClass);
  5621. }
  5622. return renderer.getTableCellRendererComponent(
  5623. JTable.this, null, false, false,
  5624. row, column);
  5625. }
  5626. // AccessibleContext methods
  5627. /**
  5628. * Gets the accessible name of this object.
  5629. *
  5630. * @return the localized name of the object; <code>null</code>
  5631. * if this object does not have a name
  5632. */
  5633. public String getAccessibleName() {
  5634. AccessibleContext ac = getCurrentAccessibleContext();
  5635. if (ac != null) {
  5636. String name = ac.getAccessibleName();
  5637. if ((name != null) && (name != "")) {
  5638. return ac.getAccessibleName();
  5639. }
  5640. }
  5641. if ((accessibleName != null) && (accessibleName != "")) {
  5642. return accessibleName;
  5643. } else {
  5644. return null;
  5645. }
  5646. }
  5647. /**
  5648. * Sets the localized accessible name of this object.
  5649. *
  5650. * @param s the new localized name of the object
  5651. */
  5652. public void setAccessibleName(String s) {
  5653. AccessibleContext ac = getCurrentAccessibleContext();
  5654. if (ac != null) {
  5655. ac.setAccessibleName(s);
  5656. } else {
  5657. super.setAccessibleName(s);
  5658. }
  5659. }
  5660. //
  5661. // *** should check toolTip text for desc. (needs MouseEvent)
  5662. //
  5663. /**
  5664. * Gets the accessible description of this object.
  5665. *
  5666. * @return the localized description of the object;
  5667. * <code>null</code> if this object does not have
  5668. * a description
  5669. */
  5670. public String getAccessibleDescription() {
  5671. AccessibleContext ac = getCurrentAccessibleContext();
  5672. if (ac != null) {
  5673. return ac.getAccessibleDescription();
  5674. } else {
  5675. return super.getAccessibleDescription();
  5676. }
  5677. }
  5678. /**
  5679. * Sets the accessible description of this object.
  5680. *
  5681. * @param s the new localized description of the object
  5682. */
  5683. public void setAccessibleDescription(String s) {
  5684. AccessibleContext ac = getCurrentAccessibleContext();
  5685. if (ac != null) {
  5686. ac.setAccessibleDescription(s);
  5687. } else {
  5688. super.setAccessibleDescription(s);
  5689. }
  5690. }
  5691. /**
  5692. * Gets the role of this object.
  5693. *
  5694. * @return an instance of <code>AccessibleRole</code>
  5695. * describing the role of the object
  5696. * @see AccessibleRole
  5697. */
  5698. public AccessibleRole getAccessibleRole() {
  5699. AccessibleContext ac = getCurrentAccessibleContext();
  5700. if (ac != null) {
  5701. return ac.getAccessibleRole();
  5702. } else {
  5703. return AccessibleRole.UNKNOWN;
  5704. }
  5705. }
  5706. /**
  5707. * Gets the state set of this object.
  5708. *
  5709. * @return an instance of <code>AccessibleStateSet</code>
  5710. * containing the current state set of the object
  5711. * @see AccessibleState
  5712. */
  5713. public AccessibleStateSet getAccessibleStateSet() {
  5714. AccessibleContext ac = getCurrentAccessibleContext();
  5715. AccessibleStateSet as = null;
  5716. if (ac != null) {
  5717. as = ac.getAccessibleStateSet();
  5718. }
  5719. if (as == null) {
  5720. as = new AccessibleStateSet();
  5721. }
  5722. Rectangle rjt = JTable.this.getVisibleRect();
  5723. Rectangle rcell = JTable.this.getCellRect(row, column, false);
  5724. if (rjt.intersects(rcell)) {
  5725. as.add(AccessibleState.SHOWING);
  5726. } else {
  5727. if (as.contains(AccessibleState.SHOWING)) {
  5728. as.remove(AccessibleState.SHOWING);
  5729. }
  5730. }
  5731. if (parent.isCellSelected(row, column)) {
  5732. as.add(AccessibleState.SELECTED);
  5733. } else if (as.contains(AccessibleState.SELECTED)) {
  5734. as.remove(AccessibleState.SELECTED);
  5735. }
  5736. if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
  5737. as.add(AccessibleState.ACTIVE);
  5738. }
  5739. as.add(AccessibleState.TRANSIENT);
  5740. return as;
  5741. }
  5742. /**
  5743. * Gets the <code>Accessible</code> parent of this object.
  5744. *
  5745. * @return the Accessible parent of this object;
  5746. * <code>null</code> if this object does not
  5747. * have an <code>Accessible</code> parent
  5748. */
  5749. public Accessible getAccessibleParent() {
  5750. return parent;
  5751. }
  5752. /**
  5753. * Gets the index of this object in its accessible parent.
  5754. *
  5755. * @return the index of this object in its parent; -1 if this
  5756. * object does not have an accessible parent
  5757. * @see #getAccessibleParent
  5758. */
  5759. public int getAccessibleIndexInParent() {
  5760. return index;
  5761. }
  5762. /**
  5763. * Returns the number of accessible children in the object.
  5764. *
  5765. * @return the number of accessible children in the object
  5766. */
  5767. public int getAccessibleChildrenCount() {
  5768. AccessibleContext ac = getCurrentAccessibleContext();
  5769. if (ac != null) {
  5770. return ac.getAccessibleChildrenCount();
  5771. } else {
  5772. return 0;
  5773. }
  5774. }
  5775. /**
  5776. * Returns the specified <code>Accessible</code> child of the
  5777. * object.
  5778. *
  5779. * @param i zero-based index of child
  5780. * @return the <code>Accessible</code> child of the object
  5781. */
  5782. public Accessible getAccessibleChild(int i) {
  5783. AccessibleContext ac = getCurrentAccessibleContext();
  5784. if (ac != null) {
  5785. Accessible accessibleChild = ac.getAccessibleChild(i);
  5786. ac.setAccessibleParent(this);
  5787. return accessibleChild;
  5788. } else {
  5789. return null;
  5790. }
  5791. }
  5792. /**
  5793. * Gets the locale of the component. If the component
  5794. * does not have a locale, then the locale of its parent
  5795. * is returned.
  5796. *
  5797. * @return this component's locale; if this component does
  5798. * not have a locale, the locale of its parent is returned
  5799. * @exception IllegalComponentStateException if the
  5800. * <code>Component</code> does not have its own locale
  5801. * and has not yet been added to a containment hierarchy
  5802. * such that the locale can be determined from the
  5803. * containing parent
  5804. * @see #setLocale
  5805. */
  5806. public Locale getLocale() {
  5807. AccessibleContext ac = getCurrentAccessibleContext();
  5808. if (ac != null) {
  5809. return ac.getLocale();
  5810. } else {
  5811. return null;
  5812. }
  5813. }
  5814. /**
  5815. * Adds a <code>PropertyChangeListener</code> to the listener list.
  5816. * The listener is registered for all properties.
  5817. *
  5818. * @param l the <code>PropertyChangeListener</code>
  5819. * to be added
  5820. */
  5821. public void addPropertyChangeListener(PropertyChangeListener l) {
  5822. AccessibleContext ac = getCurrentAccessibleContext();
  5823. if (ac != null) {
  5824. ac.addPropertyChangeListener(l);
  5825. } else {
  5826. super.addPropertyChangeListener(l);
  5827. }
  5828. }
  5829. /**
  5830. * Removes a <code>PropertyChangeListener</code> from the
  5831. * listener list. This removes a <code>PropertyChangeListener</code>
  5832. * that was registered for all properties.
  5833. *
  5834. * @param l the <code>PropertyChangeListener</code>
  5835. * to be removed
  5836. */
  5837. public void removePropertyChangeListener(PropertyChangeListener l) {
  5838. AccessibleContext ac = getCurrentAccessibleContext();
  5839. if (ac != null) {
  5840. ac.removePropertyChangeListener(l);
  5841. } else {
  5842. super.removePropertyChangeListener(l);
  5843. }
  5844. }
  5845. /**
  5846. * Gets the <code>AccessibleAction</code> associated with this
  5847. * object if one exists. Otherwise returns <code>null</code>.
  5848. *
  5849. * @return the <code>AccessibleAction</code>, or <code>null</code>
  5850. */
  5851. public AccessibleAction getAccessibleAction() {
  5852. return getCurrentAccessibleContext().getAccessibleAction();
  5853. }
  5854. /**
  5855. * Gets the <code>AccessibleComponent</code> associated with
  5856. * this object if one exists. Otherwise returns <code>null</code>.
  5857. *
  5858. * @return the <code>AccessibleComponent</code>, or
  5859. * <code>null</code>
  5860. */
  5861. public AccessibleComponent getAccessibleComponent() {
  5862. return this; // to override getBounds()
  5863. }
  5864. /**
  5865. * Gets the <code>AccessibleSelection</code> associated with
  5866. * this object if one exists. Otherwise returns <code>null</code>.
  5867. *
  5868. * @return the <code>AccessibleSelection</code>, or
  5869. * <code>null</code>
  5870. */
  5871. public AccessibleSelection getAccessibleSelection() {
  5872. return getCurrentAccessibleContext().getAccessibleSelection();
  5873. }
  5874. /**
  5875. * Gets the <code>AccessibleText</code> associated with this
  5876. * object if one exists. Otherwise returns <code>null</code>.
  5877. *
  5878. * @return the <code>AccessibleText</code>, or <code>null</code>
  5879. */
  5880. public AccessibleText getAccessibleText() {
  5881. return getCurrentAccessibleContext().getAccessibleText();
  5882. }
  5883. /**
  5884. * Gets the <code>AccessibleValue</code> associated with
  5885. * this object if one exists. Otherwise returns <code>null</code>.
  5886. *
  5887. * @return the <code>AccessibleValue</code>, or <code>null</code>
  5888. */
  5889. public AccessibleValue getAccessibleValue() {
  5890. return getCurrentAccessibleContext().getAccessibleValue();
  5891. }
  5892. // AccessibleComponent methods
  5893. /**
  5894. * Gets the background color of this object.
  5895. *
  5896. * @return the background color, if supported, of the object;
  5897. * otherwise, <code>null</code>
  5898. */
  5899. public Color getBackground() {
  5900. AccessibleContext ac = getCurrentAccessibleContext();
  5901. if (ac instanceof AccessibleComponent) {
  5902. return ((AccessibleComponent) ac).getBackground();
  5903. } else {
  5904. Component c = getCurrentComponent();
  5905. if (c != null) {
  5906. return c.getBackground();
  5907. } else {
  5908. return null;
  5909. }
  5910. }
  5911. }
  5912. /**
  5913. * Sets the background color of this object.
  5914. *
  5915. * @param c the new <code>Color</code> for the background
  5916. */
  5917. public void setBackground(Color c) {
  5918. AccessibleContext ac = getCurrentAccessibleContext();
  5919. if (ac instanceof AccessibleComponent) {
  5920. ((AccessibleComponent) ac).setBackground(c);
  5921. } else {
  5922. Component cp = getCurrentComponent();
  5923. if (cp != null) {
  5924. cp.setBackground(c);
  5925. }
  5926. }
  5927. }
  5928. /**
  5929. * Gets the foreground color of this object.
  5930. *
  5931. * @return the foreground color, if supported, of the object;
  5932. * otherwise, <code>null</code>
  5933. */
  5934. public Color getForeground() {
  5935. AccessibleContext ac = getCurrentAccessibleContext();
  5936. if (ac instanceof AccessibleComponent) {
  5937. return ((AccessibleComponent) ac).getForeground();
  5938. } else {
  5939. Component c = getCurrentComponent();
  5940. if (c != null) {
  5941. return c.getForeground();
  5942. } else {
  5943. return null;
  5944. }
  5945. }
  5946. }
  5947. /**
  5948. * Sets the foreground color of this object.
  5949. *
  5950. * @param c the new <code>Color</code> for the foreground
  5951. */
  5952. public void setForeground(Color c) {
  5953. AccessibleContext ac = getCurrentAccessibleContext();
  5954. if (ac instanceof AccessibleComponent) {
  5955. ((AccessibleComponent) ac).setForeground(c);
  5956. } else {
  5957. Component cp = getCurrentComponent();
  5958. if (cp != null) {
  5959. cp.setForeground(c);
  5960. }
  5961. }
  5962. }
  5963. /**
  5964. * Gets the <code>Cursor</code> of this object.
  5965. *
  5966. * @return the <code>Cursor</code>, if supported,
  5967. * of the object; otherwise, <code>null</code>
  5968. */
  5969. public Cursor getCursor() {
  5970. AccessibleContext ac = getCurrentAccessibleContext();
  5971. if (ac instanceof AccessibleComponent) {
  5972. return ((AccessibleComponent) ac).getCursor();
  5973. } else {
  5974. Component c = getCurrentComponent();
  5975. if (c != null) {
  5976. return c.getCursor();
  5977. } else {
  5978. Accessible ap = getAccessibleParent();
  5979. if (ap instanceof AccessibleComponent) {
  5980. return ((AccessibleComponent) ap).getCursor();
  5981. } else {
  5982. return null;
  5983. }
  5984. }
  5985. }
  5986. }
  5987. /**
  5988. * Sets the <code>Cursor</code> of this object.
  5989. *
  5990. * @param c the new <code>Cursor</code> for the object
  5991. */
  5992. public void setCursor(Cursor c) {
  5993. AccessibleContext ac = getCurrentAccessibleContext();
  5994. if (ac instanceof AccessibleComponent) {
  5995. ((AccessibleComponent) ac).setCursor(c);
  5996. } else {
  5997. Component cp = getCurrentComponent();
  5998. if (cp != null) {
  5999. cp.setCursor(c);
  6000. }
  6001. }
  6002. }
  6003. /**
  6004. * Gets the <code>Font</code> of this object.
  6005. *
  6006. * @return the <code>Font</code>,if supported,
  6007. * for the object; otherwise, <code>null</code>
  6008. */
  6009. public Font getFont() {
  6010. AccessibleContext ac = getCurrentAccessibleContext();
  6011. if (ac instanceof AccessibleComponent) {
  6012. return ((AccessibleComponent) ac).getFont();
  6013. } else {
  6014. Component c = getCurrentComponent();
  6015. if (c != null) {
  6016. return c.getFont();
  6017. } else {
  6018. return null;
  6019. }
  6020. }
  6021. }
  6022. /**
  6023. * Sets the <code>Font</code> of this object.
  6024. *
  6025. * @param f the new <code>Font</code> for the object
  6026. */
  6027. public void setFont(Font f) {
  6028. AccessibleContext ac = getCurrentAccessibleContext();
  6029. if (ac instanceof AccessibleComponent) {
  6030. ((AccessibleComponent) ac).setFont(f);
  6031. } else {
  6032. Component c = getCurrentComponent();
  6033. if (c != null) {
  6034. c.setFont(f);
  6035. }
  6036. }
  6037. }
  6038. /**
  6039. * Gets the <code>FontMetrics</code> of this object.
  6040. *
  6041. * @param f the <code>Font</code>
  6042. * @return the <code>FontMetrics</code> object, if supported;
  6043. * otherwise <code>null</code>
  6044. * @see #getFont
  6045. */
  6046. public FontMetrics getFontMetrics(Font f) {
  6047. AccessibleContext ac = getCurrentAccessibleContext();
  6048. if (ac instanceof AccessibleComponent) {
  6049. return ((AccessibleComponent) ac).getFontMetrics(f);
  6050. } else {
  6051. Component c = getCurrentComponent();
  6052. if (c != null) {
  6053. return c.getFontMetrics(f);
  6054. } else {
  6055. return null;
  6056. }
  6057. }
  6058. }
  6059. /**
  6060. * Determines if the object is enabled.
  6061. *
  6062. * @return true if object is enabled; otherwise, false
  6063. */
  6064. public boolean isEnabled() {
  6065. AccessibleContext ac = getCurrentAccessibleContext();
  6066. if (ac instanceof AccessibleComponent) {
  6067. return ((AccessibleComponent) ac).isEnabled();
  6068. } else {
  6069. Component c = getCurrentComponent();
  6070. if (c != null) {
  6071. return c.isEnabled();
  6072. } else {
  6073. return false;
  6074. }
  6075. }
  6076. }
  6077. /**
  6078. * Sets the enabled state of the object.
  6079. *
  6080. * @param b if true, enables this object; otherwise, disables it
  6081. */
  6082. public void setEnabled(boolean b) {
  6083. AccessibleContext ac = getCurrentAccessibleContext();
  6084. if (ac instanceof AccessibleComponent) {
  6085. ((AccessibleComponent) ac).setEnabled(b);
  6086. } else {
  6087. Component c = getCurrentComponent();
  6088. if (c != null) {
  6089. c.setEnabled(b);
  6090. }
  6091. }
  6092. }
  6093. /**
  6094. * Determines if this object is visible. Note: this means that the
  6095. * object intends to be visible; however, it may not in fact be
  6096. * showing on the screen because one of the objects that this object
  6097. * is contained by is not visible. To determine if an object is
  6098. * showing on the screen, use <code>isShowing</code>.
  6099. *
  6100. * @return true if object is visible; otherwise, false
  6101. */
  6102. public boolean isVisible() {
  6103. AccessibleContext ac = getCurrentAccessibleContext();
  6104. if (ac instanceof AccessibleComponent) {
  6105. return ((AccessibleComponent) ac).isVisible();
  6106. } else {
  6107. Component c = getCurrentComponent();
  6108. if (c != null) {
  6109. return c.isVisible();
  6110. } else {
  6111. return false;
  6112. }
  6113. }
  6114. }
  6115. /**
  6116. * Sets the visible state of the object.
  6117. *
  6118. * @param b if true, shows this object; otherwise, hides it
  6119. */
  6120. public void setVisible(boolean b) {
  6121. AccessibleContext ac = getCurrentAccessibleContext();
  6122. if (ac instanceof AccessibleComponent) {
  6123. ((AccessibleComponent) ac).setVisible(b);
  6124. } else {
  6125. Component c = getCurrentComponent();
  6126. if (c != null) {
  6127. c.setVisible(b);
  6128. }
  6129. }
  6130. }
  6131. /**
  6132. * Determines if the object is showing. This is determined
  6133. * by checking the visibility of the object and ancestors
  6134. * of the object. Note: this will return true even if the
  6135. * object is obscured by another (for example,
  6136. * it happens to be underneath a menu that was pulled down).
  6137. *
  6138. * @return true if the object is showing; otherwise, false
  6139. */
  6140. public boolean isShowing() {
  6141. AccessibleContext ac = getCurrentAccessibleContext();
  6142. if (ac instanceof AccessibleComponent) {
  6143. if (ac.getAccessibleParent() != null) {
  6144. return ((AccessibleComponent) ac).isShowing();
  6145. } else {
  6146. // Fixes 4529616 - AccessibleJTableCell.isShowing()
  6147. // returns false when the cell on the screen
  6148. // if no parent
  6149. return isVisible();
  6150. }
  6151. } else {
  6152. Component c = getCurrentComponent();
  6153. if (c != null) {
  6154. return c.isShowing();
  6155. } else {
  6156. return false;
  6157. }
  6158. }
  6159. }
  6160. /**
  6161. * Checks whether the specified point is within this
  6162. * object's bounds, where the point's x and y coordinates
  6163. * are defined to be relative to the coordinate system of
  6164. * the object.
  6165. *
  6166. * @param p the <code>Point</code> relative to the
  6167. * coordinate system of the object
  6168. * @return true if object contains <code>Point</code>
  6169. * otherwise false
  6170. */
  6171. public boolean contains(Point p) {
  6172. AccessibleContext ac = getCurrentAccessibleContext();
  6173. if (ac instanceof AccessibleComponent) {
  6174. Rectangle r = ((AccessibleComponent) ac).getBounds();
  6175. return r.contains(p);
  6176. } else {
  6177. Component c = getCurrentComponent();
  6178. if (c != null) {
  6179. Rectangle r = c.getBounds();
  6180. return r.contains(p);
  6181. } else {
  6182. return getBounds().contains(p);
  6183. }
  6184. }
  6185. }
  6186. /**
  6187. * Returns the location of the object on the screen.
  6188. *
  6189. * @return location of object on screen -- can be
  6190. * <code>null</code> if this object is not on the screen
  6191. */
  6192. public Point getLocationOnScreen() {
  6193. if (parent != null) {
  6194. Point parentLocation = parent.getLocationOnScreen();
  6195. Point componentLocation = getLocation();
  6196. componentLocation.translate(parentLocation.x, parentLocation.y);
  6197. return componentLocation;
  6198. } else {
  6199. return null;
  6200. }
  6201. }
  6202. /**
  6203. * Gets the location of the object relative to the parent
  6204. * in the form of a point specifying the object's
  6205. * top-left corner in the screen's coordinate space.
  6206. *
  6207. * @return an instance of <code>Point</code> representing
  6208. * the top-left corner of the object's bounds in the
  6209. * coordinate space of the screen; <code>null</code> if
  6210. * this object or its parent are not on the screen
  6211. */
  6212. public Point getLocation() {
  6213. if (parent != null) {
  6214. Rectangle r = parent.getCellRect(row, column, false);
  6215. if (r != null) {
  6216. return r.getLocation();
  6217. }
  6218. }
  6219. return null;
  6220. }
  6221. /**
  6222. * Sets the location of the object relative to the parent.
  6223. */
  6224. public void setLocation(Point p) {
  6225. // if ((parent != null) && (parent.contains(p))) {
  6226. // ensureIndexIsVisible(indexInParent);
  6227. // }
  6228. }
  6229. public Rectangle getBounds() {
  6230. if (parent != null) {
  6231. return parent.getCellRect(row, column, false);
  6232. } else {
  6233. return null;
  6234. }
  6235. }
  6236. public void setBounds(Rectangle r) {
  6237. AccessibleContext ac = getCurrentAccessibleContext();
  6238. if (ac instanceof AccessibleComponent) {
  6239. ((AccessibleComponent) ac).setBounds(r);
  6240. } else {
  6241. Component c = getCurrentComponent();
  6242. if (c != null) {
  6243. c.setBounds(r);
  6244. }
  6245. }
  6246. }
  6247. public Dimension getSize() {
  6248. if (parent != null) {
  6249. Rectangle r = parent.getCellRect(row, column, false);
  6250. if (r != null) {
  6251. return r.getSize();
  6252. }
  6253. }
  6254. return null;
  6255. }
  6256. public void setSize (Dimension d) {
  6257. AccessibleContext ac = getCurrentAccessibleContext();
  6258. if (ac instanceof AccessibleComponent) {
  6259. ((AccessibleComponent) ac).setSize(d);
  6260. } else {
  6261. Component c = getCurrentComponent();
  6262. if (c != null) {
  6263. c.setSize(d);
  6264. }
  6265. }
  6266. }
  6267. public Accessible getAccessibleAt(Point p) {
  6268. AccessibleContext ac = getCurrentAccessibleContext();
  6269. if (ac instanceof AccessibleComponent) {
  6270. return ((AccessibleComponent) ac).getAccessibleAt(p);
  6271. } else {
  6272. return null;
  6273. }
  6274. }
  6275. public boolean isFocusTraversable() {
  6276. AccessibleContext ac = getCurrentAccessibleContext();
  6277. if (ac instanceof AccessibleComponent) {
  6278. return ((AccessibleComponent) ac).isFocusTraversable();
  6279. } else {
  6280. Component c = getCurrentComponent();
  6281. if (c != null) {
  6282. return c.isFocusTraversable();
  6283. } else {
  6284. return false;
  6285. }
  6286. }
  6287. }
  6288. public void requestFocus() {
  6289. AccessibleContext ac = getCurrentAccessibleContext();
  6290. if (ac instanceof AccessibleComponent) {
  6291. ((AccessibleComponent) ac).requestFocus();
  6292. } else {
  6293. Component c = getCurrentComponent();
  6294. if (c != null) {
  6295. c.requestFocus();
  6296. }
  6297. }
  6298. }
  6299. public void addFocusListener(FocusListener l) {
  6300. AccessibleContext ac = getCurrentAccessibleContext();
  6301. if (ac instanceof AccessibleComponent) {
  6302. ((AccessibleComponent) ac).addFocusListener(l);
  6303. } else {
  6304. Component c = getCurrentComponent();
  6305. if (c != null) {
  6306. c.addFocusListener(l);
  6307. }
  6308. }
  6309. }
  6310. public void removeFocusListener(FocusListener l) {
  6311. AccessibleContext ac = getCurrentAccessibleContext();
  6312. if (ac instanceof AccessibleComponent) {
  6313. ((AccessibleComponent) ac).removeFocusListener(l);
  6314. } else {
  6315. Component c = getCurrentComponent();
  6316. if (c != null) {
  6317. c.removeFocusListener(l);
  6318. }
  6319. }
  6320. }
  6321. } // inner class AccessibleJTableCell
  6322. // Begin AccessibleJTableHeader ========== // TIGER - 4715503
  6323. /**
  6324. * This class implements accessibility for JTable header cells.
  6325. */
  6326. private class AccessibleJTableHeaderCell extends AccessibleContext
  6327. implements Accessible, AccessibleComponent {
  6328. private int row;
  6329. private int column;
  6330. private JTableHeader parent;
  6331. private Component rendererComponent;
  6332. /**
  6333. * Constructs an <code>AccessibleJTableHeaderEntry</code> instance.
  6334. *
  6335. * @param row header cell row index
  6336. * @param column header cell column index
  6337. * @param parent header cell parent
  6338. * @param rendererComponent component that renders the header cell
  6339. */
  6340. public AccessibleJTableHeaderCell(int row, int column,
  6341. JTableHeader parent,
  6342. Component rendererComponent) {
  6343. this.row = row;
  6344. this.column = column;
  6345. this.parent = parent;
  6346. this.rendererComponent = rendererComponent;
  6347. this.setAccessibleParent(parent);
  6348. }
  6349. /**
  6350. * Gets the <code>AccessibleContext</code> associated with this
  6351. * component. In the implementation of the Java Accessibility
  6352. * API for this class, return this object, which is its own
  6353. * <code>AccessibleContext</code>.
  6354. *
  6355. * @return this object
  6356. */
  6357. public AccessibleContext getAccessibleContext() {
  6358. return this;
  6359. }
  6360. /*
  6361. * Returns the AccessibleContext for the header cell
  6362. * renderer.
  6363. */
  6364. private AccessibleContext getCurrentAccessibleContext() {
  6365. return rendererComponent.getAccessibleContext();
  6366. }
  6367. /*
  6368. * Returns the component that renders the header cell.
  6369. */
  6370. private Component getCurrentComponent() {
  6371. return rendererComponent;
  6372. }
  6373. // AccessibleContext methods ==========
  6374. /**
  6375. * Gets the accessible name of this object.
  6376. *
  6377. * @return the localized name of the object; <code>null</code>
  6378. * if this object does not have a name
  6379. */
  6380. public String getAccessibleName() {
  6381. AccessibleContext ac = getCurrentAccessibleContext();
  6382. if (ac != null) {
  6383. String name = ac.getAccessibleName();
  6384. if ((name != null) && (name != "")) {
  6385. return ac.getAccessibleName();
  6386. }
  6387. }
  6388. if ((accessibleName != null) && (accessibleName != "")) {
  6389. return accessibleName;
  6390. } else {
  6391. return null;
  6392. }
  6393. }
  6394. /**
  6395. * Sets the localized accessible name of this object.
  6396. *
  6397. * @param s the new localized name of the object
  6398. */
  6399. public void setAccessibleName(String s) {
  6400. AccessibleContext ac = getCurrentAccessibleContext();
  6401. if (ac != null) {
  6402. ac.setAccessibleName(s);
  6403. } else {
  6404. super.setAccessibleName(s);
  6405. }
  6406. }
  6407. /**
  6408. * Gets the accessible description of this object.
  6409. *
  6410. * @return the localized description of the object;
  6411. * <code>null</code> if this object does not have
  6412. * a description
  6413. */
  6414. public String getAccessibleDescription() {
  6415. AccessibleContext ac = getCurrentAccessibleContext();
  6416. if (ac != null) {
  6417. return ac.getAccessibleDescription();
  6418. } else {
  6419. return super.getAccessibleDescription();
  6420. }
  6421. }
  6422. /**
  6423. * Sets the accessible description of this object.
  6424. *
  6425. * @param s the new localized description of the object
  6426. */
  6427. public void setAccessibleDescription(String s) {
  6428. AccessibleContext ac = getCurrentAccessibleContext();
  6429. if (ac != null) {
  6430. ac.setAccessibleDescription(s);
  6431. } else {
  6432. super.setAccessibleDescription(s);
  6433. }
  6434. }
  6435. /**
  6436. * Gets the role of this object.
  6437. *
  6438. * @return an instance of <code>AccessibleRole</code>
  6439. * describing the role of the object
  6440. * @see AccessibleRole
  6441. */
  6442. public AccessibleRole getAccessibleRole() {
  6443. AccessibleContext ac = getCurrentAccessibleContext();
  6444. if (ac != null) {
  6445. return ac.getAccessibleRole();
  6446. } else {
  6447. return AccessibleRole.UNKNOWN;
  6448. }
  6449. }
  6450. /**
  6451. * Gets the state set of this object.
  6452. *
  6453. * @return an instance of <code>AccessibleStateSet</code>
  6454. * containing the current state set of the object
  6455. * @see AccessibleState
  6456. */
  6457. public AccessibleStateSet getAccessibleStateSet() {
  6458. AccessibleContext ac = getCurrentAccessibleContext();
  6459. AccessibleStateSet as = null;
  6460. if (ac != null) {
  6461. as = ac.getAccessibleStateSet();
  6462. }
  6463. if (as == null) {
  6464. as = new AccessibleStateSet();
  6465. }
  6466. Rectangle rjt = JTable.this.getVisibleRect();
  6467. Rectangle rcell = JTable.this.getCellRect(row, column, false);
  6468. if (rjt.intersects(rcell)) {
  6469. as.add(AccessibleState.SHOWING);
  6470. } else {
  6471. if (as.contains(AccessibleState.SHOWING)) {
  6472. as.remove(AccessibleState.SHOWING);
  6473. }
  6474. }
  6475. if (JTable.this.isCellSelected(row, column)) {
  6476. as.add(AccessibleState.SELECTED);
  6477. } else if (as.contains(AccessibleState.SELECTED)) {
  6478. as.remove(AccessibleState.SELECTED);
  6479. }
  6480. if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
  6481. as.add(AccessibleState.ACTIVE);
  6482. }
  6483. as.add(AccessibleState.TRANSIENT);
  6484. return as;
  6485. }
  6486. /**
  6487. * Gets the <code>Accessible</code> parent of this object.
  6488. *
  6489. * @return the Accessible parent of this object;
  6490. * <code>null</code> if this object does not
  6491. * have an <code>Accessible</code> parent
  6492. */
  6493. public Accessible getAccessibleParent() {
  6494. return parent;
  6495. }
  6496. /**
  6497. * Gets the index of this object in its accessible parent.
  6498. *
  6499. * @return the index of this object in its parent; -1 if this
  6500. * object does not have an accessible parent
  6501. * @see #getAccessibleParent
  6502. */
  6503. public int getAccessibleIndexInParent() {
  6504. return column;
  6505. }
  6506. /**
  6507. * Returns the number of accessible children in the object.
  6508. *
  6509. * @return the number of accessible children in the object
  6510. */
  6511. public int getAccessibleChildrenCount() {
  6512. AccessibleContext ac = getCurrentAccessibleContext();
  6513. if (ac != null) {
  6514. return ac.getAccessibleChildrenCount();
  6515. } else {
  6516. return 0;
  6517. }
  6518. }
  6519. /**
  6520. * Returns the specified <code>Accessible</code> child of the
  6521. * object.
  6522. *
  6523. * @param i zero-based index of child
  6524. * @return the <code>Accessible</code> child of the object
  6525. */
  6526. public Accessible getAccessibleChild(int i) {
  6527. AccessibleContext ac = getCurrentAccessibleContext();
  6528. if (ac != null) {
  6529. Accessible accessibleChild = ac.getAccessibleChild(i);
  6530. ac.setAccessibleParent(this);
  6531. return accessibleChild;
  6532. } else {
  6533. return null;
  6534. }
  6535. }
  6536. /**
  6537. * Gets the locale of the component. If the component
  6538. * does not have a locale, then the locale of its parent
  6539. * is returned.
  6540. *
  6541. * @return this component's locale; if this component does
  6542. * not have a locale, the locale of its parent is returned
  6543. * @exception IllegalComponentStateException if the
  6544. * <code>Component</code> does not have its own locale
  6545. * and has not yet been added to a containment hierarchy
  6546. * such that the locale can be determined from the
  6547. * containing parent
  6548. * @see #setLocale
  6549. */
  6550. public Locale getLocale() {
  6551. AccessibleContext ac = getCurrentAccessibleContext();
  6552. if (ac != null) {
  6553. return ac.getLocale();
  6554. } else {
  6555. return null;
  6556. }
  6557. }
  6558. /**
  6559. * Adds a <code>PropertyChangeListener</code> to the listener list.
  6560. * The listener is registered for all properties.
  6561. *
  6562. * @param l the <code>PropertyChangeListener</code>
  6563. * to be added
  6564. */
  6565. public void addPropertyChangeListener(PropertyChangeListener l) {
  6566. AccessibleContext ac = getCurrentAccessibleContext();
  6567. if (ac != null) {
  6568. ac.addPropertyChangeListener(l);
  6569. } else {
  6570. super.addPropertyChangeListener(l);
  6571. }
  6572. }
  6573. /**
  6574. * Removes a <code>PropertyChangeListener</code> from the
  6575. * listener list. This removes a <code>PropertyChangeListener</code>
  6576. * that was registered for all properties.
  6577. *
  6578. * @param l the <code>PropertyChangeListener</code>
  6579. * to be removed
  6580. */
  6581. public void removePropertyChangeListener(PropertyChangeListener l) {
  6582. AccessibleContext ac = getCurrentAccessibleContext();
  6583. if (ac != null) {
  6584. ac.removePropertyChangeListener(l);
  6585. } else {
  6586. super.removePropertyChangeListener(l);
  6587. }
  6588. }
  6589. /**
  6590. * Gets the <code>AccessibleAction</code> associated with this
  6591. * object if one exists. Otherwise returns <code>null</code>.
  6592. *
  6593. * @return the <code>AccessibleAction</code>, or <code>null</code>
  6594. */
  6595. public AccessibleAction getAccessibleAction() {
  6596. return getCurrentAccessibleContext().getAccessibleAction();
  6597. }
  6598. /**
  6599. * Gets the <code>AccessibleComponent</code> associated with
  6600. * this object if one exists. Otherwise returns <code>null</code>.
  6601. *
  6602. * @return the <code>AccessibleComponent</code>, or
  6603. * <code>null</code>
  6604. */
  6605. public AccessibleComponent getAccessibleComponent() {
  6606. return this; // to override getBounds()
  6607. }
  6608. /**
  6609. * Gets the <code>AccessibleSelection</code> associated with
  6610. * this object if one exists. Otherwise returns <code>null</code>.
  6611. *
  6612. * @return the <code>AccessibleSelection</code>, or
  6613. * <code>null</code>
  6614. */
  6615. public AccessibleSelection getAccessibleSelection() {
  6616. return getCurrentAccessibleContext().getAccessibleSelection();
  6617. }
  6618. /**
  6619. * Gets the <code>AccessibleText</code> associated with this
  6620. * object if one exists. Otherwise returns <code>null</code>.
  6621. *
  6622. * @return the <code>AccessibleText</code>, or <code>null</code>
  6623. */
  6624. public AccessibleText getAccessibleText() {
  6625. return getCurrentAccessibleContext().getAccessibleText();
  6626. }
  6627. /**
  6628. * Gets the <code>AccessibleValue</code> associated with
  6629. * this object if one exists. Otherwise returns <code>null</code>.
  6630. *
  6631. * @return the <code>AccessibleValue</code>, or <code>null</code>
  6632. */
  6633. public AccessibleValue getAccessibleValue() {
  6634. return getCurrentAccessibleContext().getAccessibleValue();
  6635. }
  6636. // AccessibleComponent methods ==========
  6637. /**
  6638. * Gets the background color of this object.
  6639. *
  6640. * @return the background color, if supported, of the object;
  6641. * otherwise, <code>null</code>
  6642. */
  6643. public Color getBackground() {
  6644. AccessibleContext ac = getCurrentAccessibleContext();
  6645. if (ac instanceof AccessibleComponent) {
  6646. return ((AccessibleComponent) ac).getBackground();
  6647. } else {
  6648. Component c = getCurrentComponent();
  6649. if (c != null) {
  6650. return c.getBackground();
  6651. } else {
  6652. return null;
  6653. }
  6654. }
  6655. }
  6656. /**
  6657. * Sets the background color of this object.
  6658. *
  6659. * @param c the new <code>Color</code> for the background
  6660. */
  6661. public void setBackground(Color c) {
  6662. AccessibleContext ac = getCurrentAccessibleContext();
  6663. if (ac instanceof AccessibleComponent) {
  6664. ((AccessibleComponent) ac).setBackground(c);
  6665. } else {
  6666. Component cp = getCurrentComponent();
  6667. if (cp != null) {
  6668. cp.setBackground(c);
  6669. }
  6670. }
  6671. }
  6672. /**
  6673. * Gets the foreground color of this object.
  6674. *
  6675. * @return the foreground color, if supported, of the object;
  6676. * otherwise, <code>null</code>
  6677. */
  6678. public Color getForeground() {
  6679. AccessibleContext ac = getCurrentAccessibleContext();
  6680. if (ac instanceof AccessibleComponent) {
  6681. return ((AccessibleComponent) ac).getForeground();
  6682. } else {
  6683. Component c = getCurrentComponent();
  6684. if (c != null) {
  6685. return c.getForeground();
  6686. } else {
  6687. return null;
  6688. }
  6689. }
  6690. }
  6691. /**
  6692. * Sets the foreground color of this object.
  6693. *
  6694. * @param c the new <code>Color</code> for the foreground
  6695. */
  6696. public void setForeground(Color c) {
  6697. AccessibleContext ac = getCurrentAccessibleContext();
  6698. if (ac instanceof AccessibleComponent) {
  6699. ((AccessibleComponent) ac).setForeground(c);
  6700. } else {
  6701. Component cp = getCurrentComponent();
  6702. if (cp != null) {
  6703. cp.setForeground(c);
  6704. }
  6705. }
  6706. }
  6707. /**
  6708. * Gets the <code>Cursor</code> of this object.
  6709. *
  6710. * @return the <code>Cursor</code>, if supported,
  6711. * of the object; otherwise, <code>null</code>
  6712. */
  6713. public Cursor getCursor() {
  6714. AccessibleContext ac = getCurrentAccessibleContext();
  6715. if (ac instanceof AccessibleComponent) {
  6716. return ((AccessibleComponent) ac).getCursor();
  6717. } else {
  6718. Component c = getCurrentComponent();
  6719. if (c != null) {
  6720. return c.getCursor();
  6721. } else {
  6722. Accessible ap = getAccessibleParent();
  6723. if (ap instanceof AccessibleComponent) {
  6724. return ((AccessibleComponent) ap).getCursor();
  6725. } else {
  6726. return null;
  6727. }
  6728. }
  6729. }
  6730. }
  6731. /**
  6732. * Sets the <code>Cursor</code> of this object.
  6733. *
  6734. * @param c the new <code>Cursor</code> for the object
  6735. */
  6736. public void setCursor(Cursor c) {
  6737. AccessibleContext ac = getCurrentAccessibleContext();
  6738. if (ac instanceof AccessibleComponent) {
  6739. ((AccessibleComponent) ac).setCursor(c);
  6740. } else {
  6741. Component cp = getCurrentComponent();
  6742. if (cp != null) {
  6743. cp.setCursor(c);
  6744. }
  6745. }
  6746. }
  6747. /**
  6748. * Gets the <code>Font</code> of this object.
  6749. *
  6750. * @return the <code>Font</code>,if supported,
  6751. * for the object; otherwise, <code>null</code>
  6752. */
  6753. public Font getFont() {
  6754. AccessibleContext ac = getCurrentAccessibleContext();
  6755. if (ac instanceof AccessibleComponent) {
  6756. return ((AccessibleComponent) ac).getFont();
  6757. } else {
  6758. Component c = getCurrentComponent();
  6759. if (c != null) {
  6760. return c.getFont();
  6761. } else {
  6762. return null;
  6763. }
  6764. }
  6765. }
  6766. /**
  6767. * Sets the <code>Font</code> of this object.
  6768. *
  6769. * @param f the new <code>Font</code> for the object
  6770. */
  6771. public void setFont(Font f) {
  6772. AccessibleContext ac = getCurrentAccessibleContext();
  6773. if (ac instanceof AccessibleComponent) {
  6774. ((AccessibleComponent) ac).setFont(f);
  6775. } else {
  6776. Component c = getCurrentComponent();
  6777. if (c != null) {
  6778. c.setFont(f);
  6779. }
  6780. }
  6781. }
  6782. /**
  6783. * Gets the <code>FontMetrics</code> of this object.
  6784. *
  6785. * @param f the <code>Font</code>
  6786. * @return the <code>FontMetrics</code> object, if supported;
  6787. * otherwise <code>null</code>
  6788. * @see #getFont
  6789. */
  6790. public FontMetrics getFontMetrics(Font f) {
  6791. AccessibleContext ac = getCurrentAccessibleContext();
  6792. if (ac instanceof AccessibleComponent) {
  6793. return ((AccessibleComponent) ac).getFontMetrics(f);
  6794. } else {
  6795. Component c = getCurrentComponent();
  6796. if (c != null) {
  6797. return c.getFontMetrics(f);
  6798. } else {
  6799. return null;
  6800. }
  6801. }
  6802. }
  6803. /**
  6804. * Determines if the object is enabled.
  6805. *
  6806. * @return true if object is enabled; otherwise, false
  6807. */
  6808. public boolean isEnabled() {
  6809. AccessibleContext ac = getCurrentAccessibleContext();
  6810. if (ac instanceof AccessibleComponent) {
  6811. return ((AccessibleComponent) ac).isEnabled();
  6812. } else {
  6813. Component c = getCurrentComponent();
  6814. if (c != null) {
  6815. return c.isEnabled();
  6816. } else {
  6817. return false;
  6818. }
  6819. }
  6820. }
  6821. /**
  6822. * Sets the enabled state of the object.
  6823. *
  6824. * @param b if true, enables this object; otherwise, disables it
  6825. */
  6826. public void setEnabled(boolean b) {
  6827. AccessibleContext ac = getCurrentAccessibleContext();
  6828. if (ac instanceof AccessibleComponent) {
  6829. ((AccessibleComponent) ac).setEnabled(b);
  6830. } else {
  6831. Component c = getCurrentComponent();
  6832. if (c != null) {
  6833. c.setEnabled(b);
  6834. }
  6835. }
  6836. }
  6837. /**
  6838. * Determines if this object is visible. Note: this means that the
  6839. * object intends to be visible; however, it may not in fact be
  6840. * showing on the screen because one of the objects that this object
  6841. * is contained by is not visible. To determine if an object is
  6842. * showing on the screen, use <code>isShowing</code>.
  6843. *
  6844. * @return true if object is visible; otherwise, false
  6845. */
  6846. public boolean isVisible() {
  6847. AccessibleContext ac = getCurrentAccessibleContext();
  6848. if (ac instanceof AccessibleComponent) {
  6849. return ((AccessibleComponent) ac).isVisible();
  6850. } else {
  6851. Component c = getCurrentComponent();
  6852. if (c != null) {
  6853. return c.isVisible();
  6854. } else {
  6855. return false;
  6856. }
  6857. }
  6858. }
  6859. /**
  6860. * Sets the visible state of the object.
  6861. *
  6862. * @param b if true, shows this object; otherwise, hides it
  6863. */
  6864. public void setVisible(boolean b) {
  6865. AccessibleContext ac = getCurrentAccessibleContext();
  6866. if (ac instanceof AccessibleComponent) {
  6867. ((AccessibleComponent) ac).setVisible(b);
  6868. } else {
  6869. Component c = getCurrentComponent();
  6870. if (c != null) {
  6871. c.setVisible(b);
  6872. }
  6873. }
  6874. }
  6875. /**
  6876. * Determines if the object is showing. This is determined
  6877. * by checking the visibility of the object and ancestors
  6878. * of the object. Note: this will return true even if the
  6879. * object is obscured by another (for example,
  6880. * it happens to be underneath a menu that was pulled down).
  6881. *
  6882. * @return true if the object is showing; otherwise, false
  6883. */
  6884. public boolean isShowing() {
  6885. AccessibleContext ac = getCurrentAccessibleContext();
  6886. if (ac instanceof AccessibleComponent) {
  6887. if (ac.getAccessibleParent() != null) {
  6888. return ((AccessibleComponent) ac).isShowing();
  6889. } else {
  6890. // Fixes 4529616 - AccessibleJTableCell.isShowing()
  6891. // returns false when the cell on the screen
  6892. // if no parent
  6893. return isVisible();
  6894. }
  6895. } else {
  6896. Component c = getCurrentComponent();
  6897. if (c != null) {
  6898. return c.isShowing();
  6899. } else {
  6900. return false;
  6901. }
  6902. }
  6903. }
  6904. /**
  6905. * Checks whether the specified point is within this
  6906. * object's bounds, where the point's x and y coordinates
  6907. * are defined to be relative to the coordinate system of
  6908. * the object.
  6909. *
  6910. * @param p the <code>Point</code> relative to the
  6911. * coordinate system of the object
  6912. * @return true if object contains <code>Point</code>
  6913. * otherwise false
  6914. */
  6915. public boolean contains(Point p) {
  6916. AccessibleContext ac = getCurrentAccessibleContext();
  6917. if (ac instanceof AccessibleComponent) {
  6918. Rectangle r = ((AccessibleComponent) ac).getBounds();
  6919. return r.contains(p);
  6920. } else {
  6921. Component c = getCurrentComponent();
  6922. if (c != null) {
  6923. Rectangle r = c.getBounds();
  6924. return r.contains(p);
  6925. } else {
  6926. return getBounds().contains(p);
  6927. }
  6928. }
  6929. }
  6930. /**
  6931. * Returns the location of the object on the screen.
  6932. *
  6933. * @return location of object on screen -- can be
  6934. * <code>null</code> if this object is not on the screen
  6935. */
  6936. public Point getLocationOnScreen() {
  6937. if (parent != null) {
  6938. Point parentLocation = parent.getLocationOnScreen();
  6939. Point componentLocation = getLocation();
  6940. componentLocation.translate(parentLocation.x, parentLocation.y);
  6941. return componentLocation;
  6942. } else {
  6943. return null;
  6944. }
  6945. }
  6946. /**
  6947. * Gets the location of the object relative to the parent
  6948. * in the form of a point specifying the object's
  6949. * top-left corner in the screen's coordinate space.
  6950. *
  6951. * @return an instance of <code>Point</code> representing
  6952. * the top-left corner of the object's bounds in the
  6953. * coordinate space of the screen; <code>null</code> if
  6954. * this object or its parent are not on the screen
  6955. */
  6956. public Point getLocation() {
  6957. if (parent != null) {
  6958. Rectangle r = parent.getHeaderRect(column);
  6959. if (r != null) {
  6960. return r.getLocation();
  6961. }
  6962. }
  6963. return null;
  6964. }
  6965. /**
  6966. * Sets the location of the object relative to the parent.
  6967. * @param p the new position for the top-left corner
  6968. * @see #getLocation
  6969. */
  6970. public void setLocation(Point p) {
  6971. }
  6972. /**
  6973. * Gets the bounds of this object in the form of a Rectangle object.
  6974. * The bounds specify this object's width, height, and location
  6975. * relative to its parent.
  6976. *
  6977. * @return A rectangle indicating this component's bounds; null if
  6978. * this object is not on the screen.
  6979. * @see #contains
  6980. */
  6981. public Rectangle getBounds() {
  6982. if (parent != null) {
  6983. return parent.getHeaderRect(column);
  6984. } else {
  6985. return null;
  6986. }
  6987. }
  6988. /**
  6989. * Sets the bounds of this object in the form of a Rectangle object.
  6990. * The bounds specify this object's width, height, and location
  6991. * relative to its parent.
  6992. *
  6993. * @param r rectangle indicating this component's bounds
  6994. * @see #getBounds
  6995. */
  6996. public void setBounds(Rectangle r) {
  6997. AccessibleContext ac = getCurrentAccessibleContext();
  6998. if (ac instanceof AccessibleComponent) {
  6999. ((AccessibleComponent) ac).setBounds(r);
  7000. } else {
  7001. Component c = getCurrentComponent();
  7002. if (c != null) {
  7003. c.setBounds(r);
  7004. }
  7005. }
  7006. }
  7007. /**
  7008. * Returns the size of this object in the form of a Dimension object.
  7009. * The height field of the Dimension object contains this object's
  7010. * height, and the width field of the Dimension object contains this
  7011. * object's width.
  7012. *
  7013. * @return A Dimension object that indicates the size of this component;
  7014. * null if this object is not on the screen
  7015. * @see #setSize
  7016. */
  7017. public Dimension getSize() {
  7018. if (parent != null) {
  7019. Rectangle r = parent.getHeaderRect(column);
  7020. if (r != null) {
  7021. return r.getSize();
  7022. }
  7023. }
  7024. return null;
  7025. }
  7026. /**
  7027. * Resizes this object so that it has width and height.
  7028. *
  7029. * @param d The dimension specifying the new size of the object.
  7030. * @see #getSize
  7031. */
  7032. public void setSize (Dimension d) {
  7033. AccessibleContext ac = getCurrentAccessibleContext();
  7034. if (ac instanceof AccessibleComponent) {
  7035. ((AccessibleComponent) ac).setSize(d);
  7036. } else {
  7037. Component c = getCurrentComponent();
  7038. if (c != null) {
  7039. c.setSize(d);
  7040. }
  7041. }
  7042. }
  7043. /**
  7044. * Returns the Accessible child, if one exists, contained at the local
  7045. * coordinate Point.
  7046. *
  7047. * @param p The point relative to the coordinate system of this object.
  7048. * @return the Accessible, if it exists, at the specified location;
  7049. * otherwise null
  7050. */
  7051. public Accessible getAccessibleAt(Point p) {
  7052. AccessibleContext ac = getCurrentAccessibleContext();
  7053. if (ac instanceof AccessibleComponent) {
  7054. return ((AccessibleComponent) ac).getAccessibleAt(p);
  7055. } else {
  7056. return null;
  7057. }
  7058. }
  7059. /**
  7060. * Returns whether this object can accept focus or not. Objects that
  7061. * can accept focus will also have the AccessibleState.FOCUSABLE state
  7062. * set in their AccessibleStateSets.
  7063. *
  7064. * @return true if object can accept focus; otherwise false
  7065. * @see AccessibleContext#getAccessibleStateSet
  7066. * @see AccessibleState#FOCUSABLE
  7067. * @see AccessibleState#FOCUSED
  7068. * @see AccessibleStateSet
  7069. */
  7070. public boolean isFocusTraversable() {
  7071. AccessibleContext ac = getCurrentAccessibleContext();
  7072. if (ac instanceof AccessibleComponent) {
  7073. return ((AccessibleComponent) ac).isFocusTraversable();
  7074. } else {
  7075. Component c = getCurrentComponent();
  7076. if (c != null) {
  7077. return c.isFocusTraversable();
  7078. } else {
  7079. return false;
  7080. }
  7081. }
  7082. }
  7083. /**
  7084. * Requests focus for this object. If this object cannot accept focus,
  7085. * nothing will happen. Otherwise, the object will attempt to take
  7086. * focus.
  7087. * @see #isFocusTraversable
  7088. */
  7089. public void requestFocus() {
  7090. AccessibleContext ac = getCurrentAccessibleContext();
  7091. if (ac instanceof AccessibleComponent) {
  7092. ((AccessibleComponent) ac).requestFocus();
  7093. } else {
  7094. Component c = getCurrentComponent();
  7095. if (c != null) {
  7096. c.requestFocus();
  7097. }
  7098. }
  7099. }
  7100. /**
  7101. * Adds the specified focus listener to receive focus events from this
  7102. * component.
  7103. *
  7104. * @param l the focus listener
  7105. * @see #removeFocusListener
  7106. */
  7107. public void addFocusListener(FocusListener l) {
  7108. AccessibleContext ac = getCurrentAccessibleContext();
  7109. if (ac instanceof AccessibleComponent) {
  7110. ((AccessibleComponent) ac).addFocusListener(l);
  7111. } else {
  7112. Component c = getCurrentComponent();
  7113. if (c != null) {
  7114. c.addFocusListener(l);
  7115. }
  7116. }
  7117. }
  7118. /**
  7119. * Removes the specified focus listener so it no longer receives focus
  7120. * events from this component.
  7121. *
  7122. * @param l the focus listener
  7123. * @see #addFocusListener
  7124. */
  7125. public void removeFocusListener(FocusListener l) {
  7126. AccessibleContext ac = getCurrentAccessibleContext();
  7127. if (ac instanceof AccessibleComponent) {
  7128. ((AccessibleComponent) ac).removeFocusListener(l);
  7129. } else {
  7130. Component c = getCurrentComponent();
  7131. if (c != null) {
  7132. c.removeFocusListener(l);
  7133. }
  7134. }
  7135. }
  7136. } // inner class AccessibleJTableHeaderCell
  7137. } // inner class AccessibleJTable
  7138. } // End of Class JTable