1. /*
  2. * @(#)JTable.java 1.121 01/11/29
  3. *
  4. * Copyright 2002 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.awt.*;
  10. import java.awt.event.*;
  11. import java.beans.*;
  12. import java.io.Serializable;
  13. import java.io.ObjectOutputStream;
  14. import java.io.ObjectInputStream;
  15. import java.io.IOException;
  16. import javax.accessibility.*;
  17. import javax.swing.event.*;
  18. import javax.swing.plaf.*;
  19. import javax.swing.table.*;
  20. import javax.swing.border.*;
  21. import java.text.DateFormat;
  22. import java.text.NumberFormat;
  23. /**
  24. * JTable is a user-interface component that presents data in a two-dimensional
  25. * table format. The JTable has many facilities that make it possible to
  26. * customize its rendering and editing but provides defaults
  27. * for these features so that simple tables can be set up easily.
  28. * For example, to set up a table with 10 rows and 10 columns of numbers:
  29. * <p>
  30. * <pre>
  31. * TableModel dataModel = new AbstractTableModel() {
  32. * public int getColumnCount() { return 10; }
  33. * public int getRowCount() { return 10;}
  34. * public Object getValueAt(int row, int col) { return new Integer(row*col); }
  35. * };
  36. * JTable table = new JTable(dataModel);
  37. * JScrollPane scrollpane = new JScrollPane(table);
  38. * </pre>
  39. * <p>
  40. * Because the JTable is now much easier to set up with custom models
  41. * the DefaultTableModel is less useful than it was in previous releases.
  42. * Instead of copying the data in an application into the DefaultTableModel,
  43. * we recommend wrapping it in the methods of the TableModel interface and
  44. * passing the real data to the JTable as above. This technique is nearly as concise
  45. * as using a DefaultTableModel and starting this way has a number of advantages
  46. * over the longer term. In particular: it is a scalable technique,
  47. * is easier to handle dynamic or editable tables and often results in much
  48. * more efficient applications because the model is free to choose the
  49. * internal representation that best suits the data.
  50. * <p>
  51. * The "Table" directory in the examples/demo area gives a number of complete
  52. * examples of JTable usage, covering how the JTable can be used to provide
  53. * an editable view of data taken from a database and how to modify the columns
  54. * in the display to use specialized renderers and editors. For example, overriding
  55. * AbstractTableModel's <code>getColumnClass()</code> method to return a value of
  56. * <code>ImageIcon.class</code> for a given column allows icons to be displayed,
  57. * while returning a value of <code>Number.class</code> allows digits to be
  58. * right-justified in the column.
  59. * <p>
  60. * The JTable uses integers exclusively to refer to both the rows and the columns
  61. * of the model that it displays. The JTable simply takes a tabular range of cells
  62. * and uses <code>getValueAt(int, int)</code> to retrieve and display the appropriate
  63. * values from the model.
  64. * <p>
  65. * If <code>getTableHeader().setReorderingAllowed(boolean)</code> is used to
  66. * enable column reordering columns may be rearranged in the JTable so that the
  67. * view's columns appear in a different order to the columns in the model.
  68. * This does not affect the implementation of the model at all: when the
  69. * columns are reordered, the JTable maintains the new order of the columns
  70. * internally and converts its column indices before querying the model.
  71. * <p>
  72. * So, when writing a TableModel, it is not necessary to listen for column
  73. * reordering events as the the model will be queried in its own co-ordinate
  74. * system regardless of what is happening in the view.
  75. * In the examples area there is a demonstration of a sorting algorithm making
  76. * use of exactly this technique to interpose yet another co-ordinate system
  77. * where the order of the rows is changed, rather than the order of the columns.
  78. * <p>
  79. * The general rule for the JTable API and the APIs of all its associated classes,
  80. * including the the column model and both the row and column selection models, is:
  81. * methods using integer indices for rows and columns always use the co-ordinate
  82. * system of the view. There are three exceptions to this rule:
  83. * <ul>
  84. * <li> All references to rows and columns in the TableModel
  85. * interface are in the co-ordinate system of the model.
  86. * <li> The index <I>modelIndex</I> in the TableColumn constructors
  87. * refers to the index of the column in the model, not the view.
  88. * <li> All constructors for the TableModelEvent, which describes changes
  89. * that have taken place in a table model, use the co-ordinate system
  90. * of the model.
  91. * </ul>
  92. * The TableColumn provides a slot for holding an identifier or "tag" for each column
  93. * and the JTable and TableColumModel both support <I>getColumn(Object id)</I>
  94. * conveniences for locating columns by their identifier. If no identifier is
  95. * explicitly set, the TableColumn returns its header value (the name of the column)
  96. * as a default. A different identifier, which can be of any type, can be set
  97. * using the TableColumn's <I>setIdentifier()</I> method. All of the JTable's
  98. * functions operate correctly regardless of the type and uniqueness of these
  99. * identifiers.
  100. * <p>
  101. * The <I>convertColumnIndexToView()</I> and
  102. * <I>convertColumnIndexToModel()</I> methods have been provided to
  103. * convert between the two co-ordinate systems but
  104. * they are rarely needed during normal use.
  105. * <p>
  106. * Like all JComponent classes, you can use
  107. * {@link JComponent#registerKeyboardAction} to associate an
  108. * {@link Action} object with a {@link KeyStroke} and execute the
  109. * action under specified conditions.
  110. * <p>
  111. * See <a href="http://java.sun.com/docs/books/tutorial/ui/swing/table.html">How to Use Tables</a>
  112. * in <a href="http://java.sun.com/Series/Tutorial/index.html"><em>The Java Tutorial</em></a>
  113. * for further documentation.
  114. * <p>
  115. * For the keyboard keys used by this component in the standard Look and
  116. * Feel (L&F) renditions, see the
  117. * <a href="doc-files/Key-Index.html#JTable">JTable</a> key assignments.
  118. * <p>
  119. * <strong>Warning:</strong>
  120. * Serialized objects of this class will not be compatible with
  121. * future Swing releases. The current serialization support is appropriate
  122. * for short term storage or RMI between applications running the same
  123. * version of Swing. A future release of Swing will provide support for
  124. * long term persistence.
  125. *
  126. *
  127. * @beaninfo
  128. * attribute: isContainer false
  129. *
  130. * @version 1.121 11/29/01
  131. * @author Philip Milne
  132. * @author Alan Chung
  133. */
  134. public class JTable extends JComponent implements TableModelListener, Scrollable,
  135. TableColumnModelListener, ListSelectionListener, CellEditorListener,
  136. Accessible
  137. {
  138. //
  139. // Static Constants
  140. //
  141. /**
  142. * @see #getUIClassID
  143. * @see #readObject
  144. */
  145. private static final String uiClassID = "TableUI";
  146. /** Do not adjust column widths automatically, use a scrollbar */
  147. public static final int AUTO_RESIZE_OFF = 0;
  148. /** When a column is adjusted in the UI, adjust the next column the opposite way */
  149. public static final int AUTO_RESIZE_NEXT_COLUMN = 1;
  150. /** During UI adjustment, change subsequent columns to preserve the total width */
  151. public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
  152. /** During all resize operations, apply adjustments to the last column only */
  153. public static final int AUTO_RESIZE_LAST_COLUMN = 3;
  154. /** During all resize operations, proportionately resize all columns */
  155. public static final int AUTO_RESIZE_ALL_COLUMNS = 4;
  156. //
  157. // Instance Variables
  158. //
  159. /** The TableModel of the table */
  160. protected TableModel dataModel;
  161. /** The TableColumnModel of the table */
  162. protected TableColumnModel columnModel;
  163. /** The ListSelectionModel of the table, used to keep track of row selections */
  164. protected ListSelectionModel selectionModel;
  165. /** The TableHeader working with the table */
  166. protected JTableHeader tableHeader;
  167. /** The height of all rows in the table */
  168. protected int rowHeight;
  169. /** The height margin between rows */
  170. protected int rowMargin;
  171. /** The color of the grid */
  172. protected Color gridColor;
  173. /** The table draws horizontal lines between cells if showHorizontalLines is true */
  174. protected boolean showHorizontalLines;
  175. /** The table draws vertical lines between cells if showVerticalLines is true */
  176. protected boolean showVerticalLines;
  177. /**
  178. * This mode value determines if table automatically resizes the
  179. * width the table's columns to take up the entire width of the
  180. * table, and how it does the resizing.
  181. */
  182. protected int autoResizeMode;
  183. /**
  184. * The table will query the TableModel to build the default
  185. * set of columns if this is true.
  186. */
  187. protected boolean autoCreateColumnsFromModel;
  188. /** Used by the Scrollable interface to determine the initial visible area */
  189. protected Dimension preferredViewportSize;
  190. /** Row selection allowed in this table */
  191. protected boolean rowSelectionAllowed;
  192. /**
  193. * If this is true, then both a row selection and a column selection
  194. * can be non-empty at the same time, the selected cells are the
  195. * the cells whose row and column are both selected.
  196. */
  197. protected boolean cellSelectionEnabled;
  198. /** If editing, Component that is handling the editing. */
  199. transient protected Component editorComp;
  200. /**
  201. * The object that overwrites the screen real estate occupied by the
  202. * current cell and allows the user to change those contents.
  203. */
  204. transient protected TableCellEditor cellEditor;
  205. /** Identifies the column of the cell being edited. */
  206. transient protected int editingColumn;
  207. /** Identifies the row of the cell being edited. */
  208. transient protected int editingRow;
  209. /**
  210. * A table of objects that display the contents of a cell,
  211. * indexed by class.
  212. */
  213. transient protected Hashtable defaultRenderersByColumnClass;
  214. /**
  215. * A table of objects that display and edit the contents of a cell,
  216. * indexed by class.
  217. */
  218. transient protected Hashtable defaultEditorsByColumnClass;
  219. /** The foreground color of selected cells */
  220. protected Color selectionForeground;
  221. /** The background color of selected cells */
  222. protected Color selectionBackground;
  223. //
  224. // Constructors
  225. //
  226. /**
  227. * Constructs a default JTable which is initialized with a default
  228. * data model, a default column model, and a default selection
  229. * model.
  230. *
  231. * @see #createDefaultDataModel
  232. * @see #createDefaultColumnModel
  233. * @see #createDefaultSelectionModel
  234. */
  235. public JTable() {
  236. this(null, null, null);
  237. }
  238. /**
  239. * Constructs a JTable which is initialized with <i>dm</i> as the
  240. * data model, a default column model, and a default selection
  241. * model.
  242. *
  243. * @param dm The data model for the table
  244. * @see #createDefaultColumnModel
  245. * @see #createDefaultSelectionModel
  246. */
  247. public JTable(TableModel dm) {
  248. this(dm, null, null);
  249. }
  250. /**
  251. * Constructs a JTable which is initialized with <i>dm</i> as the
  252. * data model, <i>cm</i> as the column model, and a default selection
  253. * model.
  254. *
  255. * @param dm The data model for the table
  256. * @param cm The column model for the table
  257. * @see #createDefaultSelectionModel
  258. */
  259. public JTable(TableModel dm, TableColumnModel cm) {
  260. this(dm, cm, null);
  261. }
  262. /**
  263. * Constructs a JTable which is initialized with <i>dm</i> as the
  264. * data model, <i>cm</i> as the column model, and <i>sm</i> as the
  265. * selection model. If any of the parameters are <b>null</b> this
  266. * method will initialize the table with the corresponding
  267. * default model. The <i>autoCreateColumnsFromModel</i> flag is set
  268. * to false if <i>cm</i> is non-null, otherwise it is set to true
  269. * and the column model is populated with suitable TableColumns
  270. * for the columns in <i>dm</i>.
  271. *
  272. * @param dm The data model for the table
  273. * @param cm The column model for the table
  274. * @param sm The row selection model for the table
  275. * @see #createDefaultDataModel
  276. * @see #createDefaultColumnModel
  277. * @see #createDefaultSelectionModel
  278. */
  279. public JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
  280. super();
  281. setLayout(null);
  282. if (cm == null) {
  283. cm = createDefaultColumnModel();
  284. autoCreateColumnsFromModel = true;
  285. }
  286. setColumnModel(cm);
  287. if (sm == null)
  288. sm = createDefaultSelectionModel();
  289. setSelectionModel(sm);
  290. // Set the model last, that way if the autoCreatColumnsFromModel has
  291. // been set above, we will automatically populate an empty columnModel
  292. // with suitable columns for the new model.
  293. if (dm == null)
  294. dm = createDefaultDataModel();
  295. setModel(dm);
  296. initializeLocalVars();
  297. updateUI();
  298. }
  299. /**
  300. * Constructs a JTable with <i>numRows</i> and <i>numColumns</i> of
  301. * empty cells using the DefaultTableModel. The columns will have
  302. * names of the form "A", "B", "C", etc.
  303. *
  304. * @param numRows The number of rows the table holds
  305. * @param numColumns The number of columns the table holds
  306. * @see javax.swing.table.DefaultTableModel
  307. */
  308. public JTable(int numRows, int numColumns) {
  309. this(new DefaultTableModel(numRows, numColumns));
  310. }
  311. /**
  312. * Constructs a JTable to display the values in the Vector of Vectors,
  313. * <i>rowData</i>, with column names, <i>columnNames</i>.
  314. * The Vectors contained in <i>rowData</i> should contain the values
  315. * for that row. In other words, the value of the cell at row 1,
  316. * column 5 can be obtained with the following code:
  317. * <p>
  318. * <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
  319. * <p>
  320. * All rows must be of the same length as <i>columnNames</i>.
  321. * <p>
  322. * @param rowData The data for the new table
  323. * @param columnNames Names of each column
  324. */
  325. public JTable(final Vector rowData, final Vector columnNames) {
  326. this(new AbstractTableModel() {
  327. public String getColumnName(int column) { return columnNames.elementAt(column).toString(); }
  328. public int getRowCount() { return rowData.size(); }
  329. public int getColumnCount() { return columnNames.size(); }
  330. public Object getValueAt(int row, int column) {
  331. return ((Vector)rowData.elementAt(row)).elementAt(column);
  332. }
  333. public boolean isCellEditable(int row, int column) { return true; }
  334. public void setValueAt(Object value, int row, int column) {
  335. ((Vector)rowData.elementAt(row)).setElementAt(value, column);
  336. fireTableCellUpdated(row, column);
  337. }
  338. });
  339. }
  340. /**
  341. * Constructs a JTable to display the values in the two dimensional array,
  342. * <i>rowData</i>, with column names, <i>columnNames</i>.
  343. * <i>rowData</i> is an Array of rows, so the value of the cell at row 1,
  344. * column 5 can be obtained with the following code:
  345. * <p>
  346. * <pre> rowData[1][5]; </pre>
  347. * <p>
  348. * All rows must be of the same length as <i>columnNames</i>.
  349. * <p>
  350. * @param rowData The data for the new table
  351. * @param columnNames Names of each column
  352. */
  353. public JTable(final Object[][] rowData, final Object[] columnNames) {
  354. this(new AbstractTableModel() {
  355. public String getColumnName(int column) { return columnNames[column].toString(); }
  356. public int getRowCount() { return rowData.length; }
  357. public int getColumnCount() { return columnNames.length; }
  358. public Object getValueAt(int row, int col) { return rowData[row][col]; }
  359. public boolean isCellEditable(int row, int column) { return true; }
  360. public void setValueAt(Object value, int row, int col) {
  361. rowData[row][col] = value;
  362. fireTableCellUpdated(row, col);
  363. }
  364. });
  365. }
  366. /**
  367. * Calls <code>configureEnclosingScrollPane</code>.
  368. *
  369. * @see #configureEnclosingScrollPane
  370. */
  371. public void addNotify() {
  372. super.addNotify();
  373. configureEnclosingScrollPane();
  374. }
  375. /**
  376. * If the JTable is the viewportView of an enclosing JScrollPane
  377. * (the usual situation), configure this ScrollPane by, amongst other things,
  378. * installing the table's tableHeader as the columnHeaderView of the scrollpane.
  379. * When a JTable is added to a JScrollPane in the usual way,
  380. * using <code>new JScrollPane(myTable)</code>, <code>addNotify</code> is
  381. * called in the JTable (when the table is added to the viewport).
  382. * JTable's <code>addNotify</code> method in turn calls this method
  383. * which is protected so that this default installation procedure can
  384. * be overridden by a subclass.
  385. *
  386. * @see #addNotify
  387. */
  388. protected void configureEnclosingScrollPane() {
  389. Container p = getParent();
  390. if (p instanceof JViewport) {
  391. Container gp = p.getParent();
  392. if (gp instanceof JScrollPane) {
  393. JScrollPane scrollPane = (JScrollPane)gp;
  394. // Make certain we are the viewPort's view and not, for
  395. // example, the rowHeaderView of the scrollPane -
  396. // an implementor of fixed columns might do this.
  397. JViewport viewport = scrollPane.getViewport();
  398. if (viewport == null || viewport.getView() != this) {
  399. return;
  400. }
  401. scrollPane.setColumnHeaderView(getTableHeader());
  402. scrollPane.getViewport().setBackingStoreEnabled(true);
  403. Border border = scrollPane.getBorder();
  404. if (border == null || border instanceof UIResource) {
  405. scrollPane.setBorder(UIManager.getBorder("Table.scrollPaneBorder"));
  406. }
  407. }
  408. }
  409. }
  410. //
  411. // Static Methods
  412. //
  413. /**
  414. * Equivalent to <code>new JScrollPane(aTable)</code>.
  415. *
  416. * @deprecated As of Swing version 1.0.2,
  417. * replaced by <code>new JScrollPane(aTable)</code>.
  418. */
  419. static public JScrollPane createScrollPaneForTable(JTable aTable) {
  420. return new JScrollPane(aTable);
  421. }
  422. //
  423. // Table Attributes
  424. //
  425. /**
  426. * Sets the tableHeader working with this JTable to <I>newHeader</I>.
  427. * It is legal to have a <B>null</B> tableHeader.
  428. *
  429. * @param newHeader new tableHeader
  430. * @see #getTableHeader
  431. * @beaninfo
  432. * description: The JTableHeader instance which renders the column headers.
  433. */
  434. public void setTableHeader(JTableHeader newHeader) {
  435. if (tableHeader != newHeader) {
  436. // Release the old header
  437. if (tableHeader != null)
  438. tableHeader.setTable(null);
  439. tableHeader = newHeader;
  440. if (tableHeader != null)
  441. tableHeader.setTable(this);
  442. }
  443. }
  444. /**
  445. * Returns the tableHeader working with this JTable.
  446. *
  447. * @return the tableHeader working with the receiver
  448. * @see #setTableHeader
  449. */
  450. public JTableHeader getTableHeader() {
  451. return tableHeader;
  452. }
  453. /**
  454. * Sets the height for rows to <I>newRowHeight</I> and invokes tile
  455. *
  456. * @param newRowHeight new row height
  457. * @exception IllegalArgumentException If <I>newRowHeight</I> is
  458. * less than 1.
  459. * @see #getRowHeight
  460. * @beaninfo
  461. * description: The height of the cells including the inter-cell spacing.
  462. */
  463. public void setRowHeight(int newHeight) {
  464. if (newHeight <= 0) {
  465. throw new IllegalArgumentException("New row height less than 1");
  466. }
  467. rowHeight = newHeight;
  468. resizeAndRepaint();
  469. }
  470. /**
  471. * Returns the height of a table row in the receiver.
  472. * The default row height is 16.0.
  473. *
  474. * @return the height of each row in the receiver
  475. * @see #setRowHeight
  476. */
  477. public int getRowHeight() {
  478. return rowHeight;
  479. }
  480. /**
  481. * Sets the amount of emtpy space between rows.
  482. *
  483. * @see #getRowMargin
  484. */
  485. public void setRowMargin(int rowMargin) {
  486. this.rowMargin = rowMargin;
  487. }
  488. /**
  489. * Gets the amount of emtpy space between rows. Equivalent to:
  490. * <code>getIntercellSpacing().height</code>.
  491. *
  492. * @see #setRowMargin
  493. */
  494. public int getRowMargin() {
  495. return rowMargin;
  496. }
  497. /**
  498. * Sets the width and height between cells to <I>newSpacing</I> and
  499. * redisplays the receiver.
  500. *
  501. * @param newSpacing The new width and height intercellSpacing
  502. * @see #getIntercellSpacing
  503. * @beaninfo
  504. * description: The spacing between the cells, drawn in the background color of the JTable.
  505. */
  506. public void setIntercellSpacing(Dimension newSpacing) {
  507. // Set the rowMargin here and columnMargin in the TableColumnModel
  508. rowMargin = newSpacing.height;
  509. getColumnModel().setColumnMargin(newSpacing.width);
  510. resizeAndRepaint();
  511. }
  512. /**
  513. * Returns the horizontal and vertical spacing between cells.
  514. * The default spacing is (3, 2).
  515. *
  516. * @return the horizontal and vertical spacing between cells
  517. * @see #setIntercellSpacing
  518. */
  519. public Dimension getIntercellSpacing() {
  520. return new Dimension(getColumnModel().getColumnMargin(), rowMargin);
  521. }
  522. /**
  523. * Sets the color used to draw grid lines to <I>color</I> and redisplays
  524. * the receiver. The default color is gray.
  525. *
  526. * @param color new color of the grid
  527. * @exception IllegalArgumentException if <I>color</I> is null
  528. * @see #getGridColor
  529. */
  530. public void setGridColor(Color newColor) {
  531. if (newColor == null) {
  532. throw new IllegalArgumentException("New color is null");
  533. }
  534. gridColor = newColor;
  535. // Redraw
  536. repaint();
  537. }
  538. /**
  539. * Returns the color used to draw grid lines. The default color is gray.
  540. *
  541. * @return the color used to draw grid lines
  542. * @see #setGridColor
  543. */
  544. public Color getGridColor() {
  545. return gridColor;
  546. }
  547. /**
  548. * Sets whether the receiver draws grid lines around cells.
  549. * If <I>flag</I> is true it does; if it is false it doesn't.
  550. * There is no getShowGrid() method as the this state is held
  551. * in two variables: showHorizontalLines and showVerticalLines
  552. * each of which may be queried independently.
  553. *
  554. * @param flag true if table view should draw grid lines
  555. *
  556. * @see #setShowVerticalLines
  557. * @see #setShowHorizontalLines
  558. * @beaninfo
  559. * description: The color used to draw the grid lines.
  560. */
  561. public void setShowGrid(boolean b) {
  562. setShowHorizontalLines(b);
  563. setShowVerticalLines(b);
  564. // Redraw
  565. repaint();
  566. }
  567. /**
  568. * Sets whether the receiver draws horizontal lines between cells.
  569. * If <I>flag</I> is true it does; if it is false it doesn't.
  570. *
  571. * @param flag true if table view should draw horizontal lines
  572. * @see #getShowHorizontalLines
  573. * @see #setShowGrid
  574. * @see #setShowVerticalLines
  575. * @beaninfo
  576. * description: Whether horizontal lines should be drawn in between the cells.
  577. */
  578. public void setShowHorizontalLines(boolean b) {
  579. showHorizontalLines = b;
  580. // Redraw
  581. repaint();
  582. }
  583. /**
  584. * Sets whether the receiver draws vertical lines between cells.
  585. * If <I>flag</I> is true it does; if it is false it doesn't.
  586. *
  587. * @param flag true if table view should draw vertical lines
  588. * @see #getShowVerticalLines
  589. * @see #setShowGrid
  590. * @see #setShowHorizontalLines
  591. * @beaninfo
  592. * description: Whether vertical lines should be drawn in between the cells.
  593. */
  594. public void setShowVerticalLines(boolean b) {
  595. showVerticalLines = b;
  596. // Redraw
  597. repaint();
  598. }
  599. /**
  600. * Returns true if the receiver draws horizontal lines between cells, false if it
  601. * doesn't. The default is true.
  602. *
  603. * @return true if the receiver draws horizontal lines between cells, false if it
  604. * doesn't
  605. * @see #setShowHorizontalLines
  606. */
  607. public boolean getShowHorizontalLines() {
  608. return showHorizontalLines;
  609. }
  610. /**
  611. * Returns true if the receiver draws vertical lines between cells, false if it
  612. * doesn't. The default is true.
  613. *
  614. * @return true if the receiver draws vertical lines between cells, false if it
  615. * doesn't
  616. * @see #setShowVerticalLines
  617. */
  618. public boolean getShowVerticalLines() {
  619. return showVerticalLines;
  620. }
  621. /**
  622. * Sets the table's auto resize mode when the table is resized.
  623. *
  624. * @param mode One of 5 legal values:
  625. * AUTO_RESIZE_OFF,
  626. * AUTO_RESIZE_NEXT_COLUMN,
  627. * AUTO_RESIZE_SUBSEQUENT_COLUMNS,
  628. * AUTO_RESIZE_LAST_COLUMN,
  629. * AUTO_RESIZE_ALL_COLUMNS
  630. *
  631. * @see #getAutoResizeMode
  632. * @see #sizeColumnsToFit(int)
  633. * @beaninfo
  634. * description: Whether the columns should adjust themselves automatically.
  635. * enum: AUTO_RESIZE_OFF JTable.AUTO_RESIZE_OFF
  636. * AUTO_RESIZE_NEXT_COLUMN JTable.AUTO_RESIZE_NEXT_COLUMN
  637. * AUTO_RESIZE_SUBSEQUENT_COLUMNS JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS
  638. * AUTO_RESIZE_LAST_COLUMN JTable.AUTO_RESIZE_LAST_COLUMN
  639. * AUTO_RESIZE_ALL_COLUMNS JTable.AUTO_RESIZE_ALL_COLUMNS
  640. */
  641. public void setAutoResizeMode(int mode) {
  642. if ((mode == AUTO_RESIZE_OFF) ||
  643. (mode == AUTO_RESIZE_NEXT_COLUMN) ||
  644. (mode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) ||
  645. (mode == AUTO_RESIZE_LAST_COLUMN) ||
  646. (mode == AUTO_RESIZE_ALL_COLUMNS)) {
  647. autoResizeMode = mode;
  648. resizeAndRepaint();
  649. if (tableHeader != null) {
  650. tableHeader.resizeAndRepaint();
  651. }
  652. }
  653. }
  654. /**
  655. * Returns auto resize mode of the table.
  656. *
  657. * @return the autoResizeMode of the table
  658. *
  659. * @see #setAutoResizeMode
  660. * @see #sizeColumnsToFit(int)
  661. */
  662. public int getAutoResizeMode() {
  663. return autoResizeMode;
  664. }
  665. /**
  666. * Sets the table's autoCreateColumnsFromModel flag. This method
  667. * will call createDefaultColumnsFromModel() if <i>createColumns</i>
  668. * is true.
  669. *
  670. * @param createColumns true if JTable should auto create columns
  671. * @see #getAutoCreateColumnsFromModel
  672. * @see #createDefaultColumnsFromModel
  673. * @beaninfo
  674. * description: Automatically populate the columnModel when a new TableModel is submitted.
  675. */
  676. public void setAutoCreateColumnsFromModel(boolean createColumns) {
  677. if (autoCreateColumnsFromModel != createColumns) {
  678. autoCreateColumnsFromModel = createColumns;
  679. if (autoCreateColumnsFromModel)
  680. createDefaultColumnsFromModel();
  681. }
  682. }
  683. /**
  684. * Returns whether the table will create default columns from the model.
  685. * If this is true, setModel() will clear any existing columns and
  686. * create new columns from the new model. Also if the event in the
  687. * the tableChanged() notification specified the entired table changed
  688. * then the columns will be rebuilt. The default is true.
  689. *
  690. * @return the autoCreateColumnsFromModel of the table
  691. * @see #setAutoCreateColumnsFromModel
  692. * @see #createDefaultColumnsFromModel
  693. */
  694. public boolean getAutoCreateColumnsFromModel() {
  695. return autoCreateColumnsFromModel;
  696. }
  697. /**
  698. * This method will create default columns for the table from
  699. * the data model using the getColumnCount() and getColumnClass() methods
  700. * defined in the TableModel interface.
  701. * <p>
  702. * This method will clear any exsiting columns before creating the
  703. * new columns based on information from the model.
  704. *
  705. * @see #getAutoCreateColumnsFromModel
  706. */
  707. public void createDefaultColumnsFromModel() {
  708. TableModel m = getModel();
  709. if (m != null) {
  710. // Remove any current columns
  711. TableColumnModel cm = getColumnModel();
  712. cm.removeColumnModelListener(this);
  713. while (cm.getColumnCount() > 0)
  714. cm.removeColumn(cm.getColumn(0));
  715. // Create new columns from the data model info
  716. for (int i = 0; i < m.getColumnCount(); i++) {
  717. TableColumn newColumn = new TableColumn(i);
  718. addColumn(newColumn);
  719. }
  720. cm.addColumnModelListener(this);
  721. }
  722. }
  723. /**
  724. * Set a default renderer to be used if no renderer has been set in
  725. * a TableColumn. If renderer is null, remove the default renderer
  726. * for this column class.
  727. *
  728. * @see #getDefaultRenderer
  729. * @see #setDefaultEditor
  730. */
  731. public void setDefaultRenderer(Class columnClass, TableCellRenderer renderer) {
  732. if (renderer != null) {
  733. defaultRenderersByColumnClass.put(columnClass, renderer);
  734. }
  735. else {
  736. defaultRenderersByColumnClass.remove(columnClass);
  737. }
  738. }
  739. /**
  740. * Returns the renderer to be used when no renderer has been set in
  741. * a TableColumn. During the rendering of cells the renderer is fetched from
  742. * a Hashtable of entries according to the class of the cells in the column. If
  743. * there is no entry for this <I>columnClass</I> the method returns
  744. * the entry for the most specific superclass. The JTable installs entries
  745. * for <I>Object</I>, <I>Number</I> and <I>Boolean</I> all which can be modified
  746. * or replaced.
  747. *
  748. * @see #setDefaultRenderer
  749. * @see #getColumnClass
  750. */
  751. public TableCellRenderer getDefaultRenderer(Class columnClass) {
  752. if (columnClass == null) {
  753. return null;
  754. }
  755. else {
  756. Object renderer = defaultRenderersByColumnClass.get(columnClass);
  757. if (renderer != null) {
  758. return (TableCellRenderer)renderer;
  759. }
  760. else {
  761. return getDefaultRenderer(columnClass.getSuperclass());
  762. }
  763. }
  764. }
  765. /**
  766. * Set a default editor to be used if no editor has been set in
  767. * a TableColumn. If no editing is required in a table, or a
  768. * particular column in a table, use the isCellEditable()
  769. * method in the TableModel interface to ensure that the
  770. * JTable will not start an editor in these columns.
  771. * If editor is null, remove the default editor for this
  772. * column class.
  773. *
  774. * @see TableModel#isCellEditable
  775. * @see #getDefaultEditor
  776. * @see #setDefaultRenderer
  777. */
  778. public void setDefaultEditor(Class columnClass, TableCellEditor editor) {
  779. if (editor != null) {
  780. defaultEditorsByColumnClass.put(columnClass, editor);
  781. }
  782. else {
  783. defaultEditorsByColumnClass.remove(columnClass);
  784. }
  785. }
  786. /**
  787. * Returns the editor to be used when no editor has been set in
  788. * a TableColumn. During the editing of cells the editor is fetched from
  789. * a Hashtable of entries according to the class of the cells in the column. If
  790. * there is no entry for this <I>columnClass</I> the method returns
  791. * the entry for the most specific superclass. The JTable installs entries
  792. * for <I>Object</I>, <I>Number</I> and <I>Boolean</I> all which can be modified
  793. * or replaced.
  794. *
  795. * @see #setDefaultEditor
  796. * @see #getColumnClass
  797. */
  798. public TableCellEditor getDefaultEditor(Class columnClass) {
  799. if (columnClass == null) {
  800. return null;
  801. }
  802. else {
  803. Object editor = defaultEditorsByColumnClass.get(columnClass);
  804. if (editor != null) {
  805. return (TableCellEditor)editor;
  806. }
  807. else {
  808. return getDefaultEditor(columnClass.getSuperclass());
  809. }
  810. }
  811. }
  812. //
  813. // Selection methods
  814. //
  815. /**
  816. * Sets the table's selection mode to allow only single selections, a single
  817. * contiguous interval, or multiple intervals.
  818. *
  819. * NOTE:<br>
  820. * JTable provides all the methods for handling column and row selection.
  821. * When setting states, such as setSelectionMode, it not only
  822. * updates the mode for the row selection model but also sets similar
  823. * values in the selection model of the columnModel.
  824. * If you want to have the row and column selection models operating
  825. * in different modes, set them both directly.
  826. * <p>
  827. * Both the row and column selection models for the JTable default
  828. * to using a DefaultListSelectionModel so that JTable works the same
  829. * way as the JList. See setSelectionMode() in JList for details
  830. * about the modes.
  831. *
  832. * @see JList#setSelectionMode
  833. * @beaninfo
  834. * description: The selection mode used by the row and column selection models.
  835. * enum: SINGLE_SELECTION ListSelectionModel.SINGLE_SELECTION
  836. * SINGLE_INTERVAL_SELECTION ListSelectionModel.SINGLE_INTERVAL_SELECTION
  837. * MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
  838. */
  839. public void setSelectionMode(int selectionMode) {
  840. clearSelection();
  841. getSelectionModel().setSelectionMode(selectionMode);
  842. getColumnModel().getSelectionModel().setSelectionMode(selectionMode);
  843. }
  844. /**
  845. * Sets whether the rows in this model can be selected.
  846. *
  847. * @see #getRowSelectionAllowed
  848. * @beaninfo
  849. * description: If true, an entire row is selected for each selected cell.
  850. */
  851. public void setRowSelectionAllowed(boolean flag) {
  852. rowSelectionAllowed = flag;
  853. }
  854. /**
  855. * Returns true if rows can be selected.
  856. *
  857. * @return true if rows can be selected
  858. * @see #setRowSelectionAllowed
  859. */
  860. public boolean getRowSelectionAllowed() {
  861. return rowSelectionAllowed;
  862. }
  863. /**
  864. * Sets whether the columns in this model can be selected.
  865. *
  866. * @see #getColumnSelectionAllowed
  867. * @beaninfo
  868. * description: If true, an entire column is selected for each selected cell.
  869. */
  870. public void setColumnSelectionAllowed(boolean flag) {
  871. columnModel.setColumnSelectionAllowed(flag);
  872. }
  873. /**
  874. * Returns true if columns can be selected.
  875. *
  876. * @return true if columns can be selected.
  877. * @see #setColumnSelectionAllowed
  878. */
  879. public boolean getColumnSelectionAllowed() {
  880. return columnModel.getColumnSelectionAllowed();
  881. }
  882. /**
  883. * Sets whether this table allows both a column selection and a
  884. * row selection to exist at the same time. When set, this results
  885. * in a facility to select a rectangular region of cells in the display.
  886. * This flag over-rides the row and column selection
  887. * modes ensuring that cell selection is possible whenever this flag is set.
  888. * @see #getCellSelectionEnabled
  889. * @beaninfo
  890. * description: Select a rectangular region of cells rather than rows or columns.
  891. */
  892. public void setCellSelectionEnabled(boolean flag) {
  893. cellSelectionEnabled = flag;
  894. }
  895. /**
  896. * Returns true if simultaneous row and column selections are allowed
  897. *
  898. * @return true if simultaneous row and column selections are allowed
  899. * @see #setCellSelectionEnabled
  900. */
  901. public boolean getCellSelectionEnabled() {
  902. return cellSelectionEnabled;
  903. }
  904. /**
  905. * Select all rows, columns and cells in the table.
  906. */
  907. public void selectAll() {
  908. // If I'm currently editing, then I should stop editing
  909. if (isEditing()) {
  910. removeEditor();
  911. }
  912. setRowSelectionInterval(0, getRowCount()-1);
  913. setColumnSelectionInterval(0, getColumnCount()-1);
  914. }
  915. /**
  916. * Deselects all selected columns and rows.
  917. */
  918. public void clearSelection() {
  919. columnModel.getSelectionModel().clearSelection();
  920. selectionModel.clearSelection();
  921. }
  922. /**
  923. * Selects the rows from <i>index0</i> to <i>index1</i> inclusive.
  924. *
  925. * @param index0 one end of the interval.
  926. * @param index1 other end of the interval
  927. */
  928. public void setRowSelectionInterval(int index0, int index1) {
  929. selectionModel.setSelectionInterval(index0, index1);
  930. }
  931. /**
  932. * Selects the columns from <i>index0</i> to <i>index1</i> inclusive.
  933. *
  934. * @param index0 one end of the interval.
  935. * @param index1 other end of the interval
  936. */
  937. public void setColumnSelectionInterval(int index0, int index1) {
  938. columnModel.getSelectionModel().setSelectionInterval(index0, index1);
  939. }
  940. /**
  941. * Adds the rows from <i>index0</i> to <i>index0</i> inclusive to
  942. * the current selection.
  943. *
  944. * @param index0 one end of the interval.
  945. * @param index1 other end of the interval
  946. */
  947. public void addRowSelectionInterval(int index0, int index1) {
  948. selectionModel.addSelectionInterval(index0, index1);
  949. }
  950. /**
  951. * Adds the columns from <i>index0</i> to <i>index0</i> inclusive to
  952. * the current selection.
  953. *
  954. * @param index0 one end of the interval.
  955. * @param index1 other end of the interval
  956. */
  957. public void addColumnSelectionInterval(int index0, int index1) {
  958. columnModel.getSelectionModel().addSelectionInterval(index0, index1);
  959. }
  960. /**
  961. * Deselects the rows from <i>index0</i> to <i>index0</i> inclusive.
  962. *
  963. * @param index0 one end of the interval.
  964. * @param index1 other end of the interval
  965. */
  966. public void removeRowSelectionInterval(int index0, int index1) {
  967. selectionModel.removeSelectionInterval(index0, index1);
  968. }
  969. /**
  970. * Deselects the columns from <i>index0</i> to <i>index0</i> inclusive.
  971. *
  972. * @param index0 one end of the interval.
  973. * @param index1 other end of the interval
  974. */
  975. public void removeColumnSelectionInterval(int index0, int index1) {
  976. columnModel.getSelectionModel().removeSelectionInterval(index0, index1);
  977. }
  978. /**
  979. * Returns the index of the first selected row, -1 if no row is selected.
  980. */
  981. public int getSelectedRow() {
  982. return selectionModel.getMinSelectionIndex();
  983. }
  984. /**
  985. * Returns the index of the first selected column, -1 if no column is selected.
  986. */
  987. public int getSelectedColumn() {
  988. return columnModel.getSelectionModel().getMinSelectionIndex();
  989. }
  990. /**
  991. * Returns the indices of all selected rows.
  992. *
  993. * @return an array of ints containing the indices of all selected rows,
  994. * or an empty array if no row is selected.
  995. * @see #getSelectedRow
  996. */
  997. public int[] getSelectedRows() {
  998. if (selectionModel != null) {
  999. int iMin = selectionModel.getMinSelectionIndex();
  1000. int iMax = selectionModel.getMaxSelectionIndex();
  1001. if ((iMin == -1) || (iMax == -1)) {
  1002. return new int[0];
  1003. }
  1004. int[] rvTmp = new int[1+ (iMax - iMin)];
  1005. int n = 0;
  1006. for(int i = iMin; i <= iMax; i++) {
  1007. if (selectionModel.isSelectedIndex(i)) {
  1008. rvTmp[n++] = i;
  1009. }
  1010. }
  1011. int[] rv = new int[n];
  1012. System.arraycopy(rvTmp, 0, rv, 0, n);
  1013. return rv;
  1014. }
  1015. return new int[0];
  1016. }
  1017. /**
  1018. * Returns the indices of all selected columns.
  1019. *
  1020. * @return an array of ints containing the indices of all selected columns,
  1021. * or an empty array if no column is selected.
  1022. * @see #getSelectedColumn
  1023. */
  1024. public int[] getSelectedColumns() {
  1025. return columnModel.getSelectedColumns();
  1026. }
  1027. /**
  1028. * Returns the number of selected rows.
  1029. *
  1030. * @return the number of selected rows, 0 if no columns are selected
  1031. */
  1032. public int getSelectedRowCount() {
  1033. if (selectionModel != null) {
  1034. int iMin = selectionModel.getMinSelectionIndex();
  1035. int iMax = selectionModel.getMaxSelectionIndex();
  1036. int count = 0;
  1037. for(int i = iMin; i <= iMax; i++) {
  1038. if (selectionModel.isSelectedIndex(i)) {
  1039. count++;
  1040. }
  1041. }
  1042. return count;
  1043. }
  1044. return 0;
  1045. }
  1046. /**
  1047. * Returns the number of selected columns.
  1048. *
  1049. * @return the number of selected columns, 0 if no columns are selected
  1050. */
  1051. public int getSelectedColumnCount() {
  1052. return columnModel.getSelectedColumnCount();
  1053. }
  1054. /**
  1055. * Returns true if the row at the specified index is selected
  1056. *
  1057. * @return true if the row at index <I>row</I> is selected, where 0 is the
  1058. * first row
  1059. * @exception IllegalArgumentException if <I>row</I> is not in the
  1060. * valid range
  1061. */
  1062. public boolean isRowSelected(int row) {
  1063. if (selectionModel != null)
  1064. return selectionModel.isSelectedIndex(row);
  1065. return false;
  1066. }
  1067. /**
  1068. * Returns true if the column at the specified index is selected
  1069. *
  1070. * @return true if the column at index <I>column</I> is selected, where
  1071. * 0 is the first column
  1072. * @exception IllegalArgumentException if <I>column</I> is not in the
  1073. * valid range
  1074. */
  1075. public boolean isColumnSelected(int column) {
  1076. return columnModel.getSelectionModel().isSelectedIndex(column);
  1077. }
  1078. /**
  1079. * Returns true if the cell at the specified position is selected.
  1080. *
  1081. * @return true if the cell at index <I>(row, column)</I> is selected,
  1082. * where the first row and first column are at index 0
  1083. * @exception IllegalArgumentException if <I>row</I> or <I>column</I>
  1084. * are not in the valid range
  1085. */
  1086. public boolean isCellSelected(int row, int column) {
  1087. if (cellSelectionEnabled)
  1088. return isRowSelected(row) && isColumnSelected(column);
  1089. else
  1090. return (getRowSelectionAllowed() && isRowSelected(row)) ||
  1091. (getColumnSelectionAllowed() && isColumnSelected(column));
  1092. }
  1093. /**
  1094. * Returns the foreground color for selected cells.
  1095. *
  1096. * @return the Color object for the foreground property
  1097. * @see #setSelectionForeground
  1098. * @see #setSelectionBackground
  1099. */
  1100. public Color getSelectionForeground() {
  1101. return selectionForeground;
  1102. }
  1103. /**
  1104. * Set the foreground color for selected cells. Cell renderers
  1105. * can use this color to render text and graphics for selected
  1106. * cells.
  1107. * <p>
  1108. * The default value of this property is defined by the look
  1109. * and feel implementation.
  1110. * <p>
  1111. * This is a JavaBeans bound property.
  1112. *
  1113. * @param selectionForeground the Color to use in the foreground
  1114. * for selected list items
  1115. * @see #getSelectionForeground
  1116. * @see #setSelectionBackground
  1117. * @see #setForeground
  1118. * @see #setBackground
  1119. * @see #setFont
  1120. * @beaninfo
  1121. * bound: true
  1122. * description: A default foreground color for selected cells.
  1123. */
  1124. public void setSelectionForeground(Color selectionForeground) {
  1125. Color oldValue = this.selectionForeground;
  1126. this.selectionForeground = selectionForeground;
  1127. firePropertyChange("selectionForeground", oldValue, selectionForeground);
  1128. }
  1129. /**
  1130. * Returns the background color for selected cells.
  1131. *
  1132. * @return the Color used for the background of selected list items
  1133. * @see #setSelectionBackground
  1134. * @see #setSelectionForeground
  1135. */
  1136. public Color getSelectionBackground() {
  1137. return selectionBackground;
  1138. }
  1139. /**
  1140. * Set the background color for selected cells. Cell renderers
  1141. * can use this color to the fill selected cells.
  1142. * <p>
  1143. * The default value of this property is defined by the look
  1144. * and feel implementation.
  1145. * <p>
  1146. * This is a JavaBeans bound property.
  1147. *
  1148. * @param selectionBackground the Color to use for the background
  1149. * of selected cells
  1150. * @see #getSelectionBackground
  1151. * @see #setSelectionForeground
  1152. * @see #setForeground
  1153. * @see #setBackground
  1154. * @see #setFont
  1155. * @beaninfo
  1156. * bound: true
  1157. * description: A default background color for selected cells.
  1158. */
  1159. public void setSelectionBackground(Color selectionBackground) {
  1160. Color oldValue = this.selectionBackground;
  1161. this.selectionBackground = selectionBackground;
  1162. firePropertyChange("selectionBackground", oldValue, selectionBackground);
  1163. }
  1164. /**
  1165. * Returns the <B>TableColumn</B> object for the column in the table
  1166. * whose identifier is equal to <I>identifier</I>, when compared using
  1167. * <I>equals()</I>.
  1168. *
  1169. * @return the TableColumn object with matching identifier
  1170. * @exception IllegalArgumentException if <I>identifier</I> is null or no TableColumn has this identifier
  1171. *
  1172. * @param identifier the identifier object
  1173. */
  1174. public TableColumn getColumn(Object identifier) {
  1175. TableColumnModel cm = getColumnModel();
  1176. int columnIndex = cm.getColumnIndex(identifier);
  1177. return cm.getColumn(columnIndex);
  1178. }
  1179. //
  1180. // Informally implement the TableModel interface.
  1181. //
  1182. /**
  1183. * Return the index of the column in the model whose data is being displayed in
  1184. * the column <I>viewColumnIndex</I> in the display. Returns <I>viewColumnIndex</I>
  1185. * unchanged when <I>viewColumnIndex</I> is less than zero.
  1186. *
  1187. * @see #convertColumnIndexToView
  1188. */
  1189. public int convertColumnIndexToModel(int viewColumnIndex) {
  1190. if (viewColumnIndex < 0) {
  1191. return viewColumnIndex;
  1192. }
  1193. return getColumnModel().getColumn(viewColumnIndex).getModelIndex();
  1194. }
  1195. /**
  1196. * Return the index of the column in the view which is displaying the
  1197. * data from the column <I>modelColumnIndex</I> in the model. Returns
  1198. * -1 if this column is not being displayed. Returns <I>modelColumnIndex</I>
  1199. * unchanged when <I>modelColumnIndex</I> is less than zero.
  1200. *
  1201. * @see #convertColumnIndexToModel
  1202. */
  1203. public int convertColumnIndexToView(int modelColumnIndex) {
  1204. if (modelColumnIndex < 0) {
  1205. return modelColumnIndex;
  1206. }
  1207. TableColumnModel cm = getColumnModel();
  1208. for (int column = 0; column < getColumnCount(); column++) {
  1209. if (cm.getColumn(column).getModelIndex() == modelColumnIndex) {
  1210. return column;
  1211. }
  1212. }
  1213. return -1;
  1214. }
  1215. /**
  1216. * Returns the number of rows in the table.
  1217. *
  1218. * @see #getColumnCount
  1219. */
  1220. public int getRowCount() {
  1221. return getModel().getRowCount();
  1222. }
  1223. /**
  1224. * Returns the number of columns in the column model, note this may
  1225. * be different to the number of columns in the table model.
  1226. *
  1227. * @return the number of columns in the table
  1228. * @see #getRowCount
  1229. */
  1230. public int getColumnCount() {
  1231. return getColumnModel().getColumnCount();
  1232. }
  1233. /**
  1234. * Returns the name of the column at the specified view position.
  1235. *
  1236. * @return the name of the column at position <I>column</I> in the view
  1237. * where the first column is column 0.
  1238. */
  1239. public String getColumnName(int column) {
  1240. return getModel().getColumnName(convertColumnIndexToModel(column));
  1241. }
  1242. /**
  1243. * Returns the type of the column at the specified view position.
  1244. *
  1245. * @return the type of the column at position <I>column</I> in the view
  1246. * where the first column is column 0.
  1247. */
  1248. public Class getColumnClass(int column) {
  1249. return getModel().getColumnClass(convertColumnIndexToModel(column));
  1250. }
  1251. /**
  1252. * Returns the cell value at <I>row</I> and <I>column</I>.
  1253. * <p>
  1254. * <b>NOTE</b>: The column is specified in the table view's display
  1255. * order, and not in the TableModel's column order. This is
  1256. * an important distinction because as the user rearranges
  1257. * the columns in the table, what is at column 2 changes.
  1258. * Meanwhile the user's actions never affect the model's
  1259. * column ordering.
  1260. *
  1261. * @param row the row whose value is to be looked up
  1262. * @param column the column whose value is to be looked up
  1263. * @return the Object at the specified cell
  1264. */
  1265. public Object getValueAt(int row, int column) {
  1266. return getModel().getValueAt(row, convertColumnIndexToModel(column));
  1267. }
  1268. /**
  1269. * Sets the value for the cell at <I>row</I> and <I>column</I>.
  1270. * <I>aValue</I> is the new value.
  1271. *
  1272. * @param aValue the new value
  1273. * @param row the row whose value is to be changed
  1274. * @param column the column whose value is to be changed
  1275. * @see #getValueAt
  1276. */
  1277. public void setValueAt(Object aValue, int row, int column) {
  1278. getModel().setValueAt(aValue, row, convertColumnIndexToModel(column));
  1279. }
  1280. /**
  1281. * Returns true if the cell at <I>row</I> and <I>column</I>
  1282. * is editable. Otherwise, setValueAt() on the cell will not change
  1283. * the value of that cell.
  1284. *
  1285. * @param row the row whose value is to be looked up
  1286. * @param column the column whose value is to be looked up
  1287. * @return true if the cell is editable.
  1288. * @see #setValueAt
  1289. */
  1290. public boolean isCellEditable(int row, int column) {
  1291. return getModel().isCellEditable(row, convertColumnIndexToModel(column));
  1292. }
  1293. //
  1294. // Adding and removing columns in the view
  1295. //
  1296. /**
  1297. * Appends <I>aColumn</I> to the end of the array of columns held by
  1298. * the JTable's column model.
  1299. * If the header value of <I>aColumn</I> is <I>null</I>,
  1300. * sets the header value of <I>aColumn</I> to the name
  1301. * returned by <code>getModel().getColumnName()</code>.
  1302. * <p>
  1303. * To add a column to the JTable to display the <I>modelColumn</I>'th column of
  1304. * data in the model, with a given <I>width</I>,
  1305. * <I>cellRenderer</I> and <I>cellEditor</I> you can use:
  1306. * <pre>
  1307. *
  1308. * addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
  1309. *
  1310. * </pre>
  1311. * [All of the other constructors in the TableColumn can be used in place of
  1312. * this one.] The model column is stored inside the TableColumn and is used during
  1313. * rendering and editing to locate the appropriate data values in the
  1314. * model. The model column does not change when columns are reordered
  1315. * in the view.
  1316. *
  1317. * @param aColumn The <B>TableColumn</B> to be added
  1318. * @see #removeColumn
  1319. */
  1320. public void addColumn(TableColumn aColumn) {
  1321. int modelColumn = aColumn.getModelIndex();
  1322. String columnName = getModel().getColumnName(modelColumn);
  1323. if (aColumn.getHeaderValue() == null) {
  1324. aColumn.setHeaderValue(columnName);
  1325. }
  1326. getColumnModel().addColumn(aColumn);
  1327. }
  1328. /**
  1329. * Removes <I>aColumn</I> from the JTable's array of columns.
  1330. * Note: this method does not remove the column of data from the
  1331. * model it just removes the TableColumn that was displaying it.
  1332. *
  1333. * @param aColumn The <B>TableColumn</B> to be removed
  1334. * @see #addColumn
  1335. */
  1336. public void removeColumn(TableColumn aColumn) {
  1337. getColumnModel().removeColumn(aColumn);
  1338. }
  1339. /**
  1340. * Moves the column <I>column</I> to the position currently occupied by the
  1341. * column <I>targetColumn</I>. The old column at <I>targetColumn</I> is
  1342. * shifted left or right to make room.
  1343. *
  1344. * @param column the index of column to be moved
  1345. * @param targetColumn the new index of the column
  1346. */
  1347. public void moveColumn(int column, int targetColumn) {
  1348. getColumnModel().moveColumn(column, targetColumn);
  1349. }
  1350. //
  1351. // Cover methods for various models and helper methods
  1352. //
  1353. /**
  1354. * Returns the index of the column that <I>point</I> lies in, or -1 if it
  1355. * lies outside the receiver's bounds.
  1356. *
  1357. * @return the index of the column that <I>point</I> lies in, or -1 if it
  1358. * lies outside the receiver's bounds
  1359. * @see #rowAtPoint
  1360. */
  1361. public int columnAtPoint(Point point) {
  1362. return getColumnModel().getColumnIndexAtX(point.x);
  1363. }
  1364. /**
  1365. * Returns the index of the row that <I>point</I> lies in, or -1 if is
  1366. * not in the range [0, getRowCount()-1].
  1367. *
  1368. * @return the index of the row that <I>point</I> lies in, or -1 if it
  1369. * is not in the range [0, getRowCount()-1]
  1370. * @see #columnAtPoint
  1371. */
  1372. public int rowAtPoint(Point point) {
  1373. int y = point.y;
  1374. // if (y < 0 || y >= getBounds().height) {
  1375. // return -1;
  1376. // }
  1377. int rowHeight = getRowHeight();
  1378. int rowSpacing = getIntercellSpacing().height;
  1379. int totalRowHeight = rowHeight + rowSpacing;
  1380. int result = ytotalRowHeight;
  1381. if (result < 0) {
  1382. return -1;
  1383. }
  1384. else if (result >= getRowCount()) {
  1385. return -1;
  1386. }
  1387. else {
  1388. return result;
  1389. }
  1390. }
  1391. /**
  1392. * Returns a rectangle locating the cell that lies at the intersection of
  1393. * <I>row</I> and <I>column</I>. If <I>includeSpacing</I> is true then
  1394. * the value returned includes the intercellSpacing margin. If it is false,
  1395. * then the returned rect is inset by half of intercellSpacing.
  1396. * (This is the true frame of the cell)
  1397. *
  1398. * @param row the row to compute
  1399. * @param column the column to compute
  1400. * @param includeSpacing if true, the rect returned will
  1401. * include the correct
  1402. * intercellSpacing
  1403. * @return the rectangle containing the cell at index
  1404. * <I>row</I>,<I>column</I>
  1405. * @exception IllegalArgumentException If <I>row</I> or <I>column</I>
  1406. * are not in the valid range.
  1407. */
  1408. public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
  1409. int index = 0;
  1410. Rectangle cellFrame;
  1411. int columnMargin = getColumnModel().getColumnMargin();
  1412. Enumeration enumeration = getColumnModel().getColumns();
  1413. TableColumn aColumn;
  1414. cellFrame = new Rectangle();
  1415. cellFrame.height = getRowHeight() + rowMargin;
  1416. cellFrame.y = row * cellFrame.height;
  1417. while (enumeration.hasMoreElements()) {
  1418. aColumn = (TableColumn)enumeration.nextElement();
  1419. cellFrame.width = aColumn.getWidth() + columnMargin;
  1420. if (index == column)
  1421. break;
  1422. cellFrame.x += cellFrame.width;
  1423. index++;
  1424. }
  1425. if (!includeSpacing) {
  1426. Dimension spacing = getIntercellSpacing();
  1427. // This is not the same as grow(), it rounds differently.
  1428. cellFrame.setBounds(cellFrame.x + spacing.width2,
  1429. cellFrame.y + spacing.height2,
  1430. cellFrame.width - spacing.width,
  1431. cellFrame.height - spacing.height);
  1432. }
  1433. return cellFrame;
  1434. }
  1435. /**
  1436. * Calls super.reshape(), and is overridden simply to detect changes in
  1437. * our bounds. After reshaping we resize the columns (similar to triggering
  1438. * a layout) to fit the new bounds for the component using sizeColumnsToFit().
  1439. *
  1440. * @see #sizeColumnsToFit(int)
  1441. */
  1442. public void reshape(int x, int y, int width, int height) {
  1443. boolean widthChanged = (getWidth() != width);
  1444. super.reshape(x, y, width, height);
  1445. if (widthChanged) {
  1446. sizeColumnsToFit(-1);
  1447. }
  1448. }
  1449. /**
  1450. * Sizes the table columns to fit the available space.
  1451. * @deprecated As of Swing version 1.0.3,
  1452. * replaced by <code>sizeColumnsToFit(int)</code>.
  1453. * @see #sizeColumnsToFit(int)
  1454. */
  1455. public void sizeColumnsToFit(boolean lastColumnOnly) {
  1456. int oldAutoResizeMode = autoResizeMode;
  1457. setAutoResizeMode(lastColumnOnly ? AUTO_RESIZE_LAST_COLUMN
  1458. : AUTO_RESIZE_ALL_COLUMNS);
  1459. sizeColumnsToFit(-1);
  1460. setAutoResizeMode(oldAutoResizeMode);
  1461. }
  1462. /**
  1463. * This method will resize one or more ot the columns in the table
  1464. * so that the total width of all of the JTable's columns will be
  1465. * equal to the width of the table.
  1466. * <p>
  1467. * When setBounds() is called on the JTable, often as
  1468. * a result of resizing of an enclosing window -
  1469. * this method is called with <code>resizingColumn</code>
  1470. * set to -1. This means that resizing has taken place 'outside' the
  1471. * JTable and the change - or 'delta' - should be distributed to all
  1472. * of the columns regardless of the JTable's autoResizeMode mode.
  1473. * <p>
  1474. * If the <code>resizingColumn</code> is not -1, it is one of
  1475. * the columns in the table that has changed size rather than
  1476. * the table itself. In this case the auto-resize modes govern
  1477. * the way the extra (or defecit) space is distributed
  1478. * amongst the availible columns.
  1479. * <p>
  1480. * The modes are:
  1481. * <ul>
  1482. * <li> AUTO_RESIZE_OFF Don't automatically adjust the column's
  1483. * widths at all. Use a horizontal scrollbar to accomodate the
  1484. * columns when their sum exceeds the width of the Viewport.
  1485. * If the JTable is not enclosed in a JScrollPane this may
  1486. * leave parts of the table invisible.
  1487. * <li> AUTO_RESIZE_NEXT_COLUMN: Use just the column after the
  1488. * resizing column. This results in the 'boundry' or divider
  1489. * between adjacent cells being independently adjustable.
  1490. * <li> AUTO_RESIZE_SUBSEQUENT_COLUMNS: Use all columns after the
  1491. * one being adjusted to absorb the changes.
  1492. * <li> AUTO_RESIZE_LAST_COLUMN Only ever automatically adjust the
  1493. * size of the last column. If the bounds of the last column
  1494. * prevent the desired size from being allocated, set the
  1495. * width of the last column to the appropriate limit and make
  1496. * no further adjustments.
  1497. * <li> AUTO_RESIZE_ALL_COLUMNS Spread the delta amongst all the columns
  1498. * in the JTable, including the one that is being adjusted.
  1499. * </ul>
  1500. * <p>
  1501. * Note: When the JTable makes adjustments to the widths of the
  1502. * columns it respects their minimum and maximum values absolutely.
  1503. * It is therefore possible that, even after this method is called,
  1504. * the total width of the columns is still not equal to the width
  1505. * of the table. When this happens the JTable does not put itself
  1506. * in AUTO_RESIZE_OFF mode to bring up a ScrollBar, or break other
  1507. * commitments of its current auto-resize mode - instead it
  1508. * allows its bounds to be set larger (or smaller) than the total of the
  1509. * column minima or maxima, meaning, either that there
  1510. * will not be enough room to display all of the columns, or that the
  1511. * columns will not fill the JTable's bounds. These respectively, result
  1512. * in the clipping of some columns or an area being painted in the
  1513. * JTable's background color during painting.
  1514. * <p>
  1515. * The mechanism for distributing the delta amongst the availible
  1516. * columns is provided in a private method in the JTable class:
  1517. * <pre>
  1518. * adjustSizes(long targetSize, final Resizable3 r, boolean inverse)
  1519. * </pre>
  1520. * an explanation of which is provided below. Resizable3 is a private
  1521. * interface that allows any data structure containing a collection
  1522. * of elements with a size, preferredSize, maximumSize and minimumSize
  1523. * to have its elements manipulated by the algorithm.
  1524. * <p>
  1525. * <H3> Distributing the delta </H3>
  1526. * <p>
  1527. * <H4> Overview </H4>
  1528. * <P>
  1529. * Call 'DELTA' the difference between the targetSize and the
  1530. * sum of the preferred sizes of the elements in r. The individual
  1531. * sizes are calculated by taking the original preferred
  1532. * sizes and adding a share of the DELTA - that share being based on
  1533. * how far each preferred size is from its limiting bound (minimum or
  1534. * maximum).
  1535. * <p>
  1536. * <H4>Definition</H4>
  1537. * <P>
  1538. * Call the individual constraints min[i], max[i] and pref[i].?
  1539. * <p>
  1540. * Call their respective sums: MIN, MAX and PREF.?
  1541. * <p>
  1542. * Each new size will be calculated using:
  1543. * <p>
  1544. * <pre>
  1545. * size[i] = pref[i] + delta[i]
  1546. * </pre>
  1547. * where each individual delta[i] is calculated according to:
  1548. * <p>
  1549. * If (DELTA < 0) we are in shrink mode where:?
  1550. * <p>
  1551. * <PRE>
  1552. *                         ? DELTA
  1553. *       ? delta[i] =     ------------ * (pref[i] - min[i])
  1554. *                        (PREF - MIN)
  1555. * </PRE>
  1556. * If (DELTA > 0) we are in expand mode where:?
  1557. * <p>
  1558. * <PRE>
  1559. *                         ? DELTA
  1560. *       ? delta[i] =     ------------ * (max[i] - pref[i])
  1561. *                        (MAX - PREF)
  1562. * </PRE>
  1563. * <P>
  1564. * The overall effect is that the total size moves that same percentage,
  1565. * k, towards the total minimum or maximum and that percentage guarentees
  1566. * accomodation of the required space, DELTA.
  1567. *
  1568. * <H4>Details</H4>
  1569. * <P>
  1570. * Naive evaluation of the formulae presented here would be subject to
  1571. * the aggregated rounding errors caused by doing this operation in finite
  1572. * precision (using ints). To deal with this, the muliplying factor above,
  1573. * is constantly recalculated and this takes account of the rounding errors in
  1574. * the previous iterations. The result is an algorithm which produces
  1575. * a set of integers whose values exactly sum to the supplied
  1576. * <code>targetSize</code>, and does so by spreading the rounding
  1577. * errors evenly over the given elements.
  1578. *
  1579. * <H4>When the MAX and MIN bounds are hit</H4>
  1580. * <P>
  1581. * When <code>targetSize</code> is outside the [MIN, MAX] range, the algorithm
  1582. * sets all sizes to either their appropriate limiting value (maximum or minimum).
  1583. *
  1584. * @param resizingColumn The column whose resizing made this adjustment
  1585. * necessary or -1 if there is no such column.
  1586. * @see TableColumn#setWidth
  1587. */
  1588. public void sizeColumnsToFit(int resizingColumn) {
  1589. if (resizingColumn == -1) {
  1590. setWidthsFromPreferredWidths(false);
  1591. }
  1592. else {
  1593. if (autoResizeMode == AUTO_RESIZE_OFF) {
  1594. Enumeration enumeration = getColumnModel().getColumns();
  1595. while (enumeration.hasMoreElements()) {
  1596. TableColumn aColumn = (TableColumn)enumeration.nextElement();
  1597. aColumn.setPreferredWidth(aColumn.getWidth());
  1598. }
  1599. }
  1600. else {
  1601. int delta = getWidth() - getColumnModel().getTotalColumnWidth();
  1602. accommodateDelta(resizingColumn, delta);
  1603. }
  1604. }
  1605. }
  1606. private void setWidthsFromPreferredWidths(final boolean inverse) {
  1607. int columnCount = getColumnCount();
  1608. int totalIntercellSpacing = columnCount * getColumnModel().getColumnMargin();
  1609. int totalWidth = getWidth() - totalIntercellSpacing;
  1610. int totalPreferred = getPreferredSize().width - totalIntercellSpacing;
  1611. int target = !inverse ? totalWidth : totalPreferred;
  1612. final TableColumnModel cm = columnModel;
  1613. Resizable3 r = new Resizable3() {
  1614. public int getElementCount() { return cm.getColumnCount(); }
  1615. public int getLowerBoundAt(int i) { return cm.getColumn(i).getMinWidth(); }
  1616. public int getUpperBoundAt(int i) { return cm.getColumn(i).getMaxWidth(); }
  1617. public int getMidPointAt(int i) {
  1618. if (!inverse) {
  1619. return cm.getColumn(i).getPreferredWidth();
  1620. }
  1621. else {
  1622. return cm.getColumn(i).getWidth();
  1623. }
  1624. }
  1625. public void setSizeAt(int s, int i) {
  1626. if (!inverse) {
  1627. cm.getColumn(i).setWidth(s);
  1628. }
  1629. else {
  1630. cm.getColumn(i).setPreferredWidth(s);
  1631. }
  1632. }
  1633. };
  1634. adjustSizes(target, r, inverse);
  1635. }
  1636. // Distribute delta over columns, as indicated by the autoresize mode.
  1637. private void accommodateDelta(int resizingColumnIndex, int delta) {
  1638. int columnCount = getColumnCount();
  1639. int from = resizingColumnIndex;
  1640. int to = columnCount;
  1641. // Use the mode to determine how to absorb the changes.
  1642. switch(autoResizeMode) {
  1643. case AUTO_RESIZE_NEXT_COLUMN: from = from + 1; to = from + 1; break;
  1644. case AUTO_RESIZE_SUBSEQUENT_COLUMNS: from = from + 1; to = columnCount; break;
  1645. case AUTO_RESIZE_LAST_COLUMN: from = columnCount - 1; to = from + 1; break;
  1646. case AUTO_RESIZE_ALL_COLUMNS: from = 0; to = columnCount; break;
  1647. default: return;
  1648. }
  1649. final int start = from;
  1650. final int end = to;
  1651. final TableColumnModel cm = columnModel;
  1652. Resizable3 r = new Resizable3() {
  1653. public int getElementCount() { return end-start; }
  1654. public int getLowerBoundAt(int i) { return cm.getColumn(i+start).getMinWidth(); }
  1655. public int getUpperBoundAt(int i) { return cm.getColumn(i+start).getMaxWidth(); }
  1656. public int getMidPointAt(int i) { return cm.getColumn(i+start).getWidth(); }
  1657. public void setSizeAt(int s, int i) { cm.getColumn(i+start).setWidth(s); }
  1658. };
  1659. int totalWidth = 0;
  1660. for(int i = from; i < to; i++) {
  1661. TableColumn aColumn = columnModel.getColumn(i);
  1662. int input = aColumn.getWidth();
  1663. totalWidth = totalWidth + input;
  1664. }
  1665. adjustSizes(totalWidth + delta, r, false);
  1666. setWidthsFromPreferredWidths(true);
  1667. // setWidthsFromPreferredWidths(false);
  1668. return;
  1669. }
  1670. private interface Resizable2 {
  1671. public int getElementCount();
  1672. public int getLowerBoundAt(int i);
  1673. public int getUpperBoundAt(int i);
  1674. public void setSizeAt(int newSize, int i);
  1675. }
  1676. private interface Resizable3 extends Resizable2 {
  1677. public int getMidPointAt(int i);
  1678. }
  1679. private void adjustSizes(long target, final Resizable3 r, boolean inverse) {
  1680. int N = r.getElementCount();
  1681. long totalPreferred = 0;
  1682. for(int i = 0; i < N; i++) {
  1683. totalPreferred += r.getMidPointAt(i);
  1684. }
  1685. Resizable2 s;
  1686. if ((target < totalPreferred) == !inverse) {
  1687. s = new Resizable2() {
  1688. public int getElementCount() { return r.getElementCount(); }
  1689. public int getLowerBoundAt(int i) { return r.getLowerBoundAt(i); }
  1690. public int getUpperBoundAt(int i) { return r.getMidPointAt(i); }
  1691. public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
  1692. };
  1693. }
  1694. else {
  1695. s = new Resizable2() {
  1696. public int getElementCount() { return r.getElementCount(); }
  1697. public int getLowerBoundAt(int i) { return r.getMidPointAt(i); }
  1698. public int getUpperBoundAt(int i) { return r.getUpperBoundAt(i); }
  1699. public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
  1700. };
  1701. }
  1702. adjustSizes(target, s, !inverse);
  1703. }
  1704. private void adjustSizes(long target, Resizable2 r, boolean limitToRange) {
  1705. long totalLowerBound = 0;
  1706. long totalUpperBound = 0;
  1707. for(int i = 0; i < r.getElementCount(); i++) {
  1708. totalLowerBound += r.getLowerBoundAt(i);
  1709. totalUpperBound += r.getUpperBoundAt(i);
  1710. }
  1711. if (limitToRange) {
  1712. target = Math.min(Math.max(totalLowerBound, target), totalUpperBound);
  1713. }
  1714. for(int i = 0; i < r.getElementCount(); i++) {
  1715. int lowerBound = r.getLowerBoundAt(i);
  1716. int upperBound = r.getUpperBoundAt(i);
  1717. // Check for zero. This happens when the distribution of the delta
  1718. // finishes early due to a series of 'fixed' entries at the end.
  1719. // In this case, lowerBound == upperBound, for all subsequent terms.
  1720. int newSize;
  1721. if (totalLowerBound == totalUpperBound) {
  1722. newSize = lowerBound;
  1723. }
  1724. else {
  1725. double f = (double)(target - totalLowerBound)/(totalUpperBound - totalLowerBound);
  1726. newSize = (int)Math.round(lowerBound+f*(upperBound - lowerBound));
  1727. // We'd need to round manually in an all integer version.
  1728. // size[i] = (int)(((totalUpperBound - target) * lowerBound +
  1729. // (target - totalLowerBound) * upperBound)/(totalUpperBound-totalLowerBound));
  1730. }
  1731. r.setSizeAt(newSize, i);
  1732. target -= newSize;
  1733. totalLowerBound -= lowerBound;
  1734. totalUpperBound -= upperBound;
  1735. }
  1736. }
  1737. /**
  1738. * Overrides JComponent's setToolTipText method to allow use of the
  1739. * renderer's tips (if the renderer has text set).
  1740. * <p>
  1741. * NOTE: For JTable to properly display tooltips of its renderers
  1742. * JTable must be a registered component with the ToolTipManager.
  1743. * This is done automatically in initializeLocalVars(), but
  1744. * if at a later point JTable is told setToolTipText(null)
  1745. * it will unregister the table component, and no tips from
  1746. * renderers will display anymore.
  1747. *
  1748. * @see JComponent#getToolTipText
  1749. */
  1750. public String getToolTipText(MouseEvent event) {
  1751. String tip = null;
  1752. Point p = event.getPoint();
  1753. // Locate the renderer under the event location
  1754. int hitColumnIndex = columnAtPoint(p);
  1755. int hitRowIndex = rowAtPoint(p);
  1756. if ((hitColumnIndex != -1) && (hitRowIndex != -1)) {
  1757. TableCellRenderer renderer = getCellRenderer(hitRowIndex, hitColumnIndex);
  1758. Component component = prepareRenderer(renderer, hitRowIndex, hitColumnIndex);
  1759. // Now have to see if the component is a JComponent before
  1760. // getting the tip
  1761. if (component instanceof JComponent) {
  1762. // Convert the event to the renderer's coordinate system
  1763. Rectangle cellRect = getCellRect(hitRowIndex, hitColumnIndex, false);
  1764. p.translate(-cellRect.x, -cellRect.y);
  1765. MouseEvent newEvent = new MouseEvent(component, event.getID(),
  1766. event.getWhen(), event.getModifiers(),
  1767. p.x, p.y, event.getClickCount(),
  1768. event.isPopupTrigger());
  1769. tip = ((JComponent)component).getToolTipText(newEvent);
  1770. }
  1771. }
  1772. // No tip from the renderer get our own tip
  1773. if (tip == null)
  1774. tip = getToolTipText();
  1775. return tip;
  1776. }
  1777. //
  1778. // Editing Support
  1779. //
  1780. /**
  1781. * Programmatically starts editing the cell at <I>row</I> and
  1782. * <I>column</I>, if the cell is editable.
  1783. *
  1784. * @param row the row to be edited
  1785. * @param column the column to be edited
  1786. * @exception IllegalArgumentException If <I>row</I> or <I>column</I>
  1787. * are not in the valid range
  1788. * @return false if for any reason the cell cannot be edited.
  1789. */
  1790. public boolean editCellAt(int row, int column) {
  1791. return editCellAt(row, column, null);
  1792. }
  1793. /**
  1794. * Programmatically starts editing the cell at <I>row</I> and
  1795. * <I>column</I>, if the cell is editable.
  1796. * To prevent the JTable from editing a particular table, column or
  1797. * cell value, return false from the isCellEditable() method in the
  1798. * TableModel interface.
  1799. *
  1800. * @param row the row to be edited
  1801. * @param column the column to be edited
  1802. * @param e event to pass into
  1803. * shouldSelectCell
  1804. * @exception IllegalArgumentException If <I>row</I> or <I>column</I>
  1805. * are not in the valid range
  1806. * @return false if for any reason the cell cannot be edited.
  1807. */
  1808. public boolean editCellAt(int row, int column, EventObject e){
  1809. if (cellEditor != null && !cellEditor.stopCellEditing()) {
  1810. return false;
  1811. }
  1812. if (!isCellEditable(row, column))
  1813. return false;
  1814. TableCellEditor editor = getCellEditor(row, column);
  1815. if (editor != null && editor.isCellEditable(e)) {
  1816. editorComp = prepareEditor(editor, row, column);
  1817. editorComp.setBounds(getCellRect(row, column, false));
  1818. add(editorComp);
  1819. editorComp.validate();
  1820. setCellEditor(editor);
  1821. setEditingRow(row);
  1822. setEditingColumn(column);
  1823. editor.addCellEditorListener(this);
  1824. return true;
  1825. }
  1826. return false;
  1827. }
  1828. /**
  1829. * Returns true is the table is editing a cell.
  1830. *
  1831. * @return true is the table is editing a cell
  1832. * @see #editingColumn
  1833. * @see #editingRow
  1834. */
  1835. public boolean isEditing() {
  1836. return (cellEditor == null)? false : true;
  1837. }
  1838. /**
  1839. * If the receiver is currently editing this will return the Component
  1840. * that was returned from the CellEditor.
  1841. *
  1842. * @return Component handling editing session
  1843. */
  1844. public Component getEditorComponent() {
  1845. return editorComp;
  1846. }
  1847. /**
  1848. * This returns the index of the editing column.
  1849. *
  1850. * @return the index of the column being edited
  1851. * @see #editingRow
  1852. */
  1853. public int getEditingColumn() {
  1854. return editingColumn;
  1855. }
  1856. /**
  1857. * Returns the index of the editing row.
  1858. *
  1859. * @return the index of the row being edited
  1860. * @see #editingColumn
  1861. */
  1862. public int getEditingRow() {
  1863. return editingRow;
  1864. }
  1865. //
  1866. // Managing TableUI
  1867. //
  1868. /**
  1869. * Returns the L&F object that renders this component.
  1870. *
  1871. * @return the TableUI object that renders this component
  1872. */
  1873. public TableUI getUI() {
  1874. return (TableUI)ui;
  1875. }
  1876. /**
  1877. * Sets the L&F object that renders this component.
  1878. *
  1879. * @param ui the TableUI L&F object
  1880. * @see UIDefaults#getUI
  1881. */
  1882. public void setUI(TableUI ui) {
  1883. if (this.ui != ui) {
  1884. super.setUI(ui);
  1885. repaint();
  1886. }
  1887. }
  1888. private void updateSubComponentUI(Object componentShell) {
  1889. if (componentShell == null) {
  1890. return;
  1891. }
  1892. Component component = null;
  1893. if (componentShell instanceof Component) {
  1894. component = (Component)componentShell;
  1895. }
  1896. if (componentShell instanceof DefaultCellEditor) {
  1897. component = ((DefaultCellEditor)componentShell).getComponent();
  1898. }
  1899. if (component != null && component instanceof JComponent) {
  1900. ((JComponent)component).updateUI();
  1901. }
  1902. }
  1903. /**
  1904. * Notification from the UIManager that the L&F has changed.
  1905. * Replaces the current UI object with the latest version from the
  1906. * UIManager.
  1907. *
  1908. * @see JComponent#updateUI
  1909. */
  1910. public void updateUI() {
  1911. // Update the UIs of the cell renderers, cell editors and header renderers.
  1912. TableColumnModel cm = getColumnModel();
  1913. for(int column = 0; column < cm.getColumnCount(); column++) {
  1914. TableColumn aColumn = cm.getColumn(column);
  1915. // updateSubComponentUI(aColumn.getCellRenderer());
  1916. updateSubComponentUI(aColumn.getCellEditor());
  1917. // updateSubComponentUI(aColumn.getHeaderRenderer());
  1918. }
  1919. // Update the UIs of all the default renderers.
  1920. /*
  1921. Enumeration defaultRenderers = defaultRenderersByColumnClass.elements();
  1922. while (defaultRenderers.hasMoreElements()) {
  1923. updateSubComponentUI(defaultRenderers.nextElement());
  1924. }
  1925. */
  1926. // Update the UIs of all the default editors.
  1927. Enumeration defaultEditors = defaultEditorsByColumnClass.elements();
  1928. while (defaultEditors.hasMoreElements()) {
  1929. updateSubComponentUI(defaultEditors.nextElement());
  1930. }
  1931. setUI((TableUI)UIManager.getUI(this));
  1932. resizeAndRepaint();
  1933. invalidate();//PENDING
  1934. }
  1935. /**
  1936. * Returns the name of the L&F class that renders this component.
  1937. *
  1938. * @return "TableUI"
  1939. * @see JComponent#getUIClassID
  1940. * @see UIDefaults#getUI
  1941. */
  1942. public String getUIClassID() {
  1943. return uiClassID;
  1944. }
  1945. //
  1946. // Managing models
  1947. //
  1948. /**
  1949. * Sets the data model for this table to <I>newModel</I> and registers
  1950. * with for listner notifications from the new data model.
  1951. *
  1952. * @param newModel the new data source for this table
  1953. * @exception IllegalArgumentException if <I>newModel</I> is null
  1954. * @see #getModel
  1955. * @beaninfo
  1956. * description: The model that is the source of the data for this view.
  1957. */
  1958. public void setModel(TableModel newModel) {
  1959. TableModel oldModel = dataModel;
  1960. if (newModel == null)
  1961. throw new IllegalArgumentException("Cannot set a null TableModel");
  1962. if (newModel != oldModel) {
  1963. if (oldModel != null)
  1964. oldModel.removeTableModelListener(this);
  1965. dataModel = newModel;
  1966. newModel.addTableModelListener(this);
  1967. // If this method is called from the JTable constructor,
  1968. // the column model will be null. In this case we can't use
  1969. // the usual methods to update the internal state. In all other
  1970. // cases, use the usual tableChanged() method to reconfigure
  1971. // the JTable for the new model.
  1972. if (getColumnModel() != null) {
  1973. tableChanged(new TableModelEvent(dataModel, TableModelEvent.HEADER_ROW));
  1974. }
  1975. firePropertyChange("model", oldModel, newModel);
  1976. }
  1977. }
  1978. /**
  1979. * Returns the <B>TableModel</B> that provides the data displayed by
  1980. * the receiver.
  1981. *
  1982. * @return the object that provides the data displayed by the receiver
  1983. * @see #setModel
  1984. */
  1985. public TableModel getModel() {
  1986. return dataModel;
  1987. }
  1988. /**
  1989. * Sets the column model for this table to <I>newModel</I> and registers
  1990. * with for listner notifications from the new column model. Also sets
  1991. * the column model of the JTableHeader to <I>newModel</I>.
  1992. *
  1993. * @param newModel the new data source for this table
  1994. * @exception IllegalArgumentException if <I>newModel</I> is null
  1995. * @see #getColumnModel
  1996. * @beaninfo
  1997. * description: The object governing the way columns appear in the view.
  1998. */
  1999. public void setColumnModel(TableColumnModel newModel) {
  2000. if (newModel == null) {
  2001. throw new IllegalArgumentException("Cannot set a null ColumnModel");
  2002. }
  2003. TableColumnModel oldModel = columnModel;
  2004. if (newModel != oldModel) {
  2005. if (oldModel != null)
  2006. oldModel.removeColumnModelListener(this);
  2007. columnModel = newModel;
  2008. newModel.addColumnModelListener(this);
  2009. // Set the column model of the header as well.
  2010. if (tableHeader != null) {
  2011. tableHeader.setColumnModel(newModel);
  2012. }
  2013. firePropertyChange("columnModel", oldModel, newModel);
  2014. resizeAndRepaint();
  2015. }
  2016. }
  2017. /**
  2018. * Returns the <B>TableColumnModel</B> that contains all column inforamtion
  2019. * of this table.
  2020. *
  2021. * @return the object that provides the column state of the table
  2022. * @see #setColumnModel
  2023. */
  2024. public TableColumnModel getColumnModel() {
  2025. return columnModel;
  2026. }
  2027. /**
  2028. * Sets the row selection model for this table to <I>newModel</I>
  2029. * and registers with for listner notifications from the new selection model.
  2030. *
  2031. * @param newModel the new selection model
  2032. * @exception IllegalArgumentException if <I>newModel</I> is null
  2033. * @see #getSelectionModel
  2034. * @beaninfo
  2035. * description: The selection model for rows.
  2036. */
  2037. public void setSelectionModel(ListSelectionModel newModel) {
  2038. if (newModel == null) {
  2039. throw new IllegalArgumentException("Cannot set a null SelectionModel");
  2040. }
  2041. ListSelectionModel oldModel = selectionModel;
  2042. if (newModel != oldModel) {
  2043. if (oldModel != null) {
  2044. oldModel.removeListSelectionListener(this);
  2045. }
  2046. selectionModel = newModel;
  2047. if (newModel != null) {
  2048. newModel.addListSelectionListener(this);
  2049. }
  2050. firePropertyChange("selectionModel", oldModel, newModel);
  2051. repaint();
  2052. }
  2053. }
  2054. /**
  2055. * Returns the <B>ListSelectionModel</B> that is used to maintain row
  2056. * selection state.
  2057. *
  2058. * @return the object that provides row selection state. Or <B>null</B>
  2059. * if row selection is not allowed.
  2060. * @see #setSelectionModel
  2061. */
  2062. public ListSelectionModel getSelectionModel() {
  2063. return selectionModel;
  2064. }
  2065. //
  2066. // Implementing TableModelListener interface
  2067. //
  2068. /**
  2069. * The TableModelEvent should be constructed in the co-ordinate system
  2070. * of the model, the appropriate mapping to the view co-ordinate system
  2071. * is performed by the JTable when it recieves the event.
  2072. */
  2073. public void tableChanged(TableModelEvent e) {
  2074. if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
  2075. // The whole thing changed
  2076. clearSelection();
  2077. if (getAutoCreateColumnsFromModel())
  2078. createDefaultColumnsFromModel();
  2079. resizeAndRepaint();
  2080. if (tableHeader != null) {
  2081. tableHeader.resizeAndRepaint();
  2082. }
  2083. return;
  2084. }
  2085. if (e.getType() == TableModelEvent.INSERT) {
  2086. tableRowsInserted(e);
  2087. return;
  2088. }
  2089. if (e.getType() == TableModelEvent.DELETE) {
  2090. tableRowsDeleted(e);
  2091. return;
  2092. }
  2093. int modelColumn = e.getColumn();
  2094. int start = e.getFirstRow();
  2095. int end = e.getLastRow();
  2096. if (start == TableModelEvent.HEADER_ROW) {
  2097. start = 0;
  2098. end = Integer.MAX_VALUE;
  2099. }
  2100. int rowHeight = getRowHeight() + rowMargin;
  2101. Rectangle dirtyRegion;
  2102. if (modelColumn == TableModelEvent.ALL_COLUMNS) {
  2103. // 1 or more rows changed
  2104. dirtyRegion = new Rectangle(0, start * rowHeight,
  2105. getColumnModel().getTotalColumnWidth(), 0);
  2106. }
  2107. else {
  2108. // A cell or column of cells has changed.
  2109. // Unlike the rest of the methods in the JTable, the TableModelEvent
  2110. // uses the co-ordinate system of the model instead of the view.
  2111. // This is the only place in the JTable where this "reverse mapping"
  2112. // is used.
  2113. int column = convertColumnIndexToView(modelColumn);
  2114. dirtyRegion = getCellRect(start, column, false);
  2115. }
  2116. // Now adjust the height of the dirty region according to the value of "end".
  2117. // Check for Integer.MAX_VALUE as this will cause an overflow.
  2118. if (end != Integer.MAX_VALUE) {
  2119. dirtyRegion.height = (end-start+1)*rowHeight;
  2120. repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
  2121. }
  2122. // In fact, if the end is Integer.MAX_VALUE we need to revalidate anyway
  2123. // because the scrollbar may need repainting.
  2124. else {
  2125. resizeAndRepaint();
  2126. }
  2127. }
  2128. /*
  2129. * Invoked when rows have been inserted into the table.
  2130. *
  2131. * @param e the TableModelEvent encapsulating the insertion
  2132. */
  2133. private void tableRowsInserted(TableModelEvent e) {
  2134. int start = e.getFirstRow();
  2135. int end = e.getLastRow();
  2136. if (start < 0)
  2137. start = 0;
  2138. // 1 or more rows added, so we have to repaint from the first
  2139. // new row to the end of the table. (Everything shifts down)
  2140. int rowHeight = getRowHeight() + rowMargin;
  2141. Rectangle drawRect = new Rectangle(0, start * rowHeight,
  2142. getColumnModel().getTotalColumnWidth(),
  2143. (getRowCount()-start) * rowHeight);
  2144. // Adjust the selection to account for the new rows
  2145. if (selectionModel != null) {
  2146. if (end < 0)
  2147. end = getRowCount()-1;
  2148. int length = end - start + 1;
  2149. selectionModel.insertIndexInterval(start, length, true);
  2150. }
  2151. revalidate();
  2152. // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
  2153. // repaint still required in the unusual case where there is no ScrollPane
  2154. repaint(drawRect);
  2155. }
  2156. /*
  2157. * Invoked when rows have been removed from the table.
  2158. *
  2159. * @param e the TableModelEvent encapsulating the deletion
  2160. */
  2161. private void tableRowsDeleted(TableModelEvent e) {
  2162. int start = e.getFirstRow();
  2163. int end = e.getLastRow();
  2164. if (start < 0)
  2165. start = 0;
  2166. int deletedCount = end - start + 1;
  2167. int previousRowCount = getRowCount() + deletedCount;
  2168. // 1 or more rows added, so we have to repaint from the first
  2169. // new row to the end of the table. (Everything shifts up)
  2170. int rowHeight = getRowHeight() + rowMargin;
  2171. Rectangle drawRect = new Rectangle(0, start * rowHeight,
  2172. getColumnModel().getTotalColumnWidth(),
  2173. (previousRowCount - start) * rowHeight);
  2174. // Adjust the selection to account for the new rows
  2175. if (selectionModel != null) {
  2176. if (end < 0)
  2177. end = getRowCount()-1;
  2178. selectionModel.removeIndexInterval(start, end);
  2179. }
  2180. revalidate();
  2181. // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
  2182. // repaint still required in the unusual case where there is no ScrollPane
  2183. repaint(drawRect);
  2184. }
  2185. //
  2186. // Implementing TableColumnModelListener interface
  2187. //
  2188. /**
  2189. * Tells listeners that a column was added to the model.
  2190. *
  2191. * @see TableColumnModelListener
  2192. */
  2193. public void columnAdded(TableColumnModelEvent e) {
  2194. // If I'm currently editing, then I should stop editing
  2195. if (isEditing()) {
  2196. removeEditor();
  2197. }
  2198. resizeAndRepaint();
  2199. }
  2200. /**
  2201. * Tells listeners that a column was removed from the model.
  2202. *
  2203. * @see TableColumnModelListener
  2204. */
  2205. public void columnRemoved(TableColumnModelEvent e) {
  2206. // If I'm currently editing, then I should stop editing
  2207. if (isEditing()) {
  2208. removeEditor();
  2209. }
  2210. resizeAndRepaint();
  2211. }
  2212. /**
  2213. * Tells listeners that a column was repositioned.
  2214. *
  2215. * @see TableColumnModelListener
  2216. */
  2217. public void columnMoved(TableColumnModelEvent e) {
  2218. // If I'm currently editing, then I should stop editing
  2219. if (isEditing()) {
  2220. removeEditor();
  2221. }
  2222. repaint();
  2223. }
  2224. /**
  2225. * Tells listeners that a column was moved due to a margin change.
  2226. *
  2227. * @see TableColumnModelListener
  2228. */
  2229. public void columnMarginChanged(ChangeEvent e) {
  2230. // If I'm currently editing, then I should stop editing
  2231. if (isEditing()) {
  2232. removeEditor();
  2233. }
  2234. resizeAndRepaint();
  2235. }
  2236. /**
  2237. * Tells listeners that the selection model of the
  2238. * TableColumnModel changed.
  2239. *
  2240. * @see TableColumnModelListener
  2241. */
  2242. public void columnSelectionChanged(ListSelectionEvent e) {
  2243. int firstIndex = e.getFirstIndex();
  2244. int lastIndex = e.getLastIndex();
  2245. if (firstIndex == -1 && lastIndex == -1) { // Selection cleared.
  2246. repaint();
  2247. }
  2248. Rectangle firstColumnRect = getCellRect(0, firstIndex, false);
  2249. Rectangle lastColumnRect = getCellRect(getRowCount(), lastIndex, false);
  2250. Rectangle dirtyRegion = firstColumnRect.union(lastColumnRect);
  2251. // This marks this entire column as dirty but the painting system will
  2252. // intersect this with the clip rect of the viewport and redraw only
  2253. // the visible cells.
  2254. repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
  2255. }
  2256. //
  2257. // Implementing ListSelectionListener interface
  2258. //
  2259. /**
  2260. * Invoked when the selection changes -- repaints to show the new
  2261. * selection.
  2262. *
  2263. * @see ListSelectionListener
  2264. */
  2265. public void valueChanged(ListSelectionEvent e) {
  2266. int firstIndex = e.getFirstIndex();
  2267. int lastIndex = e.getLastIndex();
  2268. if (firstIndex == -1 && lastIndex == -1) { // Selection cleared.
  2269. repaint();
  2270. }
  2271. Rectangle firstRowRect = getCellRect(firstIndex, 0, false);
  2272. Rectangle lastRowRect = getCellRect(lastIndex, getColumnCount(), false);
  2273. Rectangle dirtyRegion = firstRowRect.union(lastRowRect);
  2274. // This marks this entire row as dirty but the painting system will
  2275. // intersect this with the clip rect of the viewport and redraw only
  2276. // the visible cells.
  2277. repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
  2278. }
  2279. //
  2280. // Implementing the CellEditorListener interface
  2281. //
  2282. /**
  2283. * Invoked when editing is finished. The changes are saved and the
  2284. * editor is discarded.
  2285. *
  2286. * @see CellEditorListener
  2287. */
  2288. public void editingStopped(ChangeEvent e) {
  2289. // Take in the new value
  2290. TableCellEditor editor = getCellEditor();
  2291. if (editor != null) {
  2292. Object value = editor.getCellEditorValue();
  2293. setValueAt(value, editingRow, editingColumn);
  2294. removeEditor();
  2295. }
  2296. }
  2297. /**
  2298. * Invoked when editing is canceled. The editor object is discarded
  2299. * and the cell is rendered once again.
  2300. *
  2301. * @see CellEditorListener
  2302. */
  2303. public void editingCanceled(ChangeEvent e) {
  2304. removeEditor();
  2305. }
  2306. //
  2307. // Implementing the Scrollable interface
  2308. //
  2309. /**
  2310. * Sets the preferred size of the viewport for this table.
  2311. *
  2312. * @param size a Dimension object specifying the preferredSize of a
  2313. * JViewport whose view is this table
  2314. * @see Scrollable#getPreferredScrollableViewportSize
  2315. * @beaninfo
  2316. * description: The preferred size of the viewport.
  2317. */
  2318. public void setPreferredScrollableViewportSize(Dimension size) {
  2319. preferredViewportSize = size;
  2320. }
  2321. /**
  2322. * Returns the preferred size of the viewport for this table.
  2323. *
  2324. * @return a Dimension object containing the preferredSize of the JViewport
  2325. * which displays this table
  2326. * @see Scrollable#getPreferredScrollableViewportSize
  2327. */
  2328. public Dimension getPreferredScrollableViewportSize() {
  2329. return preferredViewportSize;
  2330. }
  2331. /**
  2332. * Returns the scroll increment that completely exposes one new row
  2333. * or column (depending on the orientation).
  2334. * <p>
  2335. * This method is called each time the user requests a unit scroll.
  2336. *
  2337. * @param visibleRect The view area visible within the viewport
  2338. * @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
  2339. * @param direction Less than zero to scroll up/left, greater than zero for down/right.
  2340. * @return The "unit" increment for scrolling in the specified direction
  2341. * @see Scrollable#getScrollableUnitIncrement
  2342. */
  2343. public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
  2344. int direction) {
  2345. // PENDING(alan): do something smarter
  2346. if (orientation == SwingConstants.HORIZONTAL) {
  2347. return 100;
  2348. }
  2349. return rowHeight + rowMargin;
  2350. }
  2351. /**
  2352. * Returns The visibleRect.height or visibleRect.width, depending on the
  2353. * table's orientation.
  2354. *
  2355. * @return The visibleRect.height or visibleRect.width per the orientation.
  2356. * @see Scrollable#getScrollableBlockIncrement
  2357. */
  2358. public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation,
  2359. int direction) {
  2360. if (orientation == SwingConstants.VERTICAL) {
  2361. int rh = getRowHeight() + getRowMargin();
  2362. return (rh > 0) ? Math.max(rh, (visibleRect.height / rh) * rh) : visibleRect.height;
  2363. }
  2364. else {
  2365. return visibleRect.width;
  2366. }
  2367. }
  2368. /**
  2369. * Returns false to indicate that the width of the viewport does not
  2370. * determine the width of the table.
  2371. *
  2372. * @return false
  2373. * @see Scrollable#getScrollableTracksViewportWidth
  2374. */
  2375. public boolean getScrollableTracksViewportWidth() {
  2376. return !(autoResizeMode == AUTO_RESIZE_OFF);
  2377. }
  2378. /**
  2379. * Returns false to indicate that the height of the viewport does not
  2380. * determine the height of the table.
  2381. *
  2382. * @return false
  2383. * @see Scrollable#getScrollableTracksViewportHeight
  2384. */
  2385. public boolean getScrollableTracksViewportHeight() {
  2386. return false;
  2387. }
  2388. //
  2389. // Protected Methods
  2390. //
  2391. private class CheckBoxRenderer extends JCheckBox implements TableCellRenderer
  2392. {
  2393. public Component getTableCellRendererComponent(JTable table, Object value,
  2394. boolean isSelected, boolean hasFocus, int row, int column) {
  2395. if (isSelected) {
  2396. setForeground(table.getSelectionForeground());
  2397. super.setBackground(table.getSelectionBackground());
  2398. }
  2399. else {
  2400. setForeground(table.getForeground());
  2401. setBackground(table.getBackground());
  2402. }
  2403. setSelected((value != null && ((Boolean)value).booleanValue()));
  2404. return this;
  2405. }
  2406. }
  2407. protected void createDefaultRenderers() {
  2408. defaultRenderersByColumnClass = new Hashtable();
  2409. // Objects
  2410. DefaultTableCellRenderer label = new DefaultTableCellRenderer();
  2411. setDefaultRenderer(Object.class, label);
  2412. // Numbers
  2413. DefaultTableCellRenderer numberRenderer = new DefaultTableCellRenderer() {
  2414. NumberFormat formatter = NumberFormat.getInstance();
  2415. public void setValue(Object value) {
  2416. setText((value == null) ? "" : formatter.format(value));
  2417. }
  2418. };
  2419. numberRenderer.setHorizontalAlignment(JLabel.RIGHT);
  2420. setDefaultRenderer(Number.class, numberRenderer);
  2421. // Dates
  2422. DefaultTableCellRenderer dateRenderer = new DefaultTableCellRenderer() {
  2423. DateFormat formatter = DateFormat.getDateInstance();
  2424. public void setValue(Object value) {
  2425. setText((value == null) ? "" : formatter.format(value)); }
  2426. };
  2427. dateRenderer.setHorizontalAlignment(JLabel.RIGHT);
  2428. setDefaultRenderer(Date.class, dateRenderer);
  2429. // Icons
  2430. DefaultTableCellRenderer centeredLabel = new DefaultTableCellRenderer() {
  2431. public void setValue(Object value) { setIcon((Icon)value); }
  2432. };
  2433. centeredLabel.setHorizontalAlignment(JLabel.CENTER);
  2434. setDefaultRenderer(ImageIcon.class, centeredLabel);
  2435. // Booleans
  2436. /* DefaultTableCellRenderer booleanRenderer = new DefaultTableCellRenderer() {
  2437. Icon trueIcon = UIManager.getIcon("CheckBox.icon");
  2438. public void setValue(Object value) {
  2439. setIcon((value != null && ((Boolean)value).booleanValue()) ? trueIcon : null);
  2440. }
  2441. };
  2442. booleanRenderer.setHorizontalAlignment(JLabel.CENTER);
  2443. setDefaultRenderer(Boolean.class, booleanRenderer);
  2444. */
  2445. CheckBoxRenderer booleanRenderer = new CheckBoxRenderer();
  2446. booleanRenderer.setHorizontalAlignment(JLabel.CENTER);
  2447. setDefaultRenderer(Boolean.class, booleanRenderer);
  2448. }
  2449. /**
  2450. * Creates default cell editors for Objects, numbers, and boolean values.
  2451. */
  2452. protected void createDefaultEditors() {
  2453. defaultEditorsByColumnClass = new Hashtable();
  2454. // Objects
  2455. JTextField textField = new JTextField();
  2456. textField.setBorder(new LineBorder(Color.black));
  2457. setDefaultEditor(Object.class, new DefaultCellEditor(textField));
  2458. // Numbers
  2459. JTextField rightAlignedTextField = new JTextField();
  2460. rightAlignedTextField.setHorizontalAlignment(JTextField.RIGHT);
  2461. rightAlignedTextField.setBorder(new LineBorder(Color.black));
  2462. setDefaultEditor(Number.class, new DefaultCellEditor(rightAlignedTextField));
  2463. // Booleans
  2464. JCheckBox centeredCheckBox = new JCheckBox();
  2465. centeredCheckBox.setHorizontalAlignment(JCheckBox.CENTER);
  2466. setDefaultEditor(Boolean.class, new DefaultCellEditor(centeredCheckBox));
  2467. }
  2468. /**
  2469. * Initializes table properties to their default values.
  2470. */
  2471. protected void initializeLocalVars() {
  2472. getSelectionModel().setAnchorSelectionIndex(0);
  2473. columnModel.getSelectionModel().setAnchorSelectionIndex(0);
  2474. setOpaque(true);
  2475. createDefaultRenderers();
  2476. createDefaultEditors();
  2477. setTableHeader(createDefaultTableHeader());
  2478. setShowGrid(true);
  2479. setAutoResizeMode(AUTO_RESIZE_SUBSEQUENT_COLUMNS);
  2480. setRowHeight(16);
  2481. rowMargin = 1;
  2482. setRowSelectionAllowed(true);
  2483. setCellSelectionEnabled(false);
  2484. cellEditor = null;
  2485. editingColumn = editingRow = -1;
  2486. preferredViewportSize = new Dimension(450,400);
  2487. // I'm registered to do tool tips so we can draw tips for the renderers
  2488. ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
  2489. toolTipManager.registerComponent(this);
  2490. setAutoscrolls(true);
  2491. }
  2492. /**
  2493. * Returns the default table model object which is
  2494. * a DefaultTableModel. Subclass can override this
  2495. * method to return a different table model object.
  2496. *
  2497. * @return the default table model object
  2498. */
  2499. protected TableModel createDefaultDataModel() {
  2500. return new DefaultTableModel();
  2501. }
  2502. /**
  2503. * Returns the default column model object which is
  2504. * a DefaultTableColumnModel. Subclass can override this
  2505. * method to return a different column model object
  2506. *
  2507. * @return the default column model object
  2508. */
  2509. protected TableColumnModel createDefaultColumnModel() {
  2510. return new DefaultTableColumnModel();
  2511. }
  2512. /**
  2513. * Returns the default selection model object which is
  2514. * a DefaultListSelectionModel. Subclass can override this
  2515. * method to return a different selection model object.
  2516. *
  2517. * @return the default selection model object
  2518. */
  2519. protected ListSelectionModel createDefaultSelectionModel() {
  2520. return new DefaultListSelectionModel();
  2521. }
  2522. /**
  2523. * Returns the default table header object which is
  2524. * a JTableHeader. Subclass can override this
  2525. * method to return a different table header object
  2526. *
  2527. * @return the default table header object
  2528. */
  2529. protected JTableHeader createDefaultTableHeader() {
  2530. return new JTableHeader(columnModel);
  2531. }
  2532. /**
  2533. * Equivalent to revalidate() followed by repaint().
  2534. */
  2535. protected void resizeAndRepaint() {
  2536. revalidate();
  2537. repaint();
  2538. }
  2539. /**
  2540. * Return the cellEditor.
  2541. *
  2542. * @return the TableCellEditor that does the editing
  2543. * @see #cellEditor
  2544. */
  2545. public TableCellEditor getCellEditor() {
  2546. return cellEditor;
  2547. }
  2548. /**
  2549. * Set the cellEditor variable.
  2550. *
  2551. * @param anEditor the TableCellEditor that does the editing
  2552. * @see #cellEditor
  2553. */
  2554. public void setCellEditor(TableCellEditor anEditor) {
  2555. TableCellEditor oldEditor = cellEditor;
  2556. cellEditor = anEditor;
  2557. firePropertyChange("tableCellEditor", oldEditor, anEditor);
  2558. }
  2559. /**
  2560. * Set the editingColumn variable.
  2561. *
  2562. * @see #editingColumn
  2563. */
  2564. public void setEditingColumn(int aColumn) {
  2565. editingColumn = aColumn;
  2566. }
  2567. /**
  2568. * Set the editingRow variable.
  2569. *
  2570. * @see #editingRow
  2571. */
  2572. public void setEditingRow(int aRow) {
  2573. editingRow = aRow;
  2574. }
  2575. /**
  2576. * Return an appropriate renderer for the cell specified by this this row and
  2577. * column. If the TableColumn for this column has a non-null renderer, return that.
  2578. * If not, find the class of the data in this column (using getColumnClass())
  2579. * and return the default renderer for this type of data.
  2580. *
  2581. * @param row the row of the cell to render, where 0 is the first
  2582. * @param column the column of the cell to render, where 0 is the first
  2583. */
  2584. public TableCellRenderer getCellRenderer(int row, int column) {
  2585. TableColumn tableColumn = getColumnModel().getColumn(column);
  2586. TableCellRenderer renderer = tableColumn.getCellRenderer();
  2587. if (renderer == null) {
  2588. renderer = getDefaultRenderer(getColumnClass(column));
  2589. }
  2590. return renderer;
  2591. }
  2592. /**
  2593. * Prepares the specified renderer with an appropriate value
  2594. * from the dataModel, and an appropriate selection value from
  2595. * the selection models.
  2596. *
  2597. * @param renderer the TableCellRenderer to prepare
  2598. * @param row the row of the cell to render, where 0 is the first
  2599. * @param column the column of the cell to render, where 0 is the first
  2600. */
  2601. public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
  2602. Object value = getValueAt(row, column);
  2603. boolean isSelected = isCellSelected(row, column);
  2604. boolean rowIsAnchor = (selectionModel.getAnchorSelectionIndex() == row);
  2605. boolean colIsAnchor =
  2606. (columnModel.getSelectionModel().getAnchorSelectionIndex() == column);
  2607. boolean hasFocus = (rowIsAnchor && colIsAnchor) && hasFocus();
  2608. return renderer.getTableCellRendererComponent(this, value,
  2609. isSelected, hasFocus,
  2610. row, column);
  2611. }
  2612. /**
  2613. * Return an appropriate editor for the cell specified by this this row and
  2614. * column. If the TableColumn for this column has a non-null editor, return that.
  2615. * If not, find the class of the data in this column (using getColumnClass())
  2616. * and return the default editor for this type of data.
  2617. *
  2618. * @param row the row of the cell to edit, where 0 is the first
  2619. * @param column the column of the cell to edit, where 0 is the first
  2620. */
  2621. public TableCellEditor getCellEditor(int row, int column) {
  2622. TableColumn tableColumn = getColumnModel().getColumn(column);
  2623. TableCellEditor editor = tableColumn.getCellEditor();
  2624. if (editor == null) {
  2625. editor = getDefaultEditor(getColumnClass(column));
  2626. }
  2627. return editor;
  2628. }
  2629. /**
  2630. * Prepares the specified editor using the value at the specified cell.
  2631. *
  2632. * @param editor the TableCellEditor to set up
  2633. * @param row the row of the cell to edit, where 0 is the first
  2634. * @param column the column of the cell to edit, where 0 is the first
  2635. */
  2636. public Component prepareEditor(TableCellEditor editor, int row, int column) {
  2637. Object value = getValueAt(row, column);
  2638. boolean isSelected = isCellSelected(row, column);
  2639. Component comp = editor.getTableCellEditorComponent(this, value, isSelected,
  2640. row, column);
  2641. if (comp instanceof JComponent) {
  2642. ((JComponent)comp).setNextFocusableComponent(this);
  2643. }
  2644. return comp;
  2645. }
  2646. /**
  2647. * Discard the editor object and return the real estate it used to
  2648. * cell rendering.
  2649. */
  2650. public void removeEditor() {
  2651. TableCellEditor editor = getCellEditor();
  2652. if(editor != null) {
  2653. editor.removeCellEditorListener(this);
  2654. requestFocus();
  2655. remove(editorComp);
  2656. Rectangle cellRect = getCellRect(editingRow, editingColumn, false);
  2657. setCellEditor(null);
  2658. setEditingColumn(-1);
  2659. setEditingRow(-1);
  2660. editorComp = null;
  2661. repaint(cellRect);
  2662. }
  2663. }
  2664. //
  2665. // Serialization
  2666. //
  2667. private void readObject(ObjectInputStream s)
  2668. throws IOException, ClassNotFoundException
  2669. {
  2670. s.defaultReadObject();
  2671. if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  2672. ui.installUI(this);
  2673. }
  2674. createDefaultRenderers();
  2675. createDefaultEditors();
  2676. }
  2677. /**
  2678. * Returns a string representation of this JTable. This method
  2679. * is intended to be used only for debugging purposes, and the
  2680. * content and format of the returned string may vary between
  2681. * implementations. The returned string may be empty but may not
  2682. * be <code>null</code>.
  2683. *
  2684. * @return a string representation of this JTable.
  2685. */
  2686. protected String paramString() {
  2687. String gridColorString = (gridColor != null ?
  2688. gridColor.toString() : "");
  2689. String showHorizontalLinesString = (showHorizontalLines ?
  2690. "true" : "false");
  2691. String showVerticalLinesString = (showVerticalLines ?
  2692. "true" : "false");
  2693. String autoResizeModeString;
  2694. if (autoResizeMode == AUTO_RESIZE_OFF) {
  2695. autoResizeModeString = "AUTO_RESIZE_OFF";
  2696. } else if (autoResizeMode == AUTO_RESIZE_NEXT_COLUMN) {
  2697. autoResizeModeString = "AUTO_RESIZE_NEXT_COLUMN";
  2698. } else if (autoResizeMode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) {
  2699. autoResizeModeString = "AUTO_RESIZE_SUBSEQUENT_COLUMNS";
  2700. } else if (autoResizeMode == AUTO_RESIZE_LAST_COLUMN) {
  2701. autoResizeModeString = "AUTO_RESIZE_LAST_COLUMN";
  2702. } else if (autoResizeMode == AUTO_RESIZE_ALL_COLUMNS) {
  2703. autoResizeModeString = "AUTO_RESIZE_ALL_COLUMNS";
  2704. } else autoResizeModeString = "";
  2705. String autoCreateColumnsFromModelString = (autoCreateColumnsFromModel ?
  2706. "true" : "false");
  2707. String preferredViewportSizeString = (preferredViewportSize != null ?
  2708. preferredViewportSize.toString()
  2709. : "");
  2710. String rowSelectionAllowedString = (rowSelectionAllowed ?
  2711. "true" : "false");
  2712. String cellSelectionEnabledString = (cellSelectionEnabled ?
  2713. "true" : "false");
  2714. String selectionForegroundString = (selectionForeground != null ?
  2715. selectionForeground.toString() :
  2716. "");
  2717. String selectionBackgroundString = (selectionBackground != null ?
  2718. selectionBackground.toString() :
  2719. "");
  2720. return super.paramString() +
  2721. ",autoCreateColumnsFromModel=" + autoCreateColumnsFromModelString +
  2722. ",autoResizeMode=" + autoResizeModeString +
  2723. ",cellSelectionEnabled=" + cellSelectionEnabledString +
  2724. ",editingColumn=" + editingColumn +
  2725. ",editingRow=" + editingRow +
  2726. ",gridColor=" + gridColorString +
  2727. ",preferredViewportSize=" + preferredViewportSizeString +
  2728. ",rowHeight=" + rowHeight +
  2729. ",rowMargin=" + rowMargin +
  2730. ",rowSelectionAllowed=" + rowSelectionAllowedString +
  2731. ",selectionBackground=" + selectionBackgroundString +
  2732. ",selectionForeground=" + selectionForegroundString +
  2733. ",showHorizontalLines=" + showHorizontalLinesString +
  2734. ",showVerticalLines=" + showVerticalLinesString;
  2735. }
  2736. /**
  2737. * We override this method, whose implementation in JComponent
  2738. * returns false, to return true. This allows us to give a special
  2739. * meaning to TAB and SHIFT-TAB in the JTable.
  2740. */
  2741. public boolean isManagingFocus() {
  2742. return true;
  2743. }
  2744. /////////////////
  2745. // Accessibility support
  2746. ////////////////
  2747. /**
  2748. * Get the AccessibleContext associated with this JComponent
  2749. *
  2750. * @return the AccessibleContext of this JComponent
  2751. */
  2752. public AccessibleContext getAccessibleContext() {
  2753. if (accessibleContext == null) {
  2754. accessibleContext = new AccessibleJTable();
  2755. }
  2756. return accessibleContext;
  2757. }
  2758. //
  2759. // *** should also implement AccessibleSelction?
  2760. // *** and what's up with keyboard navigation/manipulation?
  2761. //
  2762. /**
  2763. * The class used to obtain the accessible role for this object.
  2764. * <p>
  2765. * <strong>Warning:</strong>
  2766. * Serialized objects of this class will not be compatible with
  2767. * future Swing releases. The current serialization support is appropriate
  2768. * for short term storage or RMI between applications running the same
  2769. * version of Swing. A future release of Swing will provide support for
  2770. * long term persistence.
  2771. */
  2772. protected class AccessibleJTable extends AccessibleJComponent
  2773. implements AccessibleSelection, ListSelectionListener, TableModelListener,
  2774. TableColumnModelListener, CellEditorListener, PropertyChangeListener {
  2775. int lastSelectedRow;
  2776. int lastSelectedCol;
  2777. AccessibleJTable() {
  2778. super();
  2779. JTable.this.addPropertyChangeListener(this);
  2780. JTable.this.getSelectionModel().addListSelectionListener(this);
  2781. TableColumnModel tcm = JTable.this.getColumnModel();
  2782. tcm.addColumnModelListener(this);
  2783. tcm.getSelectionModel().addListSelectionListener(this);
  2784. JTable.this.getModel().addTableModelListener(this);
  2785. lastSelectedRow = JTable.this.getSelectedRow();
  2786. lastSelectedCol = JTable.this.getSelectedColumn();
  2787. }
  2788. // Listeners to track model, etc. changes to as to re-place the other
  2789. // listeners
  2790. /**
  2791. * Track changes to selection model, column model, etc. so as to
  2792. * be able to re-place listeners on those in order to pass on
  2793. * information to the Accessibility PropertyChange mechanism
  2794. */
  2795. public void propertyChange(PropertyChangeEvent e) {
  2796. String name = e.getPropertyName();
  2797. Object oldValue = e.getOldValue();
  2798. Object newValue = e.getNewValue();
  2799. // re-set tableModel listeners
  2800. if (name.compareTo("model") == 0) {
  2801. if (oldValue != null && oldValue instanceof TableModel) {
  2802. ((TableModel) oldValue).removeTableModelListener(this);
  2803. }
  2804. if (newValue != null && newValue instanceof TableModel) {
  2805. ((TableModel) newValue).addTableModelListener(this);
  2806. }
  2807. // re-set selectionModel listeners
  2808. } else if (name.compareTo("selectionModel") == 0) {
  2809. Object source = e.getSource();
  2810. if (source == JTable.this) { // row selection model
  2811. if (oldValue != null &&
  2812. oldValue instanceof ListSelectionModel) {
  2813. ((ListSelectionModel) oldValue).removeListSelectionListener(this);
  2814. }
  2815. if (newValue != null &&
  2816. newValue instanceof ListSelectionModel) {
  2817. ((ListSelectionModel) newValue).addListSelectionListener(this);
  2818. }
  2819. } else if (source == JTable.this.getColumnModel()) {
  2820. if (oldValue != null &&
  2821. oldValue instanceof ListSelectionModel) {
  2822. ((ListSelectionModel) oldValue).removeListSelectionListener(this);
  2823. }
  2824. if (newValue != null &&
  2825. newValue instanceof ListSelectionModel) {
  2826. ((ListSelectionModel) newValue).addListSelectionListener(this);
  2827. }
  2828. } else {
  2829. // System.out.println("!!! Bug in source of selectionModel propertyChangeEvent");
  2830. }
  2831. // re-set columnModel listeners
  2832. // and column's selection property listener as well
  2833. } else if (name.compareTo("columnModel") == 0) {
  2834. if (oldValue != null && oldValue instanceof TableColumnModel) {
  2835. TableColumnModel tcm = (TableColumnModel) oldValue;
  2836. tcm.removeColumnModelListener(this);
  2837. tcm.getSelectionModel().removeListSelectionListener(this);
  2838. }
  2839. if (newValue != null && newValue instanceof TableColumnModel) {
  2840. TableColumnModel tcm = (TableColumnModel) oldValue;
  2841. tcm.addColumnModelListener(this);
  2842. tcm.getSelectionModel().addListSelectionListener(this);
  2843. }
  2844. // re-se cellEditor listeners
  2845. } else if (name.compareTo("tableCellEditor") == 0) {
  2846. if (oldValue != null && oldValue instanceof TableCellEditor) {
  2847. ((TableCellEditor) oldValue).removeCellEditorListener((CellEditorListener) this);
  2848. }
  2849. if (newValue != null && newValue instanceof TableCellEditor) {
  2850. ((TableCellEditor) newValue).addCellEditorListener((CellEditorListener) this);
  2851. }
  2852. }
  2853. }
  2854. // Listeners to echo changes to the AccessiblePropertyChange mechanism
  2855. /**
  2856. * Track changes to the table contents
  2857. */
  2858. public void tableChanged(TableModelEvent e) {
  2859. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  2860. null, null);
  2861. }
  2862. /**
  2863. * Track changes to the table contents (row insertions)
  2864. */
  2865. public void tableRowsInserted(TableModelEvent e) {
  2866. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  2867. null, null);
  2868. }
  2869. /**
  2870. * Track changes to the table contents (row deletions)
  2871. */
  2872. public void tableRowsDeleted(TableModelEvent e) {
  2873. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  2874. null, null);
  2875. }
  2876. /**
  2877. * Track changes to the table contents (column insertions)
  2878. */
  2879. public void columnAdded(TableColumnModelEvent e) {
  2880. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  2881. null, null);
  2882. }
  2883. /**
  2884. * Track changes to the table contents (column deletions)
  2885. */
  2886. public void columnRemoved(TableColumnModelEvent e) {
  2887. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  2888. null, null);
  2889. }
  2890. /**
  2891. * Track changes of a column repositioning.
  2892. *
  2893. * @see TableColumnModelListener
  2894. */
  2895. public void columnMoved(TableColumnModelEvent e) {
  2896. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  2897. null, null);
  2898. }
  2899. /**
  2900. * Track changes of a column moving due to margin changes.
  2901. *
  2902. * @see TableColumnModelListener
  2903. */
  2904. public void columnMarginChanged(ChangeEvent e) {
  2905. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  2906. null, null);
  2907. }
  2908. /**
  2909. * Track that the selection model of the TableColumnModel changed.
  2910. *
  2911. * @see TableColumnModelListener
  2912. */
  2913. public void columnSelectionChanged(ListSelectionEvent e) {
  2914. // we should now re-place our TableColumn listener
  2915. }
  2916. /**
  2917. * Track changes to a cell's contents.
  2918. *
  2919. * Invoked when editing is finished. The changes are saved, the
  2920. * editor object is discarded, and the cell is rendered once again.
  2921. *
  2922. * @see CellEditorListener
  2923. */
  2924. public void editingStopped(ChangeEvent e) {
  2925. // it'd be great if we could figure out which cell, and pass that
  2926. // somehow as a parameter
  2927. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  2928. null, null);
  2929. }
  2930. /**
  2931. * Invoked when editing is canceled. The editor object is discarded
  2932. * and the cell is rendered once again.
  2933. *
  2934. * @see CellEditorListener
  2935. */
  2936. public void editingCanceled(ChangeEvent e) {
  2937. // nothing to report, 'cause nothing changed
  2938. }
  2939. /**
  2940. * Track changes to table cell selections
  2941. */
  2942. public void valueChanged(ListSelectionEvent e) {
  2943. firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
  2944. new Boolean(false), new Boolean(true));
  2945. int selectedRow = JTable.this.getSelectedRow();
  2946. int selectedCol = JTable.this.getSelectedColumn();
  2947. if (selectedRow != lastSelectedRow ||
  2948. selectedCol != lastSelectedCol) {
  2949. Accessible oldA = getAccessibleAt(lastSelectedRow,
  2950. lastSelectedCol);
  2951. Accessible newA = getAccessibleAt(selectedRow, selectedCol);
  2952. firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
  2953. oldA, newA);
  2954. lastSelectedRow = selectedRow;
  2955. lastSelectedCol = selectedCol;
  2956. }
  2957. }
  2958. // AccessibleContext support
  2959. /**
  2960. * Get the AccessibleSelection associated with this object if one
  2961. * exists. Otherwise return null.
  2962. *
  2963. * @return the AccessibleSelection, or null
  2964. */
  2965. public AccessibleSelection getAccessibleSelection() {
  2966. return this;
  2967. }
  2968. /**
  2969. * Get the role of this object.
  2970. *
  2971. * @return an instance of AccessibleRole describing the role of the
  2972. * object
  2973. * @see AccessibleRole
  2974. */
  2975. public AccessibleRole getAccessibleRole() {
  2976. return AccessibleRole.TABLE;
  2977. }
  2978. /**
  2979. * Returns the Accessible child, if one exists, contained at the local
  2980. * coordinate Point.
  2981. *
  2982. * @param p The point defining the top-left corner of the Accessible,
  2983. * given in the coordinate space of the object's parent.
  2984. * @return the Accessible, if it exists, at the specified location;
  2985. * else null
  2986. */
  2987. public Accessible getAccessibleAt(Point p) {
  2988. int column = columnAtPoint(p);
  2989. int row = rowAtPoint(p);
  2990. if ((column != -1) && (row != -1)) {
  2991. TableColumn aColumn = getColumnModel().getColumn(column);
  2992. TableCellRenderer renderer = aColumn.getCellRenderer();
  2993. if (renderer == null) {
  2994. Class columnClass = getColumnClass(column);
  2995. renderer = getDefaultRenderer(columnClass);
  2996. }
  2997. Component component = renderer.getTableCellRendererComponent(
  2998. JTable.this, null, false, false,
  2999. row, column);
  3000. return new AccessibleJTableCell(JTable.this, row, column,
  3001. getAccessibleIndexAt(row, column));
  3002. }
  3003. return null;
  3004. }
  3005. /**
  3006. * Returns the number of accessible children in the object. If all
  3007. * of the children of this object implement Accessible, than this
  3008. * method should return the number of children of this object.
  3009. *
  3010. * @return the number of accessible children in the object.
  3011. */
  3012. public int getAccessibleChildrenCount() {
  3013. return (JTable.this.getColumnCount() * JTable.this.getRowCount());
  3014. }
  3015. /**
  3016. * Return the nth Accessible child of the object.
  3017. *
  3018. * @param i zero-based index of child
  3019. * @return the nth Accessible child of the object
  3020. */
  3021. public Accessible getAccessibleChild(int i) {
  3022. if (i < 0 || i >= getAccessibleChildrenCount()) {
  3023. return null;
  3024. } else {
  3025. // children increase across, and then down, for tables
  3026. // (arbitrary decision)
  3027. int column = getAccessibleColumnAtIndex(i);
  3028. int row = getAccessibleRowAtIndex(i);
  3029. TableColumn aColumn = getColumnModel().getColumn(column);
  3030. TableCellRenderer renderer = aColumn.getCellRenderer();
  3031. if (renderer == null) {
  3032. Class columnClass = getColumnClass(column);
  3033. renderer = getDefaultRenderer(columnClass);
  3034. }
  3035. Component component = renderer.getTableCellRendererComponent(
  3036. JTable.this, null, false, false,
  3037. row, column);
  3038. return new AccessibleJTableCell(JTable.this, row, column,
  3039. getAccessibleIndexAt(row, column));
  3040. }
  3041. }
  3042. // AccessibleSelection support
  3043. /**
  3044. * Returns the number of Accessible children currently selected.
  3045. * If no children are selected, the return value will be 0.
  3046. *
  3047. * @return the number of items currently selected.
  3048. */
  3049. public int getAccessibleSelectionCount() {
  3050. int rowsSel = JTable.this.getSelectedRowCount();
  3051. int colsSel = JTable.this.getSelectedColumnCount();
  3052. if (JTable.this.cellSelectionEnabled) { // a contiguous block
  3053. return rowsSel * colsSel;
  3054. } else {
  3055. // a column swath and a row swath, with a shared block
  3056. if (JTable.this.getRowSelectionAllowed() &&
  3057. JTable.this.getColumnSelectionAllowed()) {
  3058. return rowsSel * JTable.this.getColumnCount() +
  3059. colsSel * JTable.this.getRowCount() -
  3060. rowsSel * colsSel;
  3061. // just one or more rows in selection
  3062. } else if (JTable.this.getRowSelectionAllowed()) {
  3063. return rowsSel * JTable.this.getColumnCount();
  3064. // just one or more rows in selection
  3065. } else if (JTable.this.getColumnSelectionAllowed()) {
  3066. return colsSel * JTable.this.getRowCount();
  3067. } else {
  3068. return 0; // JTable doesn't allow selections
  3069. }
  3070. }
  3071. }
  3072. /**
  3073. * Returns an Accessible representing the specified selected child
  3074. * in the object. If there isn't a selection, or there are
  3075. * fewer children selected than the integer passed in, the return
  3076. * value will be null.
  3077. * <p>Note that the index represents the i-th selected child, which
  3078. * is different from the i-th child.
  3079. *
  3080. * @param i the zero-based index of selected children
  3081. * @return the i-th selected child
  3082. * @see #getAccessibleSelectionCount
  3083. */
  3084. public Accessible getAccessibleSelection(int i) {
  3085. if (i < 0 || i > getAccessibleSelectionCount()) {
  3086. return (Accessible) null;
  3087. }
  3088. int rowsSel = JTable.this.getSelectedRowCount();
  3089. int colsSel = JTable.this.getSelectedColumnCount();
  3090. int rowIndicies[] = getSelectedRows();
  3091. int colIndicies[] = getSelectedColumns();
  3092. int ttlCols = JTable.this.getColumnCount();
  3093. int ttlRows = JTable.this.getRowCount();
  3094. int r;
  3095. int c;
  3096. if (JTable.this.cellSelectionEnabled) { // a contiguous block
  3097. r = rowIndicies[i / colsSel];
  3098. c = colIndicies[i % colsSel];
  3099. return getAccessibleChild((r * ttlCols) + c);
  3100. } else {
  3101. // a column swath and a row swath, with a shared block
  3102. if (JTable.this.getRowSelectionAllowed() &&
  3103. JTable.this.getColumnSelectionAllowed()) {
  3104. // Situation:
  3105. // We have a table, like the 6x3 table below,
  3106. // wherein three colums and one row selected
  3107. // (selected cells marked with "*", unselected "0"):
  3108. //
  3109. // 0 * 0 * * 0
  3110. // * * * * * *
  3111. // 0 * 0 * * 0
  3112. //
  3113. // State machine below walks through the array of
  3114. // selected rows in two states: in a selected row,
  3115. // and not in one; continuing until we are in a row
  3116. // in which the ith selection exists. Then we return
  3117. // the appropriate cell. In the state machine, we
  3118. // always do rows above the "current" selected row first,
  3119. // then the cells in the selected row. If we're done
  3120. // with the state machine before finding the requested
  3121. // selected child, we handle the rows below the last
  3122. // selected row at the end.
  3123. //
  3124. int curIndex = i;
  3125. final int IN_ROW = 0;
  3126. final int NOT_IN_ROW = 1;
  3127. int state = (rowIndicies[0] == 0 ? IN_ROW : NOT_IN_ROW);
  3128. int j = 0;
  3129. int prevRow = -1;
  3130. while (j < rowIndicies.length) {
  3131. switch (state) {
  3132. case IN_ROW: // on individual row full of selections
  3133. if (curIndex < ttlCols) { // it's here!
  3134. c = curIndex % ttlCols;
  3135. r = rowIndicies[j];
  3136. return getAccessibleChild((r * ttlCols) + c);
  3137. } else { // not here
  3138. curIndex -= ttlCols;
  3139. }
  3140. // is the next row in table selected or not?
  3141. if (j + 1 == rowIndicies.length ||
  3142. rowIndicies[j] != rowIndicies[j+1] - 1) {
  3143. state = NOT_IN_ROW;
  3144. prevRow = rowIndicies[j];
  3145. }
  3146. j++; // we didn't return earlier, so go to next row
  3147. break;
  3148. case NOT_IN_ROW: // sparse bunch of rows of selections
  3149. if (curIndex <
  3150. (colsSel * (rowIndicies[j] -
  3151. (prevRow == -1 ? 0 : (prevRow + 1))))) {
  3152. // it's here!
  3153. c = colIndicies[curIndex % colsSel];
  3154. r = (j > 0 ? rowIndicies[j-1] + 1 : 0)
  3155. + curIndex / colsSel;
  3156. return getAccessibleChild((r * ttlCols) + c);
  3157. } else { // not here
  3158. curIndex -= colsSel * (rowIndicies[j] -
  3159. (prevRow == -1 ? 0 : (prevRow + 1)));
  3160. }
  3161. state = IN_ROW;
  3162. break;
  3163. }
  3164. }
  3165. // we got here, so we didn't find it yet; find it in
  3166. // the last sparse bunch of rows
  3167. if (curIndex <
  3168. (colsSel * (ttlRows -
  3169. (prevRow == -1 ? 0 : (prevRow + 1))))) { // it's here!
  3170. c = colIndicies[curIndex % colsSel];
  3171. r = rowIndicies[j-1] + curIndex / colsSel + 1;
  3172. return getAccessibleChild((r * ttlCols) + c);
  3173. } else { // not here
  3174. // we shouldn't get to this spot in the code!
  3175. // System.out.println("Bug in AccessibleJTable.getAccessibleSelection()");
  3176. }
  3177. // one or more rows selected
  3178. } else if (JTable.this.getRowSelectionAllowed()) {
  3179. c = i % ttlCols;
  3180. r = rowIndicies[i / ttlCols];
  3181. return getAccessibleChild((r * ttlCols) + c);
  3182. // one or more columns selected
  3183. } else if (JTable.this.getColumnSelectionAllowed()) {
  3184. c = colIndicies[i % colsSel];
  3185. r = i / colsSel;
  3186. return getAccessibleChild((r * ttlCols) + c);
  3187. }
  3188. }
  3189. return (Accessible) null;
  3190. }
  3191. /**
  3192. * Determines if the current child of this object is selected.
  3193. *
  3194. * @return true if the current child of this object is selected
  3195. * @param i the zero-based index of the child in this Accessible object.
  3196. * @see AccessibleContext#getAccessibleChild
  3197. */
  3198. public boolean isAccessibleChildSelected(int i) {
  3199. int column = getAccessibleColumnAtIndex(i);
  3200. int row = getAccessibleRowAtIndex(i);
  3201. return JTable.this.isCellSelected(row, column);
  3202. }
  3203. /**
  3204. * Adds the specified Accessible child of the object to the object's
  3205. * selection. If the object supports multiple selections,
  3206. * the specified child is added to any existing selection, otherwise
  3207. * it replaces any existing selection in the object. If the
  3208. * specified child is already selected, this method has no effect.
  3209. *
  3210. * This method only works on JTables which have individual cell
  3211. * selection enabled.
  3212. *
  3213. * @param i the zero-based index of the child
  3214. * @see AccessibleContext#getAccessibleChild
  3215. */
  3216. public void addAccessibleSelection(int i) {
  3217. if (JTable.this.cellSelectionEnabled) {
  3218. int column = getAccessibleColumnAtIndex(i);
  3219. int row = getAccessibleRowAtIndex(i);
  3220. JTable.this.addRowSelectionInterval(row, row);
  3221. JTable.this.addColumnSelectionInterval(column, column);
  3222. }
  3223. }
  3224. /**
  3225. * Removes the specified child of the object from the object's
  3226. * selection. If the specified item isn't currently selected, this
  3227. * method has no effect.
  3228. *
  3229. * This method only works on JTables which have individual cell
  3230. * selection enabled.
  3231. *
  3232. * @param i the zero-based index of the child
  3233. * @see AccessibleContext#getAccessibleChild
  3234. */
  3235. public void removeAccessibleSelection(int i) {
  3236. if (JTable.this.cellSelectionEnabled) {
  3237. int column = getAccessibleColumnAtIndex(i);
  3238. int row = getAccessibleRowAtIndex(i);
  3239. JTable.this.removeRowSelectionInterval(row, row);
  3240. JTable.this.removeColumnSelectionInterval(column, column);
  3241. }
  3242. }
  3243. /**
  3244. * Clears the selection in the object, so that no children in the
  3245. * object are selected.
  3246. */
  3247. public void clearAccessibleSelection() {
  3248. JTable.this.clearSelection();
  3249. }
  3250. /**
  3251. * Causes every child of the object to be selected, but only
  3252. * if the JTable supports multiple selections, and if individual
  3253. * cell selection is enabled.
  3254. */
  3255. public void selectAllAccessibleSelection() {
  3256. if (JTable.this.cellSelectionEnabled) {
  3257. JTable.this.selectAll();
  3258. }
  3259. }
  3260. // /**
  3261. // * Get the AccessibleTable associated with this object if one
  3262. // * exists. Otherwise return null.
  3263. // */
  3264. // public AccessibleTable getAccessibleTable() {
  3265. // return this;
  3266. // }
  3267. // AccessibleTable methods
  3268. /*
  3269. * Returns the total number of rows in the table
  3270. *
  3271. * @return the total number of rows in the table
  3272. */
  3273. private int getAccessibleRowCount() {
  3274. return JTable.this.getRowCount();
  3275. }
  3276. /*
  3277. * Returns the total number of columns in the table
  3278. *
  3279. * @return the total number of columns in the table
  3280. */
  3281. private int getAccessibleColumnCount() {
  3282. return JTable.this.getColumnCount();
  3283. }
  3284. /*
  3285. * Returns the row at a given index into the table
  3286. *
  3287. * @param i zero-based index into the table
  3288. * @return the row at a given index
  3289. */
  3290. private int getAccessibleRowAtIndex(int i) {
  3291. return (i / getAccessibleColumnCount());
  3292. }
  3293. /*
  3294. * Returns the column at a given index into the table
  3295. *
  3296. * @param i zero-based index into the table
  3297. * @return the column at a given index
  3298. */
  3299. private int getAccessibleColumnAtIndex(int i) {
  3300. return (i % getAccessibleColumnCount());
  3301. }
  3302. /*
  3303. * Returns the index at a given (row, column) in the table
  3304. *
  3305. * @param r zero-based row of the table
  3306. * @param c zero-based column of the table
  3307. * @return the index into the table
  3308. */
  3309. private int getAccessibleIndexAt(int r, int c) {
  3310. return ((r * getAccessibleColumnCount()) + c);
  3311. }
  3312. /*
  3313. * Returns the Accessible at a given (row, column) in the table
  3314. *
  3315. * @param r zero-based row of the table
  3316. * @param c zero-based column of the table
  3317. * @return the Accessible at the specified (row, column)
  3318. */
  3319. private Accessible getAccessibleAt(int r, int c) {
  3320. return getAccessibleChild((r * getAccessibleColumnCount()) + c);
  3321. }
  3322. /*
  3323. * Return the Accessible representing the row header, if
  3324. * there is one (may be null).
  3325. *
  3326. * @param row zero-based row of the table
  3327. * @return the Accessible header of the row
  3328. */
  3329. private Accessible getAccessibleRowHeader(int row) {
  3330. return null;
  3331. }
  3332. /*
  3333. * Return the Accessible representing the column header, if
  3334. * there is one (may be null)
  3335. *
  3336. * @param column zero-based column of the table
  3337. * @return the Accessible header of the column
  3338. */
  3339. private Accessible getAccessibleColumnHeader(int column) {
  3340. JTableHeader header = JTable.this.getTableHeader();
  3341. AccessibleContext ac = header.getAccessibleContext();
  3342. if (ac != null) {
  3343. return ac.getAccessibleChild(column);
  3344. } else {
  3345. return null;
  3346. }
  3347. }
  3348. /**
  3349. * The class used to obtain the AccessibleRole for a cell.
  3350. */
  3351. protected class AccessibleJTableCell extends AccessibleContext
  3352. implements Accessible, AccessibleComponent {
  3353. private JTable parent;
  3354. private int row;
  3355. private int column;
  3356. private int index;
  3357. /**
  3358. * Constructs an AccessiblJTableHeaaderEntry
  3359. */
  3360. public AccessibleJTableCell(JTable t, int r, int c, int i) {
  3361. parent = t;
  3362. row = r;
  3363. column = c;
  3364. index = i;
  3365. this.setAccessibleParent(parent);
  3366. }
  3367. /**
  3368. * Get the AccessibleContext associated with this
  3369. *
  3370. * @return the AccessibleContext of this JComponent
  3371. */
  3372. public AccessibleContext getAccessibleContext() {
  3373. return this;
  3374. }
  3375. private AccessibleContext getCurrentAccessibleContext() {
  3376. TableColumn aColumn = getColumnModel().getColumn(column);
  3377. TableCellRenderer renderer = aColumn.getCellRenderer();
  3378. if (renderer == null) {
  3379. Class columnClass = getColumnClass(column);
  3380. renderer = getDefaultRenderer(columnClass);
  3381. }
  3382. Component component = renderer.getTableCellRendererComponent(
  3383. JTable.this, getValueAt(row, column),
  3384. false, false, row, column);
  3385. if (component instanceof Accessible) {
  3386. return ((Accessible) component).getAccessibleContext();
  3387. } else {
  3388. return null;
  3389. }
  3390. }
  3391. private Component getCurrentComponent() {
  3392. TableColumn aColumn = getColumnModel().getColumn(column);
  3393. TableCellRenderer renderer = aColumn.getCellRenderer();
  3394. if (renderer == null) {
  3395. Class columnClass = getColumnClass(column);
  3396. renderer = getDefaultRenderer(columnClass);
  3397. }
  3398. return renderer.getTableCellRendererComponent(
  3399. JTable.this, null, false, false,
  3400. row, column);
  3401. }
  3402. // AccessibleContext methods
  3403. /**
  3404. * Get the accessible name of this object.
  3405. *
  3406. * @return the localized name of the object; null if this
  3407. * object does not have a name
  3408. */
  3409. public String getAccessibleName() {
  3410. AccessibleContext ac = getCurrentAccessibleContext();
  3411. if (ac != null) {
  3412. String name = ac.getAccessibleName();
  3413. if ((name != null) && (name != "")) {
  3414. return ac.getAccessibleName();
  3415. }
  3416. }
  3417. if ((accessibleName != null) && (accessibleName != "")) {
  3418. return accessibleName;
  3419. } else {
  3420. return parent.getValueAt(row, column).toString();
  3421. }
  3422. }
  3423. /**
  3424. * Set the localized accessible name of this object.
  3425. *
  3426. * @param s the new localized name of the object.
  3427. */
  3428. public void setAccessibleName(String s) {
  3429. AccessibleContext ac = getCurrentAccessibleContext();
  3430. if (ac != null) {
  3431. ac.setAccessibleName(s);
  3432. } else {
  3433. super.setAccessibleName(s);
  3434. }
  3435. }
  3436. //
  3437. // *** should check toolip text for desc. (needs MouseEvent)
  3438. //
  3439. /**
  3440. * Get the accessible description of this object.
  3441. *
  3442. * @return the localized description of the object; null if
  3443. * this object does not have a description
  3444. */
  3445. public String getAccessibleDescription() {
  3446. AccessibleContext ac = getCurrentAccessibleContext();
  3447. if (ac != null) {
  3448. return ac.getAccessibleDescription();
  3449. } else {
  3450. return super.getAccessibleDescription();
  3451. }
  3452. }
  3453. /**
  3454. * Set the accessible description of this object.
  3455. *
  3456. * @param s the new localized description of the object
  3457. */
  3458. public void setAccessibleDescription(String s) {
  3459. AccessibleContext ac = getCurrentAccessibleContext();
  3460. if (ac != null) {
  3461. ac.setAccessibleDescription(s);
  3462. } else {
  3463. super.setAccessibleDescription(s);
  3464. }
  3465. }
  3466. /**
  3467. * Get the role of this object.
  3468. *
  3469. * @return an instance of AccessibleRole describing the role of the object
  3470. * @see AccessibleRole
  3471. */
  3472. public AccessibleRole getAccessibleRole() {
  3473. AccessibleContext ac = getCurrentAccessibleContext();
  3474. if (ac != null) {
  3475. return ac.getAccessibleRole();
  3476. } else {
  3477. return AccessibleRole.UNKNOWN;
  3478. }
  3479. }
  3480. /**
  3481. * Get the state set of this object.
  3482. *
  3483. * @return an instance of AccessibleStateSet containing the
  3484. * current state set of the object
  3485. * @see AccessibleState
  3486. */
  3487. public AccessibleStateSet getAccessibleStateSet() {
  3488. AccessibleContext ac = getCurrentAccessibleContext();
  3489. AccessibleStateSet as = null;
  3490. if (ac != null) {
  3491. as = ac.getAccessibleStateSet();
  3492. }
  3493. if (as == null) {
  3494. as = new AccessibleStateSet();
  3495. }
  3496. Rectangle rjt = JTable.this.getVisibleRect();
  3497. Rectangle rcell = JTable.this.getCellRect(row, column, false);
  3498. if (rjt.intersects(rcell)) {
  3499. as.add(AccessibleState.SHOWING);
  3500. } else {
  3501. if (as.contains(AccessibleState.SHOWING)) {
  3502. as.remove(AccessibleState.SHOWING);
  3503. }
  3504. }
  3505. if (parent.isCellSelected(row, column)) {
  3506. as.add(AccessibleState.SELECTED);
  3507. } else if (as.contains(AccessibleState.SELECTED)) {
  3508. as.remove(AccessibleState.SELECTED);
  3509. }
  3510. if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
  3511. as.add(AccessibleState.ACTIVE);
  3512. }
  3513. as.add(AccessibleState.TRANSIENT);
  3514. return as;
  3515. }
  3516. /**
  3517. * Get the Accessible parent of this object.
  3518. *
  3519. * @return the Accessible parent of this object; null if this
  3520. * object does not have an Accessible parent
  3521. */
  3522. public Accessible getAccessibleParent() {
  3523. return parent;
  3524. }
  3525. /**
  3526. * Get the index of this object in its accessible parent.
  3527. *
  3528. * @return the index of this object in its parent; -1 if this
  3529. * object does not have an accessible parent.
  3530. * @see #getAccessibleParent
  3531. */
  3532. public int getAccessibleIndexInParent() {
  3533. return index;
  3534. }
  3535. /**
  3536. * Returns the number of accessible children in the object.
  3537. *
  3538. * @return the number of accessible children in the object.
  3539. */
  3540. public int getAccessibleChildrenCount() {
  3541. AccessibleContext ac = getCurrentAccessibleContext();
  3542. if (ac != null) {
  3543. return ac.getAccessibleChildrenCount();
  3544. } else {
  3545. return 0;
  3546. }
  3547. }
  3548. /**
  3549. * Return the specified Accessible child of the object.
  3550. *
  3551. * @param i zero-based index of child
  3552. * @return the Accessible child of the object
  3553. */
  3554. public Accessible getAccessibleChild(int i) {
  3555. AccessibleContext ac = getCurrentAccessibleContext();
  3556. if (ac != null) {
  3557. Accessible accessibleChild = ac.getAccessibleChild(i);
  3558. ac.setAccessibleParent(this);
  3559. return accessibleChild;
  3560. } else {
  3561. return null;
  3562. }
  3563. }
  3564. /**
  3565. * Gets the locale of the component. If the component does not have a
  3566. * locale, then the locale of its parent is returned.
  3567. *
  3568. * @return This component's locale. If this component does not have a locale, the locale of its parent is returned.
  3569. * @exception IllegalComponentStateException
  3570. * If the Component does not have its own locale and has not yet been added to a containment hierarchy such that the locale can be
  3571. * determined from the containing parent.
  3572. * @see #setLocale
  3573. */
  3574. public Locale getLocale() {
  3575. AccessibleContext ac = getCurrentAccessibleContext();
  3576. if (ac != null) {
  3577. return ac.getLocale();
  3578. } else {
  3579. return null;
  3580. }
  3581. }
  3582. /**
  3583. * Add a PropertyChangeListener to the listener list.
  3584. * The listener is registered for all properties.
  3585. *
  3586. * @param listener The PropertyChangeListener to be added
  3587. */
  3588. public void addPropertyChangeListener(PropertyChangeListener l) {
  3589. AccessibleContext ac = getCurrentAccessibleContext();
  3590. if (ac != null) {
  3591. ac.addPropertyChangeListener(l);
  3592. } else {
  3593. super.addPropertyChangeListener(l);
  3594. }
  3595. }
  3596. /**
  3597. * Remove a PropertyChangeListener from the listener list.
  3598. * This removes a PropertyChangeListener that was registered
  3599. * for all properties.
  3600. *
  3601. * @param listener The PropertyChangeListener to be removed
  3602. */
  3603. public void removePropertyChangeListener(PropertyChangeListener l) {
  3604. AccessibleContext ac = getCurrentAccessibleContext();
  3605. if (ac != null) {
  3606. ac.removePropertyChangeListener(l);
  3607. } else {
  3608. super.removePropertyChangeListener(l);
  3609. }
  3610. }
  3611. /**
  3612. * Get the AccessibleAction associated with this object if one
  3613. * exists. Otherwise return null.
  3614. *
  3615. * @return the AccessibleAction, or null
  3616. */
  3617. public AccessibleAction getAccessibleAction() {
  3618. return getCurrentAccessibleContext().getAccessibleAction();
  3619. }
  3620. /**
  3621. * Get the AccessibleComponent associated with this object if one
  3622. * exists. Otherwise return null.
  3623. *
  3624. * @return the AccessibleComponent, or null
  3625. */
  3626. public AccessibleComponent getAccessibleComponent() {
  3627. return this; // to override getBounds()
  3628. }
  3629. /**
  3630. * Get the AccessibleSelection associated with this object if one
  3631. * exists. Otherwise return null.
  3632. *
  3633. * @return the AccessibleSelection, or null
  3634. */
  3635. public AccessibleSelection getAccessibleSelection() {
  3636. return getCurrentAccessibleContext().getAccessibleSelection();
  3637. }
  3638. /**
  3639. * Get the AccessibleText associated with this object if one
  3640. * exists. Otherwise return null.
  3641. *
  3642. * @return the AccessibleText, or null
  3643. */
  3644. public AccessibleText getAccessibleText() {
  3645. return getCurrentAccessibleContext().getAccessibleText();
  3646. }
  3647. /**
  3648. * Get the AccessibleValue associated with this object if one
  3649. * exists. Otherwise return null.
  3650. *
  3651. * @return the AccessibleValue, or null
  3652. */
  3653. public AccessibleValue getAccessibleValue() {
  3654. return getCurrentAccessibleContext().getAccessibleValue();
  3655. }
  3656. // AccessibleComponent methods
  3657. /**
  3658. * Get the background color of this object.
  3659. *
  3660. * @return the background color, if supported, of the object;
  3661. * otherwise, null
  3662. */
  3663. public Color getBackground() {
  3664. AccessibleContext ac = getCurrentAccessibleContext();
  3665. if (ac instanceof AccessibleComponent) {
  3666. return ((AccessibleComponent) ac).getBackground();
  3667. } else {
  3668. Component c = getCurrentComponent();
  3669. if (c != null) {
  3670. return c.getBackground();
  3671. } else {
  3672. return null;
  3673. }
  3674. }
  3675. }
  3676. /**
  3677. * Set the background color of this object.
  3678. *
  3679. * @param c the new Color for the background
  3680. */
  3681. public void setBackground(Color c) {
  3682. AccessibleContext ac = getCurrentAccessibleContext();
  3683. if (ac instanceof AccessibleComponent) {
  3684. ((AccessibleComponent) ac).setBackground(c);
  3685. } else {
  3686. Component cp = getCurrentComponent();
  3687. if (cp != null) {
  3688. cp.setBackground(c);
  3689. }
  3690. }
  3691. }
  3692. /**
  3693. * Get the foreground color of this object.
  3694. *
  3695. * @return the foreground color, if supported, of the object;
  3696. * otherwise, null
  3697. */
  3698. public Color getForeground() {
  3699. AccessibleContext ac = getCurrentAccessibleContext();
  3700. if (ac instanceof AccessibleComponent) {
  3701. return ((AccessibleComponent) ac).getForeground();
  3702. } else {
  3703. Component c = getCurrentComponent();
  3704. if (c != null) {
  3705. return c.getForeground();
  3706. } else {
  3707. return null;
  3708. }
  3709. }
  3710. }
  3711. /**
  3712. * Set the foreground color of this object.
  3713. *
  3714. * @param c the new Color for the foreground
  3715. */
  3716. public void setForeground(Color c) {
  3717. AccessibleContext ac = getCurrentAccessibleContext();
  3718. if (ac instanceof AccessibleComponent) {
  3719. ((AccessibleComponent) ac).setForeground(c);
  3720. } else {
  3721. Component cp = getCurrentComponent();
  3722. if (cp != null) {
  3723. cp.setForeground(c);
  3724. }
  3725. }
  3726. }
  3727. /**
  3728. * Get the Cursor of this object.
  3729. *
  3730. * @return the Cursor, if supported, of the object; otherwise, null
  3731. */
  3732. public Cursor getCursor() {
  3733. AccessibleContext ac = getCurrentAccessibleContext();
  3734. if (ac instanceof AccessibleComponent) {
  3735. return ((AccessibleComponent) ac).getCursor();
  3736. } else {
  3737. Component c = getCurrentComponent();
  3738. if (c != null) {
  3739. return c.getCursor();
  3740. } else {
  3741. Accessible ap = getAccessibleParent();
  3742. if (ap instanceof AccessibleComponent) {
  3743. return ((AccessibleComponent) ap).getCursor();
  3744. } else {
  3745. return null;
  3746. }
  3747. }
  3748. }
  3749. }
  3750. /**
  3751. * Set the Cursor of this object.
  3752. *
  3753. * @param c the new Cursor for the object
  3754. */
  3755. public void setCursor(Cursor c) {
  3756. AccessibleContext ac = getCurrentAccessibleContext();
  3757. if (ac instanceof AccessibleComponent) {
  3758. ((AccessibleComponent) ac).setCursor(c);
  3759. } else {
  3760. Component cp = getCurrentComponent();
  3761. if (cp != null) {
  3762. cp.setCursor(c);
  3763. }
  3764. }
  3765. }
  3766. /**
  3767. * Get the Font of this object.
  3768. *
  3769. * @return the Font,if supported, for the object; otherwise, null
  3770. */
  3771. public Font getFont() {
  3772. AccessibleContext ac = getCurrentAccessibleContext();
  3773. if (ac instanceof AccessibleComponent) {
  3774. return ((AccessibleComponent) ac).getFont();
  3775. } else {
  3776. Component c = getCurrentComponent();
  3777. if (c != null) {
  3778. return c.getFont();
  3779. } else {
  3780. return null;
  3781. }
  3782. }
  3783. }
  3784. /**
  3785. * Set the Font of this object.
  3786. *
  3787. * @param f the new Font for the object
  3788. */
  3789. public void setFont(Font f) {
  3790. AccessibleContext ac = getCurrentAccessibleContext();
  3791. if (ac instanceof AccessibleComponent) {
  3792. ((AccessibleComponent) ac).setFont(f);
  3793. } else {
  3794. Component c = getCurrentComponent();
  3795. if (c != null) {
  3796. c.setFont(f);
  3797. }
  3798. }
  3799. }
  3800. /**
  3801. * Get the FontMetrics of this object.
  3802. *
  3803. * @param f the Font
  3804. * @return the FontMetrics, if supported, the object; otherwise, null
  3805. * @see #getFont
  3806. */
  3807. public FontMetrics getFontMetrics(Font f) {
  3808. AccessibleContext ac = getCurrentAccessibleContext();
  3809. if (ac instanceof AccessibleComponent) {
  3810. return ((AccessibleComponent) ac).getFontMetrics(f);
  3811. } else {
  3812. Component c = getCurrentComponent();
  3813. if (c != null) {
  3814. return c.getFontMetrics(f);
  3815. } else {
  3816. return null;
  3817. }
  3818. }
  3819. }
  3820. /**
  3821. * Determine if the object is enabled.
  3822. *
  3823. * @return true if object is enabled; otherwise, false
  3824. */
  3825. public boolean isEnabled() {
  3826. AccessibleContext ac = getCurrentAccessibleContext();
  3827. if (ac instanceof AccessibleComponent) {
  3828. return ((AccessibleComponent) ac).isEnabled();
  3829. } else {
  3830. Component c = getCurrentComponent();
  3831. if (c != null) {
  3832. return c.isEnabled();
  3833. } else {
  3834. return false;
  3835. }
  3836. }
  3837. }
  3838. /**
  3839. * Set the enabled state of the object.
  3840. *
  3841. * @param b if true, enables this object; otherwise, disables it
  3842. */
  3843. public void setEnabled(boolean b) {
  3844. AccessibleContext ac = getCurrentAccessibleContext();
  3845. if (ac instanceof AccessibleComponent) {
  3846. ((AccessibleComponent) ac).setEnabled(b);
  3847. } else {
  3848. Component c = getCurrentComponent();
  3849. if (c != null) {
  3850. c.setEnabled(b);
  3851. }
  3852. }
  3853. }
  3854. /**
  3855. * Determine if the object is visible. Note: this means that the
  3856. * object intends to be visible; however, it may not in fact be
  3857. * showing on the screen because one of the objects that this object
  3858. * is contained by is not visible. To determine if an object is
  3859. * showing on the screen, use isShowing().
  3860. *
  3861. * @return true if object is visible; otherwise, false
  3862. */
  3863. public boolean isVisible() {
  3864. AccessibleContext ac = getCurrentAccessibleContext();
  3865. if (ac instanceof AccessibleComponent) {
  3866. return ((AccessibleComponent) ac).isVisible();
  3867. } else {
  3868. Component c = getCurrentComponent();
  3869. if (c != null) {
  3870. return c.isVisible();
  3871. } else {
  3872. return false;
  3873. }
  3874. }
  3875. }
  3876. /**
  3877. * Set the visible state of the object.
  3878. *
  3879. * @param b if true, shows this object; otherwise, hides it
  3880. */
  3881. public void setVisible(boolean b) {
  3882. AccessibleContext ac = getCurrentAccessibleContext();
  3883. if (ac instanceof AccessibleComponent) {
  3884. ((AccessibleComponent) ac).setVisible(b);
  3885. } else {
  3886. Component c = getCurrentComponent();
  3887. if (c != null) {
  3888. c.setVisible(b);
  3889. }
  3890. }
  3891. }
  3892. /**
  3893. * Determine if the object is showing. This is determined by checking
  3894. * the visibility of the object and ancestors of the object. Note: this
  3895. * will return true even if the object is obscured by another (for example,
  3896. * it happens to be underneath a menu that was pulled down).
  3897. *
  3898. * @return true if object is showing; otherwise, false
  3899. */
  3900. public boolean isShowing() {
  3901. AccessibleContext ac = getCurrentAccessibleContext();
  3902. if (ac instanceof AccessibleComponent) {
  3903. return ((AccessibleComponent) ac).isShowing();
  3904. } else {
  3905. Component c = getCurrentComponent();
  3906. if (c != null) {
  3907. return c.isShowing();
  3908. } else {
  3909. return false;
  3910. }
  3911. }
  3912. }
  3913. /**
  3914. * Checks whether the specified point is within this object's bounds,
  3915. * where the point's x and y coordinates are defined to be relative to the
  3916. * coordinate system of the object.
  3917. *
  3918. * @param p the Point relative to the coordinate system of the object
  3919. * @return true if object contains Point; otherwise false
  3920. */
  3921. public boolean contains(Point p) {
  3922. AccessibleContext ac = getCurrentAccessibleContext();
  3923. if (ac instanceof AccessibleComponent) {
  3924. Rectangle r = ((AccessibleComponent) ac).getBounds();
  3925. return r.contains(p);
  3926. } else {
  3927. Component c = getCurrentComponent();
  3928. if (c != null) {
  3929. Rectangle r = c.getBounds();
  3930. return r.contains(p);
  3931. } else {
  3932. return getBounds().contains(p);
  3933. }
  3934. }
  3935. }
  3936. /**
  3937. * Returns the location of the object on the screen.
  3938. *
  3939. * @return location of object on screen -- can be null if this object
  3940. * is not on the screen
  3941. */
  3942. public Point getLocationOnScreen() {
  3943. if (parent != null) {
  3944. Point parentLocation = parent.getLocationOnScreen();
  3945. Point componentLocation = getLocation();
  3946. componentLocation.translate(parentLocation.x, parentLocation.y);
  3947. return componentLocation;
  3948. } else {
  3949. return null;
  3950. }
  3951. }
  3952. /**
  3953. * Gets the location of the object relative to the parent in the form
  3954. * of a point specifying the object's top-left corner in the screen's
  3955. * coordinate space.
  3956. *
  3957. * @return An instance of Point representing the top-left corner of the
  3958. * objects's bounds in the coordinate space of the screen; null if
  3959. * this object or its parent are not on the screen
  3960. */
  3961. public Point getLocation() {
  3962. if (parent != null) {
  3963. Rectangle r = parent.getCellRect(row, column, false);
  3964. if (r != null) {
  3965. return r.getLocation();
  3966. }
  3967. }
  3968. return null;
  3969. }
  3970. /**
  3971. * Sets the location of the object relative to the parent.
  3972. */
  3973. public void setLocation(Point p) {
  3974. // if ((parent != null) && (parent.contains(p))) {
  3975. // ensureIndexIsVisible(indexInParent);
  3976. // }
  3977. }
  3978. public Rectangle getBounds() {
  3979. if (parent != null) {
  3980. return parent.getCellRect(row, column, false);
  3981. } else {
  3982. return null;
  3983. }
  3984. }
  3985. public void setBounds(Rectangle r) {
  3986. AccessibleContext ac = getCurrentAccessibleContext();
  3987. if (ac instanceof AccessibleComponent) {
  3988. ((AccessibleComponent) ac).setBounds(r);
  3989. } else {
  3990. Component c = getCurrentComponent();
  3991. if (c != null) {
  3992. c.setBounds(r);
  3993. }
  3994. }
  3995. }
  3996. public Dimension getSize() {
  3997. if (parent != null) {
  3998. Rectangle r = parent.getCellRect(row, column, false);
  3999. if (r != null) {
  4000. return r.getSize();
  4001. }
  4002. }
  4003. return null;
  4004. }
  4005. public void setSize (Dimension d) {
  4006. AccessibleContext ac = getCurrentAccessibleContext();
  4007. if (ac instanceof AccessibleComponent) {
  4008. ((AccessibleComponent) ac).setSize(d);
  4009. } else {
  4010. Component c = getCurrentComponent();
  4011. if (c != null) {
  4012. c.setSize(d);
  4013. }
  4014. }
  4015. }
  4016. public Accessible getAccessibleAt(Point p) {
  4017. AccessibleContext ac = getCurrentAccessibleContext();
  4018. if (ac instanceof AccessibleComponent) {
  4019. return ((AccessibleComponent) ac).getAccessibleAt(p);
  4020. } else {
  4021. return null;
  4022. }
  4023. }
  4024. public boolean isFocusTraversable() {
  4025. AccessibleContext ac = getCurrentAccessibleContext();
  4026. if (ac instanceof AccessibleComponent) {
  4027. return ((AccessibleComponent) ac).isFocusTraversable();
  4028. } else {
  4029. Component c = getCurrentComponent();
  4030. if (c != null) {
  4031. return c.isFocusTraversable();
  4032. } else {
  4033. return false;
  4034. }
  4035. }
  4036. }
  4037. public void requestFocus() {
  4038. AccessibleContext ac = getCurrentAccessibleContext();
  4039. if (ac instanceof AccessibleComponent) {
  4040. ((AccessibleComponent) ac).requestFocus();
  4041. } else {
  4042. Component c = getCurrentComponent();
  4043. if (c != null) {
  4044. c.requestFocus();
  4045. }
  4046. }
  4047. }
  4048. public void addFocusListener(FocusListener l) {
  4049. AccessibleContext ac = getCurrentAccessibleContext();
  4050. if (ac instanceof AccessibleComponent) {
  4051. ((AccessibleComponent) ac).addFocusListener(l);
  4052. } else {
  4053. Component c = getCurrentComponent();
  4054. if (c != null) {
  4055. c.addFocusListener(l);
  4056. }
  4057. }
  4058. }
  4059. public void removeFocusListener(FocusListener l) {
  4060. AccessibleContext ac = getCurrentAccessibleContext();
  4061. if (ac instanceof AccessibleComponent) {
  4062. ((AccessibleComponent) ac).removeFocusListener(l);
  4063. } else {
  4064. Component c = getCurrentComponent();
  4065. if (c != null) {
  4066. c.removeFocusListener(l);
  4067. }
  4068. }
  4069. }
  4070. } // inner class AccessibleJTableCell
  4071. } // inner class AccessibleJTable
  4072. } // End of Class JTable