46 import javax.swing.table.*;
47 import javax.swing.border.*;
48
49 import java.text.NumberFormat;
50 import java.text.DateFormat;
51 import java.text.MessageFormat;
52 import java.util.List;
53
54 import javax.print.attribute.*;
55 import javax.print.PrintService;
56
57 import sun.misc.ManagedLocalsThread;
58 import sun.reflect.misc.ReflectUtil;
59
60 import sun.swing.SwingUtilities2;
61 import sun.swing.SwingUtilities2.Section;
62 import static sun.swing.SwingUtilities2.Section.*;
63 import sun.swing.PrintingStatus;
64
65 /**
66 * The <code>JTable</code> is used to display and edit regular two-dimensional tables
67 * of cells.
68 * See <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/table.html">How to Use Tables</a>
69 * in <em>The Java Tutorial</em>
70 * for task-oriented documentation and examples of using <code>JTable</code>.
71 *
72 * <p>
73 * The <code>JTable</code> has many
74 * facilities that make it possible to customize its rendering and editing
75 * but provides defaults for these features so that simple tables can be
76 * set up easily. For example, to set up a table with 10 rows and 10
77 * columns of numbers:
78 *
79 * <pre>
80 * TableModel dataModel = new AbstractTableModel() {
81 * public int getColumnCount() { return 10; }
82 * public int getRowCount() { return 10;}
83 * public Object getValueAt(int row, int col) { return new Integer(row*col); }
84 * };
85 * JTable table = new JTable(dataModel);
86 * JScrollPane scrollpane = new JScrollPane(table);
87 * </pre>
88 * <p>
89 * {@code JTable}s are typically placed inside of a {@code JScrollPane}. By
90 * default, a {@code JTable} will adjust its width such that
91 * a horizontal scrollbar is unnecessary. To allow for a horizontal scrollbar,
92 * invoke {@link #setAutoResizeMode} with {@code AUTO_RESIZE_OFF}.
93 * Note that if you wish to use a <code>JTable</code> in a standalone
94 * view (outside of a <code>JScrollPane</code>) and want the header
95 * displayed, you can get it using {@link #getTableHeader} and
96 * display it separately.
97 * <p>
98 * To enable sorting and filtering of rows, use a
99 * {@code RowSorter}.
100 * You can set up a row sorter in either of two ways:
101 * <ul>
102 * <li>Directly set the {@code RowSorter}. For example:
103 * {@code table.setRowSorter(new TableRowSorter(model))}.
104 * <li>Set the {@code autoCreateRowSorter}
105 * property to {@code true}, so that the {@code JTable}
106 * creates a {@code RowSorter} for
107 * you. For example: {@code setAutoCreateRowSorter(true)}.
108 * </ul>
109 * <p>
110 * When designing applications that use the <code>JTable</code> it is worth paying
111 * close attention to the data structures that will represent the table's data.
112 * The <code>DefaultTableModel</code> is a model implementation that
113 * uses a <code>Vector</code> of <code>Vector</code>s of <code>Object</code>s to
114 * store the cell values. As well as copying the data from an
115 * application into the <code>DefaultTableModel</code>,
116 * it is also possible to wrap the data in the methods of the
117 * <code>TableModel</code> interface so that the data can be passed to the
118 * <code>JTable</code> directly, as in the example above. This often results
119 * in more efficient applications because the model is free to choose the
120 * internal representation that best suits the data.
121 * A good rule of thumb for deciding whether to use the <code>AbstractTableModel</code>
122 * or the <code>DefaultTableModel</code> is to use the <code>AbstractTableModel</code>
123 * as the base class for creating subclasses and the <code>DefaultTableModel</code>
124 * when subclassing is not required.
125 * <p>
126 * The "TableExample" directory in the demo area of the source distribution
127 * gives a number of complete examples of <code>JTable</code> usage,
128 * covering how the <code>JTable</code> can be used to provide an
129 * editable view of data taken from a database and how to modify
130 * the columns in the display to use specialized renderers and editors.
131 * <p>
132 * The <code>JTable</code> uses integers exclusively to refer to both the rows and the columns
133 * of the model that it displays. The <code>JTable</code> simply takes a tabular range of cells
134 * and uses <code>getValueAt(int, int)</code> to retrieve the
135 * values from the model during painting. It is important to remember that
136 * the column and row indexes returned by various <code>JTable</code> methods
137 * are in terms of the <code>JTable</code> (the view) and are not
138 * necessarily the same indexes used by the model.
139 * <p>
140 * By default, columns may be rearranged in the <code>JTable</code> so that the
141 * view's columns appear in a different order to the columns in the model.
142 * This does not affect the implementation of the model at all: when the
143 * columns are reordered, the <code>JTable</code> maintains the new order of the columns
144 * internally and converts its column indices before querying the model.
145 * <p>
146 * So, when writing a <code>TableModel</code>, it is not necessary to listen for column
147 * reordering events as the model will be queried in its own coordinate
148 * system regardless of what is happening in the view.
149 * In the examples area there is a demonstration of a sorting algorithm making
150 * use of exactly this technique to interpose yet another coordinate system
151 * where the order of the rows is changed, rather than the order of the columns.
152 * <p>
153 * Similarly when using the sorting and filtering functionality
154 * provided by <code>RowSorter</code> the underlying
155 * <code>TableModel</code> does not need to know how to do sorting,
156 * rather <code>RowSorter</code> will handle it. Coordinate
157 * conversions will be necessary when using the row based methods of
158 * <code>JTable</code> with the underlying <code>TableModel</code>.
159 * All of <code>JTable</code>s row based methods are in terms of the
160 * <code>RowSorter</code>, which is not necessarily the same as that
161 * of the underlying <code>TableModel</code>. For example, the
162 * selection is always in terms of <code>JTable</code> so that when
163 * using <code>RowSorter</code> you will need to convert using
164 * <code>convertRowIndexToView</code> or
165 * <code>convertRowIndexToModel</code>. The following shows how to
166 * convert coordinates from <code>JTable</code> to that of the
167 * underlying model:
168 * <pre>
169 * int[] selection = table.getSelectedRows();
170 * for (int i = 0; i < selection.length; i++) {
171 * selection[i] = table.convertRowIndexToModel(selection[i]);
172 * }
173 * // selection is now in terms of the underlying TableModel
174 * </pre>
175 * <p>
176 * By default if sorting is enabled <code>JTable</code> will persist the
177 * selection and variable row heights in terms of the model on
178 * sorting. For example if row 0, in terms of the underlying model,
179 * is currently selected, after the sort row 0, in terms of the
180 * underlying model will be selected. Visually the selection may
181 * change, but in terms of the underlying model it will remain the
182 * same. The one exception to that is if the model index is no longer
183 * visible or was removed. For example, if row 0 in terms of model
184 * was filtered out the selection will be empty after the sort.
185 * <p>
186 * J2SE 5 adds methods to <code>JTable</code> to provide convenient access to some
187 * common printing needs. Simple new {@link #print()} methods allow for quick
188 * and easy addition of printing support to your application. In addition, a new
189 * {@link #getPrintable} method is available for more advanced printing needs.
190 * <p>
191 * As for all <code>JComponent</code> classes, you can use
192 * {@link InputMap} and {@link ActionMap} to associate an
193 * {@link Action} object with a {@link KeyStroke} and execute the
194 * action under specified conditions.
195 * <p>
196 * <strong>Warning:</strong> Swing is not thread safe. For more
197 * information see <a
198 * href="package-summary.html#threading">Swing's Threading
199 * Policy</a>.
200 * <p>
201 * <strong>Warning:</strong>
202 * Serialized objects of this class will not be compatible with
203 * future Swing releases. The current serialization support is
204 * appropriate for short term storage or RMI between applications running
205 * the same version of Swing. As of 1.4, support for long term storage
206 * of all JavaBeans™
207 * has been added to the <code>java.beans</code> package.
208 * Please see {@link java.beans.XMLEncoder}.
209 *
210 *
211 * @beaninfo
212 * attribute: isContainer false
213 * description: A component which displays data in a two dimensional grid.
214 *
215 * @author Philip Milne
216 * @author Shannon Hickey (printing support)
217 * @see javax.swing.table.DefaultTableModel
218 * @see javax.swing.table.TableRowSorter
219 * @since 1.2
220 */
221 /* The first versions of the JTable, contained in Swing-0.1 through
222 * Swing-0.4, were written by Alan Chung.
223 */
224 @SuppressWarnings("serial") // Same-version serialization only
225 public class JTable extends JComponent implements TableModelListener, Scrollable,
226 TableColumnModelListener, ListSelectionListener, CellEditorListener,
227 Accessible, RowSorterListener
237 private static final String uiClassID = "TableUI";
238
239 /** Do not adjust column widths automatically; use a horizontal scrollbar instead. */
240 public static final int AUTO_RESIZE_OFF = 0;
241
242 /** When a column is adjusted in the UI, adjust the next column the opposite way. */
243 public static final int AUTO_RESIZE_NEXT_COLUMN = 1;
244
245 /** During UI adjustment, change subsequent columns to preserve the total width;
246 * this is the default behavior. */
247 public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
248
249 /** During all resize operations, apply adjustments to the last column only. */
250 public static final int AUTO_RESIZE_LAST_COLUMN = 3;
251
252 /** During all resize operations, proportionately resize all columns. */
253 public static final int AUTO_RESIZE_ALL_COLUMNS = 4;
254
255
256 /**
257 * Printing modes, used in printing <code>JTable</code>s.
258 *
259 * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
260 * boolean, PrintRequestAttributeSet, boolean)
261 * @see #getPrintable
262 * @since 1.5
263 */
264 public enum PrintMode {
265
266 /**
267 * Printing mode that prints the table at its current size,
268 * spreading both columns and rows across multiple pages if necessary.
269 */
270 NORMAL,
271
272 /**
273 * Printing mode that scales the output smaller, if necessary,
274 * to fit the table's entire width (and thereby all columns) on each page;
275 * Rows are spread across multiple pages as necessary.
276 */
277 FIT_WIDTH
278 }
279
280
281 //
282 // Instance Variables
283 //
284
285 /** The <code>TableModel</code> of the table. */
286 protected TableModel dataModel;
287
288 /** The <code>TableColumnModel</code> of the table. */
289 protected TableColumnModel columnModel;
290
291 /** The <code>ListSelectionModel</code> of the table, used to keep track of row selections. */
292 protected ListSelectionModel selectionModel;
293
294 /** The <code>TableHeader</code> working with the table. */
295 protected JTableHeader tableHeader;
296
297 /** The height in pixels of each row in the table. */
298 protected int rowHeight;
299
300 /** The height in pixels of the margin between the cells in each row. */
301 protected int rowMargin;
302
303 /** The color of the grid. */
304 protected Color gridColor;
305
306 /** The table draws horizontal lines between cells if <code>showHorizontalLines</code> is true. */
307 protected boolean showHorizontalLines;
308
309 /** The table draws vertical lines between cells if <code>showVerticalLines</code> is true. */
310 protected boolean showVerticalLines;
311
312 /**
313 * Determines if the table automatically resizes the
314 * width of the table's columns to take up the entire width of the
315 * table, and how it does the resizing.
316 */
317 protected int autoResizeMode;
318
319 /**
320 * The table will query the <code>TableModel</code> to build the default
321 * set of columns if this is true.
322 */
323 protected boolean autoCreateColumnsFromModel;
324
325 /** Used by the <code>Scrollable</code> interface to determine the initial visible area. */
326 protected Dimension preferredViewportSize;
327
328 /** True if row selection is allowed in this table. */
329 protected boolean rowSelectionAllowed;
330
331 /**
332 * Obsolete as of Java 2 platform v1.3. Please use the
333 * <code>rowSelectionAllowed</code> property and the
334 * <code>columnSelectionAllowed</code> property of the
335 * <code>columnModel</code> instead. Or use the
336 * method <code>getCellSelectionEnabled</code>.
337 */
338 /*
339 * If true, both a row selection and a column selection
340 * can be non-empty at the same time, the selected cells are the
341 * the cells whose row and column are both selected.
342 */
343 protected boolean cellSelectionEnabled;
344
345 /** If editing, the <code>Component</code> that is handling the editing. */
346 protected transient Component editorComp;
347
348 /**
349 * The active cell editor object, that overwrites the screen real estate
350 * occupied by the current cell and allows the user to change its contents.
351 * {@code null} if the table isn't currently editing.
352 */
353 protected transient TableCellEditor cellEditor;
354
355 /** Identifies the column of the cell being edited. */
356 protected transient int editingColumn;
357
358 /** Identifies the row of the cell being edited. */
359 protected transient int editingRow;
360
361 /**
362 * A table of objects that display the contents of a cell,
363 * indexed by class as declared in <code>getColumnClass</code>
364 * in the <code>TableModel</code> interface.
365 */
366 protected transient Hashtable<Object, Object> defaultRenderersByColumnClass;
367 // Logicaly, the above is a Hashtable<Class<?>, TableCellRenderer>.
368 // It is declared otherwise to accomodate using UIDefaults.
369
370 /**
371 * A table of objects that display and edit the contents of a cell,
372 * indexed by class as declared in <code>getColumnClass</code>
373 * in the <code>TableModel</code> interface.
374 */
375 protected transient Hashtable<Object, Object> defaultEditorsByColumnClass;
376 // Logicaly, the above is a Hashtable<Class<?>, TableCellEditor>.
377 // It is declared otherwise to accomodate using UIDefaults.
378
379 /** The foreground color of selected cells. */
380 protected Color selectionForeground;
381
382 /** The background color of selected cells. */
383 protected Color selectionBackground;
384
385 //
386 // Private state
387 //
388
389 // WARNING: If you directly access this field you should also change the
390 // SortManager.modelRowSizes field as well.
391 private SizeSequence rowModel;
392 private boolean dragEnabled;
393 private boolean surrendersFocusOnKeystroke;
440 private boolean autoCreateRowSorter;
441
442 /**
443 * Whether or not the table always fills the viewport height.
444 * @see #setFillsViewportHeight
445 * @see #getScrollableTracksViewportHeight
446 */
447 private boolean fillsViewportHeight;
448
449 /**
450 * The drop mode for this component.
451 */
452 private DropMode dropMode = DropMode.USE_SELECTION;
453
454 /**
455 * The drop location.
456 */
457 private transient DropLocation dropLocation;
458
459 /**
460 * A subclass of <code>TransferHandler.DropLocation</code> representing
461 * a drop location for a <code>JTable</code>.
462 *
463 * @see #getDropLocation
464 * @since 1.6
465 */
466 public static final class DropLocation extends TransferHandler.DropLocation {
467 private final int row;
468 private final int col;
469 private final boolean isInsertRow;
470 private final boolean isInsertCol;
471
472 private DropLocation(Point p, int row, int col,
473 boolean isInsertRow, boolean isInsertCol) {
474
475 super(p);
476 this.row = row;
477 this.col = col;
478 this.isInsertRow = isInsertRow;
479 this.isInsertCol = isInsertCol;
480 }
481
482 /**
483 * Returns the row index where a dropped item should be placed in the
484 * table. Interpretation of the value depends on the return of
485 * <code>isInsertRow()</code>. If that method returns
486 * <code>true</code> this value indicates the index where a new
487 * row should be inserted. Otherwise, it represents the value
488 * of an existing row on which the data was dropped. This index is
489 * in terms of the view.
490 * <p>
491 * <code>-1</code> indicates that the drop occurred over empty space,
492 * and no row could be calculated.
493 *
494 * @return the drop row
495 */
496 public int getRow() {
497 return row;
498 }
499
500 /**
501 * Returns the column index where a dropped item should be placed in the
502 * table. Interpretation of the value depends on the return of
503 * <code>isInsertColumn()</code>. If that method returns
504 * <code>true</code> this value indicates the index where a new
505 * column should be inserted. Otherwise, it represents the value
506 * of an existing column on which the data was dropped. This index is
507 * in terms of the view.
508 * <p>
509 * <code>-1</code> indicates that the drop occurred over empty space,
510 * and no column could be calculated.
511 *
512 * @return the drop row
513 */
514 public int getColumn() {
515 return col;
516 }
517
518 /**
519 * Returns whether or not this location represents an insert
520 * of a row.
521 *
522 * @return whether or not this is an insert row
523 */
524 public boolean isInsertRow() {
525 return isInsertRow;
526 }
527
528 /**
529 * Returns whether or not this location represents an insert
541 * and the content and format of the returned string may vary
542 * between implementations.
543 *
544 * @return a string representation of this drop location
545 */
546 public String toString() {
547 return getClass().getName()
548 + "[dropPoint=" + getDropPoint() + ","
549 + "row=" + row + ","
550 + "column=" + col + ","
551 + "insertRow=" + isInsertRow + ","
552 + "insertColumn=" + isInsertCol + "]";
553 }
554 }
555
556 //
557 // Constructors
558 //
559
560 /**
561 * Constructs a default <code>JTable</code> that is initialized with a default
562 * data model, a default column model, and a default selection
563 * model.
564 *
565 * @see #createDefaultDataModel
566 * @see #createDefaultColumnModel
567 * @see #createDefaultSelectionModel
568 */
569 public JTable() {
570 this(null, null, null);
571 }
572
573 /**
574 * Constructs a <code>JTable</code> that is initialized with
575 * <code>dm</code> as the data model, a default column model,
576 * and a default selection model.
577 *
578 * @param dm the data model for the table
579 * @see #createDefaultColumnModel
580 * @see #createDefaultSelectionModel
581 */
582 public JTable(TableModel dm) {
583 this(dm, null, null);
584 }
585
586 /**
587 * Constructs a <code>JTable</code> that is initialized with
588 * <code>dm</code> as the data model, <code>cm</code>
589 * as the column model, and a default selection model.
590 *
591 * @param dm the data model for the table
592 * @param cm the column model for the table
593 * @see #createDefaultSelectionModel
594 */
595 public JTable(TableModel dm, TableColumnModel cm) {
596 this(dm, cm, null);
597 }
598
599 /**
600 * Constructs a <code>JTable</code> that is initialized with
601 * <code>dm</code> as the data model, <code>cm</code> as the
602 * column model, and <code>sm</code> as the selection model.
603 * If any of the parameters are <code>null</code> this method
604 * will initialize the table with the corresponding default model.
605 * The <code>autoCreateColumnsFromModel</code> flag is set to false
606 * if <code>cm</code> is non-null, otherwise it is set to true
607 * and the column model is populated with suitable
608 * <code>TableColumns</code> for the columns in <code>dm</code>.
609 *
610 * @param dm the data model for the table
611 * @param cm the column model for the table
612 * @param sm the row selection model for the table
613 * @see #createDefaultDataModel
614 * @see #createDefaultColumnModel
615 * @see #createDefaultSelectionModel
616 */
617 public JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
618 super();
619 setLayout(null);
620
621 setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
622 JComponent.getManagingFocusForwardTraversalKeys());
623 setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
624 JComponent.getManagingFocusBackwardTraversalKeys());
625 if (cm == null) {
626 cm = createDefaultColumnModel();
627 autoCreateColumnsFromModel = true;
628 }
629 setColumnModel(cm);
630
631 if (sm == null) {
632 sm = createDefaultSelectionModel();
633 }
634 setSelectionModel(sm);
635
636 // Set the model last, that way if the autoCreatColumnsFromModel has
637 // been set above, we will automatically populate an empty columnModel
638 // with suitable columns for the new model.
639 if (dm == null) {
640 dm = createDefaultDataModel();
641 }
642 setModel(dm);
643
644 initializeLocalVars();
645 updateUI();
646 }
647
648 /**
649 * Constructs a <code>JTable</code> with <code>numRows</code>
650 * and <code>numColumns</code> of empty cells using
651 * <code>DefaultTableModel</code>. The columns will have
652 * names of the form "A", "B", "C", etc.
653 *
654 * @param numRows the number of rows the table holds
655 * @param numColumns the number of columns the table holds
656 * @see javax.swing.table.DefaultTableModel
657 */
658 public JTable(int numRows, int numColumns) {
659 this(new DefaultTableModel(numRows, numColumns));
660 }
661
662 /**
663 * Constructs a <code>JTable</code> to display the values in the
664 * <code>Vector</code> of <code>Vectors</code>, <code>rowData</code>,
665 * with column names, <code>columnNames</code>. The
666 * <code>Vectors</code> contained in <code>rowData</code>
667 * should contain the values for that row. In other words,
668 * the value of the cell at row 1, column 5 can be obtained
669 * with the following code:
670 *
671 * <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
672 *
673 * @param rowData the data for the new table
674 * @param columnNames names of each column
675 */
676 @SuppressWarnings("rawtypes")
677 public JTable(Vector<? extends Vector> rowData, Vector<?> columnNames) {
678 this(new DefaultTableModel(rowData, columnNames));
679 }
680
681 /**
682 * Constructs a <code>JTable</code> to display the values in the two dimensional array,
683 * <code>rowData</code>, with column names, <code>columnNames</code>.
684 * <code>rowData</code> is an array of rows, so the value of the cell at row 1,
685 * column 5 can be obtained with the following code:
686 *
687 * <pre> rowData[1][5]; </pre>
688 * <p>
689 * All rows must be of the same length as <code>columnNames</code>.
690 *
691 * @param rowData the data for the new table
692 * @param columnNames names of each column
693 */
694 public JTable(final Object[][] rowData, final Object[] columnNames) {
695 this(new AbstractTableModel() {
696 public String getColumnName(int column) { return columnNames[column].toString(); }
697 public int getRowCount() { return rowData.length; }
698 public int getColumnCount() { return columnNames.length; }
699 public Object getValueAt(int row, int col) { return rowData[row][col]; }
700 public boolean isCellEditable(int row, int column) { return true; }
701 public void setValueAt(Object value, int row, int col) {
702 rowData[row][col] = value;
703 fireTableCellUpdated(row, col);
704 }
705 });
706 }
707
708 /**
709 * Calls the <code>configureEnclosingScrollPane</code> method.
710 *
711 * @see #configureEnclosingScrollPane
712 */
713 public void addNotify() {
714 super.addNotify();
715 configureEnclosingScrollPane();
716 }
717
718 /**
719 * If this <code>JTable</code> is the <code>viewportView</code> of an enclosing <code>JScrollPane</code>
720 * (the usual situation), configure this <code>ScrollPane</code> by, amongst other things,
721 * installing the table's <code>tableHeader</code> as the <code>columnHeaderView</code> of the scroll pane.
722 * When a <code>JTable</code> is added to a <code>JScrollPane</code> in the usual way,
723 * using <code>new JScrollPane(myTable)</code>, <code>addNotify</code> is
724 * called in the <code>JTable</code> (when the table is added to the viewport).
725 * <code>JTable</code>'s <code>addNotify</code> method in turn calls this method,
726 * which is protected so that this default installation procedure can
727 * be overridden by a subclass.
728 *
729 * @see #addNotify
730 */
731 protected void configureEnclosingScrollPane() {
732 Container parent = SwingUtilities.getUnwrappedParent(this);
733 if (parent instanceof JViewport) {
734 JViewport port = (JViewport) parent;
735 Container gp = port.getParent();
736 if (gp instanceof JScrollPane) {
737 JScrollPane scrollPane = (JScrollPane)gp;
738 // Make certain we are the viewPort's view and not, for
739 // example, the rowHeaderView of the scrollPane -
740 // an implementor of fixed columns might do this.
741 JViewport viewport = scrollPane.getViewport();
742 if (viewport == null ||
743 SwingUtilities.getUnwrappedView(viewport) != this) {
744 return;
745 }
788 }
789 // add JScrollBar corner component if available from LAF and not already set by the user
790 Component corner =
791 scrollPane.getCorner(JScrollPane.UPPER_TRAILING_CORNER);
792 if (corner == null || corner instanceof UIResource){
793 corner = null;
794 try {
795 corner = (Component) UIManager.get(
796 "Table.scrollPaneCornerComponent");
797 } catch (Exception e) {
798 // just ignore and don't set corner
799 }
800 scrollPane.setCorner(JScrollPane.UPPER_TRAILING_CORNER,
801 corner);
802 }
803 }
804 }
805 }
806
807 /**
808 * Calls the <code>unconfigureEnclosingScrollPane</code> method.
809 *
810 * @see #unconfigureEnclosingScrollPane
811 */
812 public void removeNotify() {
813 KeyboardFocusManager.getCurrentKeyboardFocusManager().
814 removePropertyChangeListener("permanentFocusOwner", editorRemover);
815 editorRemover = null;
816 unconfigureEnclosingScrollPane();
817 super.removeNotify();
818 }
819
820 /**
821 * Reverses the effect of <code>configureEnclosingScrollPane</code>
822 * by replacing the <code>columnHeaderView</code> of the enclosing
823 * scroll pane with <code>null</code>. <code>JTable</code>'s
824 * <code>removeNotify</code> method calls
825 * this method, which is protected so that this default uninstallation
826 * procedure can be overridden by a subclass.
827 *
828 * @see #removeNotify
829 * @see #configureEnclosingScrollPane
830 * @since 1.3
831 */
832 protected void unconfigureEnclosingScrollPane() {
833 Container parent = SwingUtilities.getUnwrappedParent(this);
834 if (parent instanceof JViewport) {
835 JViewport port = (JViewport) parent;
836 Container gp = port.getParent();
837 if (gp instanceof JScrollPane) {
838 JScrollPane scrollPane = (JScrollPane)gp;
839 // Make certain we are the viewPort's view and not, for
840 // example, the rowHeaderView of the scrollPane -
841 // an implementor of fixed columns might do this.
842 JViewport viewport = scrollPane.getViewport();
843 if (viewport == null ||
844 SwingUtilities.getUnwrappedView(viewport) != this) {
855 }
856 }
857 }
858
859 void setUIProperty(String propertyName, Object value) {
860 if (propertyName == "rowHeight") {
861 if (!isRowHeightSet) {
862 setRowHeight(((Number)value).intValue());
863 isRowHeightSet = false;
864 }
865 return;
866 }
867 super.setUIProperty(propertyName, value);
868 }
869
870 //
871 // Static Methods
872 //
873
874 /**
875 * Equivalent to <code>new JScrollPane(aTable)</code>.
876 *
877 * @param aTable a {@code JTable} to be used for the scroll pane
878 * @return a {@code JScrollPane} created using {@code aTable}
879 * @deprecated As of Swing version 1.0.2,
880 * replaced by <code>new JScrollPane(aTable)</code>.
881 */
882 @Deprecated
883 public static JScrollPane createScrollPaneForTable(JTable aTable) {
884 return new JScrollPane(aTable);
885 }
886
887 //
888 // Table Attributes
889 //
890
891 /**
892 * Sets the <code>tableHeader</code> working with this <code>JTable</code> to <code>newHeader</code>.
893 * It is legal to have a <code>null</code> <code>tableHeader</code>.
894 *
895 * @param tableHeader new tableHeader
896 * @see #getTableHeader
897 * @beaninfo
898 * bound: true
899 * description: The JTableHeader instance which renders the column headers.
900 */
901 public void setTableHeader(JTableHeader tableHeader) {
902 if (this.tableHeader != tableHeader) {
903 JTableHeader old = this.tableHeader;
904 // Release the old header
905 if (old != null) {
906 old.setTable(null);
907 }
908 this.tableHeader = tableHeader;
909 if (tableHeader != null) {
910 tableHeader.setTable(this);
911 }
912 firePropertyChange("tableHeader", old, tableHeader);
913 }
914 }
915
916 /**
917 * Returns the <code>tableHeader</code> used by this <code>JTable</code>.
918 *
919 * @return the <code>tableHeader</code> used by this table
920 * @see #setTableHeader
921 */
922 public JTableHeader getTableHeader() {
923 return tableHeader;
924 }
925
926 /**
927 * Sets the height, in pixels, of all cells to <code>rowHeight</code>,
928 * revalidates, and repaints.
929 * The height of the cells will be equal to the row height minus
930 * the row margin.
931 *
932 * @param rowHeight new row height
933 * @exception IllegalArgumentException if <code>rowHeight</code> is
934 * less than 1
935 * @see #getRowHeight
936 * @beaninfo
937 * bound: true
938 * description: The height of the specified row.
939 */
940 public void setRowHeight(int rowHeight) {
941 if (rowHeight <= 0) {
942 throw new IllegalArgumentException("New row height less than 1");
943 }
944 int old = this.rowHeight;
945 this.rowHeight = rowHeight;
946 rowModel = null;
947 if (sortManager != null) {
948 sortManager.modelRowSizes = null;
949 }
950 isRowHeightSet = true;
951 resizeAndRepaint();
952 firePropertyChange("rowHeight", old, rowHeight);
953 }
954
955 /**
956 * Returns the height of a table row, in pixels.
957 *
958 * @return the height in pixels of a table row
959 * @see #setRowHeight
960 */
961 public int getRowHeight() {
962 return rowHeight;
963 }
964
965 private SizeSequence getRowModel() {
966 if (rowModel == null) {
967 rowModel = new SizeSequence(getRowCount(), getRowHeight());
968 }
969 return rowModel;
970 }
971
972 /**
973 * Sets the height for <code>row</code> to <code>rowHeight</code>,
974 * revalidates, and repaints. The height of the cells in this row
975 * will be equal to the row height minus the row margin.
976 *
977 * @param row the row whose height is being
978 changed
979 * @param rowHeight new row height, in pixels
980 * @exception IllegalArgumentException if <code>rowHeight</code> is
981 * less than 1
982 * @beaninfo
983 * bound: true
984 * description: The height in pixels of the cells in <code>row</code>
985 * @since 1.3
986 */
987 public void setRowHeight(int row, int rowHeight) {
988 if (rowHeight <= 0) {
989 throw new IllegalArgumentException("New row height less than 1");
990 }
991 getRowModel().setSize(row, rowHeight);
992 if (sortManager != null) {
993 sortManager.setViewRowHeight(row, rowHeight);
994 }
995 resizeAndRepaint();
996 }
997
998 /**
999 * Returns the height, in pixels, of the cells in <code>row</code>.
1000 * @param row the row whose height is to be returned
1001 * @return the height, in pixels, of the cells in the row
1002 * @since 1.3
1003 */
1004 public int getRowHeight(int row) {
1005 return (rowModel == null) ? getRowHeight() : rowModel.getSize(row);
1006 }
1007
1008 /**
1009 * Sets the amount of empty space between cells in adjacent rows.
1010 *
1011 * @param rowMargin the number of pixels between cells in a row
1012 * @see #getRowMargin
1013 * @beaninfo
1014 * bound: true
1015 * description: The amount of space between cells.
1016 */
1017 public void setRowMargin(int rowMargin) {
1018 int old = this.rowMargin;
1019 this.rowMargin = rowMargin;
1020 resizeAndRepaint();
1021 firePropertyChange("rowMargin", old, rowMargin);
1022 }
1023
1024 /**
1025 * Gets the amount of empty space, in pixels, between cells. Equivalent to:
1026 * <code>getIntercellSpacing().height</code>.
1027 * @return the number of pixels between cells in a row
1028 *
1029 * @see #setRowMargin
1030 */
1031 public int getRowMargin() {
1032 return rowMargin;
1033 }
1034
1035 /**
1036 * Sets the <code>rowMargin</code> and the <code>columnMargin</code> --
1037 * the height and width of the space between cells -- to
1038 * <code>intercellSpacing</code>.
1039 *
1040 * @param intercellSpacing a <code>Dimension</code>
1041 * specifying the new width
1042 * and height between cells
1043 * @see #getIntercellSpacing
1044 * @beaninfo
1045 * description: The spacing between the cells,
1046 * drawn in the background color of the JTable.
1047 */
1048 public void setIntercellSpacing(Dimension intercellSpacing) {
1049 // Set the rowMargin here and columnMargin in the TableColumnModel
1050 setRowMargin(intercellSpacing.height);
1051 getColumnModel().setColumnMargin(intercellSpacing.width);
1052
1053 resizeAndRepaint();
1054 }
1055
1056 /**
1057 * Returns the horizontal and vertical space between cells.
1058 * The default spacing is look and feel dependent.
1059 *
1060 * @return the horizontal and vertical spacing between cells
1061 * @see #setIntercellSpacing
1062 */
1063 public Dimension getIntercellSpacing() {
1064 return new Dimension(getColumnModel().getColumnMargin(), rowMargin);
1065 }
1066
1067 /**
1068 * Sets the color used to draw grid lines to <code>gridColor</code> and redisplays.
1069 * The default color is look and feel dependent.
1070 *
1071 * @param gridColor the new color of the grid lines
1072 * @exception IllegalArgumentException if <code>gridColor</code> is <code>null</code>
1073 * @see #getGridColor
1074 * @beaninfo
1075 * bound: true
1076 * description: The grid color.
1077 */
1078 public void setGridColor(Color gridColor) {
1079 if (gridColor == null) {
1080 throw new IllegalArgumentException("New color is null");
1081 }
1082 Color old = this.gridColor;
1083 this.gridColor = gridColor;
1084 firePropertyChange("gridColor", old, gridColor);
1085 // Redraw
1086 repaint();
1087 }
1088
1089 /**
1090 * Returns the color used to draw grid lines.
1091 * The default color is look and feel dependent.
1092 *
1093 * @return the color used to draw grid lines
1094 * @see #setGridColor
1095 */
1096 public Color getGridColor() {
1097 return gridColor;
1098 }
1099
1100 /**
1101 * Sets whether the table draws grid lines around cells.
1102 * If <code>showGrid</code> is true it does; if it is false it doesn't.
1103 * There is no <code>getShowGrid</code> method as this state is held
1104 * in two variables -- <code>showHorizontalLines</code> and <code>showVerticalLines</code> --
1105 * each of which can be queried independently.
1106 *
1107 * @param showGrid true if table view should draw grid lines
1108 *
1109 * @see #setShowVerticalLines
1110 * @see #setShowHorizontalLines
1111 * @beaninfo
1112 * description: The color used to draw the grid lines.
1113 */
1114 public void setShowGrid(boolean showGrid) {
1115 setShowHorizontalLines(showGrid);
1116 setShowVerticalLines(showGrid);
1117
1118 // Redraw
1119 repaint();
1120 }
1121
1122 /**
1123 * Sets whether the table draws horizontal lines between cells.
1124 * If <code>showHorizontalLines</code> is true it does; if it is false it doesn't.
1125 *
1126 * @param showHorizontalLines true if table view should draw horizontal lines
1127 * @see #getShowHorizontalLines
1128 * @see #setShowGrid
1129 * @see #setShowVerticalLines
1130 * @beaninfo
1131 * bound: true
1132 * description: Whether horizontal lines should be drawn in between the cells.
1133 */
1134 public void setShowHorizontalLines(boolean showHorizontalLines) {
1135 boolean old = this.showHorizontalLines;
1136 this.showHorizontalLines = showHorizontalLines;
1137 firePropertyChange("showHorizontalLines", old, showHorizontalLines);
1138
1139 // Redraw
1140 repaint();
1141 }
1142
1143 /**
1144 * Sets whether the table draws vertical lines between cells.
1145 * If <code>showVerticalLines</code> is true it does; if it is false it doesn't.
1146 *
1147 * @param showVerticalLines true if table view should draw vertical lines
1148 * @see #getShowVerticalLines
1149 * @see #setShowGrid
1150 * @see #setShowHorizontalLines
1151 * @beaninfo
1152 * bound: true
1153 * description: Whether vertical lines should be drawn in between the cells.
1154 */
1155 public void setShowVerticalLines(boolean showVerticalLines) {
1156 boolean old = this.showVerticalLines;
1157 this.showVerticalLines = showVerticalLines;
1158 firePropertyChange("showVerticalLines", old, showVerticalLines);
1159 // Redraw
1160 repaint();
1161 }
1162
1163 /**
1164 * Returns true if the table draws horizontal lines between cells, false if it
1165 * doesn't. The default value is look and feel dependent.
1224 || (mode == AUTO_RESIZE_NEXT_COLUMN)
1225 || (mode == AUTO_RESIZE_SUBSEQUENT_COLUMNS)
1226 || (mode == AUTO_RESIZE_LAST_COLUMN)
1227 || (mode == AUTO_RESIZE_ALL_COLUMNS);
1228 }
1229
1230 /**
1231 * Returns the auto resize mode of the table. The default mode
1232 * is AUTO_RESIZE_SUBSEQUENT_COLUMNS.
1233 *
1234 * @return the autoResizeMode of the table
1235 *
1236 * @see #setAutoResizeMode
1237 * @see #doLayout
1238 */
1239 public int getAutoResizeMode() {
1240 return autoResizeMode;
1241 }
1242
1243 /**
1244 * Sets this table's <code>autoCreateColumnsFromModel</code> flag.
1245 * This method calls <code>createDefaultColumnsFromModel</code> if
1246 * <code>autoCreateColumnsFromModel</code> changes from false to true.
1247 *
1248 * @param autoCreateColumnsFromModel true if <code>JTable</code> should automatically create columns
1249 * @see #getAutoCreateColumnsFromModel
1250 * @see #createDefaultColumnsFromModel
1251 * @beaninfo
1252 * bound: true
1253 * description: Automatically populates the columnModel when a new TableModel is submitted.
1254 */
1255 public void setAutoCreateColumnsFromModel(boolean autoCreateColumnsFromModel) {
1256 if (this.autoCreateColumnsFromModel != autoCreateColumnsFromModel) {
1257 boolean old = this.autoCreateColumnsFromModel;
1258 this.autoCreateColumnsFromModel = autoCreateColumnsFromModel;
1259 if (autoCreateColumnsFromModel) {
1260 createDefaultColumnsFromModel();
1261 }
1262 firePropertyChange("autoCreateColumnsFromModel", old, autoCreateColumnsFromModel);
1263 }
1264 }
1265
1266 /**
1267 * Determines whether the table will create default columns from the model.
1268 * If true, <code>setModel</code> will clear any existing columns and
1269 * create new columns from the new model. Also, if the event in
1270 * the <code>tableChanged</code> notification specifies that the
1271 * entire table changed, then the columns will be rebuilt.
1272 * The default is true.
1273 *
1274 * @return the autoCreateColumnsFromModel of the table
1275 * @see #setAutoCreateColumnsFromModel
1276 * @see #createDefaultColumnsFromModel
1277 */
1278 public boolean getAutoCreateColumnsFromModel() {
1279 return autoCreateColumnsFromModel;
1280 }
1281
1282 /**
1283 * Creates default columns for the table from
1284 * the data model using the <code>getColumnCount</code> method
1285 * defined in the <code>TableModel</code> interface.
1286 * <p>
1287 * Clears any existing columns before creating the
1288 * new columns based on information from the model.
1289 *
1290 * @see #getAutoCreateColumnsFromModel
1291 */
1292 public void createDefaultColumnsFromModel() {
1293 TableModel m = getModel();
1294 if (m != null) {
1295 // Remove any current columns
1296 TableColumnModel cm = getColumnModel();
1297 while (cm.getColumnCount() > 0) {
1298 cm.removeColumn(cm.getColumn(0));
1299 }
1300
1301 // Create new columns from the data model info
1302 for (int i = 0; i < m.getColumnCount(); i++) {
1303 TableColumn newColumn = new TableColumn(i);
1304 addColumn(newColumn);
1305 }
1306 }
1307 }
1308
1309 /**
1310 * Sets a default cell renderer to be used if no renderer has been set in
1311 * a <code>TableColumn</code>. If renderer is <code>null</code>,
1312 * removes the default renderer for this column class.
1313 *
1314 * @param columnClass set the default cell renderer for this columnClass
1315 * @param renderer default cell renderer to be used for this
1316 * columnClass
1317 * @see #getDefaultRenderer
1318 * @see #setDefaultEditor
1319 */
1320 public void setDefaultRenderer(Class<?> columnClass, TableCellRenderer renderer) {
1321 if (renderer != null) {
1322 defaultRenderersByColumnClass.put(columnClass, renderer);
1323 }
1324 else {
1325 defaultRenderersByColumnClass.remove(columnClass);
1326 }
1327 }
1328
1329 /**
1330 * Returns the cell renderer to be used when no renderer has been set in
1331 * a <code>TableColumn</code>. During the rendering of cells the renderer is fetched from
1332 * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
1333 * there is no entry for this <code>columnClass</code> the method returns
1334 * the entry for the most specific superclass. The <code>JTable</code> installs entries
1335 * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
1336 * or replaced.
1337 *
1338 * @param columnClass return the default cell renderer
1339 * for this columnClass
1340 * @return the renderer for this columnClass
1341 * @see #setDefaultRenderer
1342 * @see #getColumnClass
1343 */
1344 public TableCellRenderer getDefaultRenderer(Class<?> columnClass) {
1345 if (columnClass == null) {
1346 return null;
1347 }
1348 else {
1349 Object renderer = defaultRenderersByColumnClass.get(columnClass);
1350 if (renderer != null) {
1351 return (TableCellRenderer)renderer;
1352 }
1353 else {
1354 Class<?> c = columnClass.getSuperclass();
1355 if (c == null && columnClass != Object.class) {
1356 c = Object.class;
1357 }
1358 return getDefaultRenderer(c);
1359 }
1360 }
1361 }
1362
1363 /**
1364 * Sets a default cell editor to be used if no editor has been set in
1365 * a <code>TableColumn</code>. If no editing is required in a table, or a
1366 * particular column in a table, uses the <code>isCellEditable</code>
1367 * method in the <code>TableModel</code> interface to ensure that this
1368 * <code>JTable</code> will not start an editor in these columns.
1369 * If editor is <code>null</code>, removes the default editor for this
1370 * column class.
1371 *
1372 * @param columnClass set the default cell editor for this columnClass
1373 * @param editor default cell editor to be used for this columnClass
1374 * @see TableModel#isCellEditable
1375 * @see #getDefaultEditor
1376 * @see #setDefaultRenderer
1377 */
1378 public void setDefaultEditor(Class<?> columnClass, TableCellEditor editor) {
1379 if (editor != null) {
1380 defaultEditorsByColumnClass.put(columnClass, editor);
1381 }
1382 else {
1383 defaultEditorsByColumnClass.remove(columnClass);
1384 }
1385 }
1386
1387 /**
1388 * Returns the editor to be used when no editor has been set in
1389 * a <code>TableColumn</code>. During the editing of cells the editor is fetched from
1390 * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
1391 * there is no entry for this <code>columnClass</code> the method returns
1392 * the entry for the most specific superclass. The <code>JTable</code> installs entries
1393 * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
1394 * or replaced.
1395 *
1396 * @param columnClass return the default cell editor for this columnClass
1397 * @return the default cell editor to be used for this columnClass
1398 * @see #setDefaultEditor
1399 * @see #getColumnClass
1400 */
1401 public TableCellEditor getDefaultEditor(Class<?> columnClass) {
1402 if (columnClass == null) {
1403 return null;
1404 }
1405 else {
1406 Object editor = defaultEditorsByColumnClass.get(columnClass);
1407 if (editor != null) {
1408 return (TableCellEditor)editor;
1409 }
1410 else {
1411 return getDefaultEditor(columnClass.getSuperclass());
1412 }
1413 }
1417 * Turns on or off automatic drag handling. In order to enable automatic
1418 * drag handling, this property should be set to {@code true}, and the
1419 * table's {@code TransferHandler} needs to be {@code non-null}.
1420 * The default value of the {@code dragEnabled} property is {@code false}.
1421 * <p>
1422 * The job of honoring this property, and recognizing a user drag gesture,
1423 * lies with the look and feel implementation, and in particular, the table's
1424 * {@code TableUI}. When automatic drag handling is enabled, most look and
1425 * feels (including those that subclass {@code BasicLookAndFeel}) begin a
1426 * drag and drop operation whenever the user presses the mouse button over
1427 * an item (in single selection mode) or a selection (in other selection
1428 * modes) and then moves the mouse a few pixels. Setting this property to
1429 * {@code true} can therefore have a subtle effect on how selections behave.
1430 * <p>
1431 * If a look and feel is used that ignores this property, you can still
1432 * begin a drag and drop operation by calling {@code exportAsDrag} on the
1433 * table's {@code TransferHandler}.
1434 *
1435 * @param b whether or not to enable automatic drag handling
1436 * @exception HeadlessException if
1437 * <code>b</code> is <code>true</code> and
1438 * <code>GraphicsEnvironment.isHeadless()</code>
1439 * returns <code>true</code>
1440 * @see java.awt.GraphicsEnvironment#isHeadless
1441 * @see #getDragEnabled
1442 * @see #setTransferHandler
1443 * @see TransferHandler
1444 * @since 1.4
1445 *
1446 * @beaninfo
1447 * description: determines whether automatic drag handling is enabled
1448 * bound: false
1449 */
1450 public void setDragEnabled(boolean b) {
1451 checkDragEnabled(b);
1452 dragEnabled = b;
1453 }
1454
1455 private void checkDragEnabled(boolean b) {
1456 if (b && GraphicsEnvironment.isHeadless()) {
1457 throw new HeadlessException();
1458 }
1459 }
1460
1461 /**
1462 * Returns whether or not automatic drag handling is enabled.
1463 *
1464 * @return the value of the {@code dragEnabled} property
1465 * @see #setDragEnabled
1466 * @since 1.4
1467 */
1468 public boolean getDragEnabled() {
1469 return dragEnabled;
1470 }
1471
1472 /**
1473 * Sets the drop mode for this component. For backward compatibility,
1474 * the default for this property is <code>DropMode.USE_SELECTION</code>.
1475 * Usage of one of the other modes is recommended, however, for an
1476 * improved user experience. <code>DropMode.ON</code>, for instance,
1477 * offers similar behavior of showing items as selected, but does so without
1478 * affecting the actual selection in the table.
1479 * <p>
1480 * <code>JTable</code> supports the following drop modes:
1481 * <ul>
1482 * <li><code>DropMode.USE_SELECTION</code></li>
1483 * <li><code>DropMode.ON</code></li>
1484 * <li><code>DropMode.INSERT</code></li>
1485 * <li><code>DropMode.INSERT_ROWS</code></li>
1486 * <li><code>DropMode.INSERT_COLS</code></li>
1487 * <li><code>DropMode.ON_OR_INSERT</code></li>
1488 * <li><code>DropMode.ON_OR_INSERT_ROWS</code></li>
1489 * <li><code>DropMode.ON_OR_INSERT_COLS</code></li>
1490 * </ul>
1491 * <p>
1492 * The drop mode is only meaningful if this component has a
1493 * <code>TransferHandler</code> that accepts drops.
1494 *
1495 * @param dropMode the drop mode to use
1496 * @throws IllegalArgumentException if the drop mode is unsupported
1497 * or <code>null</code>
1498 * @see #getDropMode
1499 * @see #getDropLocation
1500 * @see #setTransferHandler
1501 * @see TransferHandler
1502 * @since 1.6
1503 */
1504 public final void setDropMode(DropMode dropMode) {
1505 checkDropMode(dropMode);
1506 this.dropMode = dropMode;
1507 }
1508
1509 private static void checkDropMode(DropMode dropMode) {
1510 if (dropMode != null) {
1511 switch (dropMode) {
1512 case USE_SELECTION:
1513 case ON:
1514 case INSERT:
1515 case INSERT_ROWS:
1516 case INSERT_COLS:
1517 case ON_OR_INSERT:
1522 }
1523 throw new IllegalArgumentException(dropMode
1524 + ": Unsupported drop mode for table");
1525 }
1526 /**
1527 * Returns the drop mode for this component.
1528 *
1529 * @return the drop mode for this component
1530 * @see #setDropMode
1531 * @since 1.6
1532 */
1533 public final DropMode getDropMode() {
1534 return dropMode;
1535 }
1536
1537 /**
1538 * Calculates a drop location in this component, representing where a
1539 * drop at the given point should insert data.
1540 *
1541 * @param p the point to calculate a drop location for
1542 * @return the drop location, or <code>null</code>
1543 */
1544 DropLocation dropLocationForPoint(Point p) {
1545 DropLocation location = null;
1546
1547 int row = rowAtPoint(p);
1548 int col = columnAtPoint(p);
1549 boolean outside = Boolean.TRUE == getClientProperty("Table.isFileList")
1550 && SwingUtilities2.pointOutsidePrefSize(this, row, col, p);
1551
1552 Rectangle rect = getCellRect(row, col, true);
1553 Section xSection, ySection;
1554 boolean between = false;
1555 boolean ltr = getComponentOrientation().isLeftToRight();
1556
1557 switch(dropMode) {
1558 case USE_SELECTION:
1559 case ON:
1560 if (row == -1 || col == -1 || outside) {
1561 location = new DropLocation(p, -1, -1, false, false);
1562 } else {
1718 }
1719
1720 /**
1721 * Called to set or clear the drop location during a DnD operation.
1722 * In some cases, the component may need to use it's internal selection
1723 * temporarily to indicate the drop location. To help facilitate this,
1724 * this method returns and accepts as a parameter a state object.
1725 * This state object can be used to store, and later restore, the selection
1726 * state. Whatever this method returns will be passed back to it in
1727 * future calls, as the state parameter. If it wants the DnD system to
1728 * continue storing the same state, it must pass it back every time.
1729 * Here's how this is used:
1730 * <p>
1731 * Let's say that on the first call to this method the component decides
1732 * to save some state (because it is about to use the selection to show
1733 * a drop index). It can return a state object to the caller encapsulating
1734 * any saved selection state. On a second call, let's say the drop location
1735 * is being changed to something else. The component doesn't need to
1736 * restore anything yet, so it simply passes back the same state object
1737 * to have the DnD system continue storing it. Finally, let's say this
1738 * method is messaged with <code>null</code>. This means DnD
1739 * is finished with this component for now, meaning it should restore
1740 * state. At this point, it can use the state parameter to restore
1741 * said state, and of course return <code>null</code> since there's
1742 * no longer anything to store.
1743 *
1744 * @param location the drop location (as calculated by
1745 * <code>dropLocationForPoint</code>) or <code>null</code>
1746 * if there's no longer a valid drop location
1747 * @param state the state object saved earlier for this component,
1748 * or <code>null</code>
1749 * @param forDrop whether or not the method is being called because an
1750 * actual drop occurred
1751 * @return any saved state for this component, or <code>null</code> if none
1752 */
1753 Object setDropLocation(TransferHandler.DropLocation location,
1754 Object state,
1755 boolean forDrop) {
1756
1757 Object retVal = null;
1758 DropLocation tableLocation = (DropLocation)location;
1759
1760 if (dropMode == DropMode.USE_SELECTION) {
1761 if (tableLocation == null) {
1762 if (!forDrop && state != null) {
1763 clearSelection();
1764
1765 int[] rows = ((int[][])state)[0];
1766 int[] cols = ((int[][])state)[1];
1767 int[] anchleads = ((int[][])state)[2];
1768
1769 for (int row : rows) {
1770 addRowSelectionInterval(row, row);
1771 }
1806 setColumnSelectionInterval(tableLocation.getColumn(),
1807 tableLocation.getColumn());
1808 }
1809 }
1810 }
1811
1812 DropLocation old = dropLocation;
1813 dropLocation = tableLocation;
1814 firePropertyChange("dropLocation", old, dropLocation);
1815
1816 return retVal;
1817 }
1818
1819 /**
1820 * Returns the location that this component should visually indicate
1821 * as the drop location during a DnD operation over the component,
1822 * or {@code null} if no location is to currently be shown.
1823 * <p>
1824 * This method is not meant for querying the drop location
1825 * from a {@code TransferHandler}, as the drop location is only
1826 * set after the {@code TransferHandler}'s <code>canImport</code>
1827 * has returned and has allowed for the location to be shown.
1828 * <p>
1829 * When this property changes, a property change event with
1830 * name "dropLocation" is fired by the component.
1831 *
1832 * @return the drop location
1833 * @see #setDropMode
1834 * @see TransferHandler#canImport(TransferHandler.TransferSupport)
1835 * @since 1.6
1836 */
1837 public final DropLocation getDropLocation() {
1838 return dropLocation;
1839 }
1840
1841 /**
1842 * Specifies whether a {@code RowSorter} should be created for the
1843 * table whenever its model changes.
1844 * <p>
1845 * When {@code setAutoCreateRowSorter(true)} is invoked, a {@code
1846 * TableRowSorter} is immediately created and installed on the
1896 * @since 1.6
1897 */
1898 public void setUpdateSelectionOnSort(boolean update) {
1899 if (updateSelectionOnSort != update) {
1900 updateSelectionOnSort = update;
1901 firePropertyChange("updateSelectionOnSort", !update, update);
1902 }
1903 }
1904
1905 /**
1906 * Returns true if the selection should be updated after sorting.
1907 *
1908 * @return whether to update the selection on a sort
1909 * @since 1.6
1910 */
1911 public boolean getUpdateSelectionOnSort() {
1912 return updateSelectionOnSort;
1913 }
1914
1915 /**
1916 * Sets the <code>RowSorter</code>. <code>RowSorter</code> is used
1917 * to provide sorting and filtering to a <code>JTable</code>.
1918 * <p>
1919 * This method clears the selection and resets any variable row heights.
1920 * <p>
1921 * This method fires a <code>PropertyChangeEvent</code> when appropriate,
1922 * with the property name <code>"rowSorter"</code>. For
1923 * backward-compatibility, this method fires an additional event with the
1924 * property name <code>"sorter"</code>.
1925 * <p>
1926 * If the underlying model of the <code>RowSorter</code> differs from
1927 * that of this <code>JTable</code> undefined behavior will result.
1928 *
1929 * @param sorter the <code>RowSorter</code>; <code>null</code> turns
1930 * sorting off
1931 * @see javax.swing.table.TableRowSorter
1932 * @beaninfo
1933 * bound: true
1934 * description: The table's RowSorter
1935 * @since 1.6
1936 */
1937 public void setRowSorter(RowSorter<? extends TableModel> sorter) {
1938 RowSorter<? extends TableModel> oldRowSorter = null;
1939 if (sortManager != null) {
1940 oldRowSorter = sortManager.sorter;
1941 sortManager.dispose();
1942 sortManager = null;
1943 }
1944 rowModel = null;
1945 clearSelectionAndLeadAnchor();
1946 if (sorter != null) {
1947 sortManager = new SortManager(sorter);
1948 }
1949 resizeAndRepaint();
1952 }
1953
1954 /**
1955 * Returns the object responsible for sorting.
1956 *
1957 * @return the object responsible for sorting
1958 * @since 1.6
1959 */
1960 public RowSorter<? extends TableModel> getRowSorter() {
1961 return (sortManager != null) ? sortManager.sorter : null;
1962 }
1963
1964 //
1965 // Selection methods
1966 //
1967 /**
1968 * Sets the table's selection mode to allow only single selections, a single
1969 * contiguous interval, or multiple intervals.
1970 * <P>
1971 * <b>Note:</b>
1972 * <code>JTable</code> provides all the methods for handling
1973 * column and row selection. When setting states,
1974 * such as <code>setSelectionMode</code>, it not only
1975 * updates the mode for the row selection model but also sets similar
1976 * values in the selection model of the <code>columnModel</code>.
1977 * If you want to have the row and column selection models operating
1978 * in different modes, set them both directly.
1979 * <p>
1980 * Both the row and column selection models for <code>JTable</code>
1981 * default to using a <code>DefaultListSelectionModel</code>
1982 * so that <code>JTable</code> works the same way as the
1983 * <code>JList</code>. See the <code>setSelectionMode</code> method
1984 * in <code>JList</code> for details about the modes.
1985 *
1986 * @param selectionMode the mode used by the row and column selection models
1987 * @see JList#setSelectionMode
1988 * @beaninfo
1989 * description: The selection mode used by the row and column selection models.
1990 * enum: SINGLE_SELECTION ListSelectionModel.SINGLE_SELECTION
1991 * SINGLE_INTERVAL_SELECTION ListSelectionModel.SINGLE_INTERVAL_SELECTION
1992 * MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
1993 */
1994 public void setSelectionMode(int selectionMode) {
1995 clearSelection();
1996 getSelectionModel().setSelectionMode(selectionMode);
1997 getColumnModel().getSelectionModel().setSelectionMode(selectionMode);
1998 }
1999
2000 /**
2001 * Sets whether the rows in this model can be selected.
2002 *
2003 * @param rowSelectionAllowed true if this model will allow row selection
2004 * @see #getRowSelectionAllowed
2042 if (old != columnSelectionAllowed) {
2043 repaint();
2044 }
2045 firePropertyChange("columnSelectionAllowed", old, columnSelectionAllowed);
2046 }
2047
2048 /**
2049 * Returns true if columns can be selected.
2050 *
2051 * @return true if columns can be selected, otherwise false
2052 * @see #setColumnSelectionAllowed
2053 */
2054 public boolean getColumnSelectionAllowed() {
2055 return columnModel.getColumnSelectionAllowed();
2056 }
2057
2058 /**
2059 * Sets whether this table allows both a column selection and a
2060 * row selection to exist simultaneously. When set,
2061 * the table treats the intersection of the row and column selection
2062 * models as the selected cells. Override <code>isCellSelected</code> to
2063 * change this default behavior. This method is equivalent to setting
2064 * both the <code>rowSelectionAllowed</code> property and
2065 * <code>columnSelectionAllowed</code> property of the
2066 * <code>columnModel</code> to the supplied value.
2067 *
2068 * @param cellSelectionEnabled true if simultaneous row and column
2069 * selection is allowed
2070 * @see #getCellSelectionEnabled
2071 * @see #isCellSelected
2072 * @beaninfo
2073 * bound: true
2074 * attribute: visualUpdate true
2075 * description: Select a rectangular region of cells rather than
2076 * rows or columns.
2077 */
2078 public void setCellSelectionEnabled(boolean cellSelectionEnabled) {
2079 setRowSelectionAllowed(cellSelectionEnabled);
2080 setColumnSelectionAllowed(cellSelectionEnabled);
2081 boolean old = this.cellSelectionEnabled;
2082 this.cellSelectionEnabled = cellSelectionEnabled;
2083 firePropertyChange("cellSelectionEnabled", old, cellSelectionEnabled);
2084 }
2085
2086 /**
2087 * Returns true if both row and column selection models are enabled.
2088 * Equivalent to <code>getRowSelectionAllowed() &&
2089 * getColumnSelectionAllowed()</code>.
2090 *
2091 * @return true if both row and column selection models are enabled
2092 *
2093 * @see #setCellSelectionEnabled
2094 */
2095 public boolean getCellSelectionEnabled() {
2096 return getRowSelectionAllowed() && getColumnSelectionAllowed();
2097 }
2098
2099 /**
2100 * Selects all rows, columns, and cells in the table.
2101 */
2102 public void selectAll() {
2103 // If I'm currently editing, then I should stop editing
2104 if (isEditing()) {
2105 removeEditor();
2106 }
2107 if (getRowCount() > 0 && getColumnCount() > 0) {
2108 int oldLead;
2109 int oldAnchor;
2161 private int getAdjustedIndex(int index, boolean row) {
2162 int compare = row ? getRowCount() : getColumnCount();
2163 return index < compare ? index : -1;
2164 }
2165
2166 private int boundRow(int row) throws IllegalArgumentException {
2167 if (row < 0 || row >= getRowCount()) {
2168 throw new IllegalArgumentException("Row index out of range");
2169 }
2170 return row;
2171 }
2172
2173 private int boundColumn(int col) {
2174 if (col< 0 || col >= getColumnCount()) {
2175 throw new IllegalArgumentException("Column index out of range");
2176 }
2177 return col;
2178 }
2179
2180 /**
2181 * Selects the rows from <code>index0</code> to <code>index1</code>,
2182 * inclusive.
2183 *
2184 * @exception IllegalArgumentException if <code>index0</code> or
2185 * <code>index1</code> lie outside
2186 * [0, <code>getRowCount()</code>-1]
2187 * @param index0 one end of the interval
2188 * @param index1 the other end of the interval
2189 */
2190 public void setRowSelectionInterval(int index0, int index1) {
2191 selectionModel.setSelectionInterval(boundRow(index0), boundRow(index1));
2192 }
2193
2194 /**
2195 * Selects the columns from <code>index0</code> to <code>index1</code>,
2196 * inclusive.
2197 *
2198 * @exception IllegalArgumentException if <code>index0</code> or
2199 * <code>index1</code> lie outside
2200 * [0, <code>getColumnCount()</code>-1]
2201 * @param index0 one end of the interval
2202 * @param index1 the other end of the interval
2203 */
2204 public void setColumnSelectionInterval(int index0, int index1) {
2205 columnModel.getSelectionModel().setSelectionInterval(boundColumn(index0), boundColumn(index1));
2206 }
2207
2208 /**
2209 * Adds the rows from <code>index0</code> to <code>index1</code>, inclusive, to
2210 * the current selection.
2211 *
2212 * @exception IllegalArgumentException if <code>index0</code> or <code>index1</code>
2213 * lie outside [0, <code>getRowCount()</code>-1]
2214 * @param index0 one end of the interval
2215 * @param index1 the other end of the interval
2216 */
2217 public void addRowSelectionInterval(int index0, int index1) {
2218 selectionModel.addSelectionInterval(boundRow(index0), boundRow(index1));
2219 }
2220
2221 /**
2222 * Adds the columns from <code>index0</code> to <code>index1</code>,
2223 * inclusive, to the current selection.
2224 *
2225 * @exception IllegalArgumentException if <code>index0</code> or
2226 * <code>index1</code> lie outside
2227 * [0, <code>getColumnCount()</code>-1]
2228 * @param index0 one end of the interval
2229 * @param index1 the other end of the interval
2230 */
2231 public void addColumnSelectionInterval(int index0, int index1) {
2232 columnModel.getSelectionModel().addSelectionInterval(boundColumn(index0), boundColumn(index1));
2233 }
2234
2235 /**
2236 * Deselects the rows from <code>index0</code> to <code>index1</code>, inclusive.
2237 *
2238 * @exception IllegalArgumentException if <code>index0</code> or
2239 * <code>index1</code> lie outside
2240 * [0, <code>getRowCount()</code>-1]
2241 * @param index0 one end of the interval
2242 * @param index1 the other end of the interval
2243 */
2244 public void removeRowSelectionInterval(int index0, int index1) {
2245 selectionModel.removeSelectionInterval(boundRow(index0), boundRow(index1));
2246 }
2247
2248 /**
2249 * Deselects the columns from <code>index0</code> to <code>index1</code>, inclusive.
2250 *
2251 * @exception IllegalArgumentException if <code>index0</code> or
2252 * <code>index1</code> lie outside
2253 * [0, <code>getColumnCount()</code>-1]
2254 * @param index0 one end of the interval
2255 * @param index1 the other end of the interval
2256 */
2257 public void removeColumnSelectionInterval(int index0, int index1) {
2258 columnModel.getSelectionModel().removeSelectionInterval(boundColumn(index0), boundColumn(index1));
2259 }
2260
2261 /**
2262 * Returns the index of the first selected row, -1 if no row is selected.
2263 * @return the index of the first selected row
2264 */
2265 public int getSelectedRow() {
2266 return selectionModel.getMinSelectionIndex();
2267 }
2268
2269 /**
2270 * Returns the index of the first selected column,
2271 * -1 if no column is selected.
2272 * @return the index of the first selected column
2273 */
2328 count++;
2329 }
2330 }
2331 return count;
2332 }
2333
2334 /**
2335 * Returns the number of selected columns.
2336 *
2337 * @return the number of selected columns, 0 if no columns are selected
2338 */
2339 public int getSelectedColumnCount() {
2340 return columnModel.getSelectedColumnCount();
2341 }
2342
2343 /**
2344 * Returns true if the specified index is in the valid range of rows,
2345 * and the row at that index is selected.
2346 *
2347 * @param row a row in the row model
2348 * @return true if <code>row</code> is a valid index and the row at
2349 * that index is selected (where 0 is the first row)
2350 */
2351 public boolean isRowSelected(int row) {
2352 return selectionModel.isSelectedIndex(row);
2353 }
2354
2355 /**
2356 * Returns true if the specified index is in the valid range of columns,
2357 * and the column at that index is selected.
2358 *
2359 * @param column the column in the column model
2360 * @return true if <code>column</code> is a valid index and the column at
2361 * that index is selected (where 0 is the first column)
2362 */
2363 public boolean isColumnSelected(int column) {
2364 return columnModel.getSelectionModel().isSelectedIndex(column);
2365 }
2366
2367 /**
2368 * Returns true if the specified indices are in the valid range of rows
2369 * and columns and the cell at the specified position is selected.
2370 * @param row the row being queried
2371 * @param column the column being queried
2372 *
2373 * @return true if <code>row</code> and <code>column</code> are valid indices
2374 * and the cell at index <code>(row, column)</code> is selected,
2375 * where the first row and first column are at index 0
2376 */
2377 public boolean isCellSelected(int row, int column) {
2378 if (!getRowSelectionAllowed() && !getColumnSelectionAllowed()) {
2379 return false;
2380 }
2381 return (!getRowSelectionAllowed() || isRowSelected(row)) &&
2382 (!getColumnSelectionAllowed() || isColumnSelected(column));
2383 }
2384
2385 private void changeSelectionModel(ListSelectionModel sm, int index,
2386 boolean toggle, boolean extend, boolean selected,
2387 int anchor, boolean anchorSelected) {
2388 if (extend) {
2389 if (toggle) {
2390 if (anchorSelected) {
2391 sm.addSelectionInterval(anchor, index);
2392 } else {
2393 sm.removeSelectionInterval(anchor, index);
2394 // this is a Windows-only behavior that we want for file lists
2402 sm.setSelectionInterval(anchor, index);
2403 }
2404 }
2405 else {
2406 if (toggle) {
2407 if (selected) {
2408 sm.removeSelectionInterval(index, index);
2409 }
2410 else {
2411 sm.addSelectionInterval(index, index);
2412 }
2413 }
2414 else {
2415 sm.setSelectionInterval(index, index);
2416 }
2417 }
2418 }
2419
2420 /**
2421 * Updates the selection models of the table, depending on the state of the
2422 * two flags: <code>toggle</code> and <code>extend</code>. Most changes
2423 * to the selection that are the result of keyboard or mouse events received
2424 * by the UI are channeled through this method so that the behavior may be
2425 * overridden by a subclass. Some UIs may need more functionality than
2426 * this method provides, such as when manipulating the lead for discontiguous
2427 * selection, and may not call into this method for some selection changes.
2428 * <p>
2429 * This implementation uses the following conventions:
2430 * <ul>
2431 * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>false</em>.
2432 * Clear the previous selection and ensure the new cell is selected.
2433 * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>true</em>.
2434 * Extend the previous selection from the anchor to the specified cell,
2435 * clearing all other selections.
2436 * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>false</em>.
2437 * If the specified cell is selected, deselect it. If it is not selected, select it.
2438 * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>true</em>.
2439 * Apply the selection state of the anchor to all cells between it and the
2440 * specified cell.
2441 * </ul>
2442 * @param rowIndex affects the selection at <code>row</code>
2443 * @param columnIndex affects the selection at <code>column</code>
2444 * @param toggle see description above
2445 * @param extend if true, extend the current selection
2446 *
2447 * @since 1.3
2448 */
2449 public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
2450 ListSelectionModel rsm = getSelectionModel();
2451 ListSelectionModel csm = getColumnModel().getSelectionModel();
2452
2453 int anchorRow = getAdjustedIndex(rsm.getAnchorSelectionIndex(), true);
2454 int anchorCol = getAdjustedIndex(csm.getAnchorSelectionIndex(), false);
2455
2456 boolean anchorSelected = true;
2457
2458 if (anchorRow == -1) {
2459 if (getRowCount() > 0) {
2460 anchorRow = 0;
2461 }
2462 anchorSelected = false;
2463 }
2481
2482 changeSelectionModel(csm, columnIndex, toggle, extend, selected,
2483 anchorCol, anchorSelected);
2484 changeSelectionModel(rsm, rowIndex, toggle, extend, selected,
2485 anchorRow, anchorSelected);
2486
2487 // Scroll after changing the selection as blit scrolling is immediate,
2488 // so that if we cause the repaint after the scroll we end up painting
2489 // everything!
2490 if (getAutoscrolls()) {
2491 Rectangle cellRect = getCellRect(rowIndex, columnIndex, false);
2492 if (cellRect != null) {
2493 scrollRectToVisible(cellRect);
2494 }
2495 }
2496 }
2497
2498 /**
2499 * Returns the foreground color for selected cells.
2500 *
2501 * @return the <code>Color</code> object for the foreground property
2502 * @see #setSelectionForeground
2503 * @see #setSelectionBackground
2504 */
2505 public Color getSelectionForeground() {
2506 return selectionForeground;
2507 }
2508
2509 /**
2510 * Sets the foreground color for selected cells. Cell renderers
2511 * can use this color to render text and graphics for selected
2512 * cells.
2513 * <p>
2514 * The default value of this property is defined by the look
2515 * and feel implementation.
2516 * <p>
2517 * This is a <a href="http://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html">JavaBeans</a> bound property.
2518 *
2519 * @param selectionForeground the <code>Color</code> to use in the foreground
2520 * for selected list items
2521 * @see #getSelectionForeground
2522 * @see #setSelectionBackground
2523 * @see #setForeground
2524 * @see #setBackground
2525 * @see #setFont
2526 * @beaninfo
2527 * bound: true
2528 * description: A default foreground color for selected cells.
2529 */
2530 public void setSelectionForeground(Color selectionForeground) {
2531 Color old = this.selectionForeground;
2532 this.selectionForeground = selectionForeground;
2533 firePropertyChange("selectionForeground", old, selectionForeground);
2534 repaint();
2535 }
2536
2537 /**
2538 * Returns the background color for selected cells.
2539 *
2540 * @return the <code>Color</code> used for the background of selected list items
2541 * @see #setSelectionBackground
2542 * @see #setSelectionForeground
2543 */
2544 public Color getSelectionBackground() {
2545 return selectionBackground;
2546 }
2547
2548 /**
2549 * Sets the background color for selected cells. Cell renderers
2550 * can use this color to the fill selected cells.
2551 * <p>
2552 * The default value of this property is defined by the look
2553 * and feel implementation.
2554 * <p>
2555 * This is a <a href="http://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html">JavaBeans</a> bound property.
2556 *
2557 * @param selectionBackground the <code>Color</code> to use for the background
2558 * of selected cells
2559 * @see #getSelectionBackground
2560 * @see #setSelectionForeground
2561 * @see #setForeground
2562 * @see #setBackground
2563 * @see #setFont
2564 * @beaninfo
2565 * bound: true
2566 * description: A default background color for selected cells.
2567 */
2568 public void setSelectionBackground(Color selectionBackground) {
2569 Color old = this.selectionBackground;
2570 this.selectionBackground = selectionBackground;
2571 firePropertyChange("selectionBackground", old, selectionBackground);
2572 repaint();
2573 }
2574
2575 /**
2576 * Returns the <code>TableColumn</code> object for the column in the table
2577 * whose identifier is equal to <code>identifier</code>, when compared using
2578 * <code>equals</code>.
2579 *
2580 * @return the <code>TableColumn</code> object that matches the identifier
2581 * @exception IllegalArgumentException if <code>identifier</code> is <code>null</code> or no <code>TableColumn</code> has this identifier
2582 *
2583 * @param identifier the identifier object
2584 */
2585 public TableColumn getColumn(Object identifier) {
2586 TableColumnModel cm = getColumnModel();
2587 int columnIndex = cm.getColumnIndex(identifier);
2588 return cm.getColumn(columnIndex);
2589 }
2590
2591 //
2592 // Informally implement the TableModel interface.
2593 //
2594
2595 /**
2596 * Maps the index of the column in the view at
2597 * <code>viewColumnIndex</code> to the index of the column
2598 * in the table model. Returns the index of the corresponding
2599 * column in the model. If <code>viewColumnIndex</code>
2600 * is less than zero, returns <code>viewColumnIndex</code>.
2601 *
2602 * @param viewColumnIndex the index of the column in the view
2603 * @return the index of the corresponding column in the model
2604 *
2605 * @see #convertColumnIndexToView
2606 */
2607 public int convertColumnIndexToModel(int viewColumnIndex) {
2608 return SwingUtilities2.convertColumnIndexToModel(
2609 getColumnModel(), viewColumnIndex);
2610 }
2611
2612 /**
2613 * Maps the index of the column in the table model at
2614 * <code>modelColumnIndex</code> to the index of the column
2615 * in the view. Returns the index of the
2616 * corresponding column in the view; returns -1 if this column is not
2617 * being displayed. If <code>modelColumnIndex</code> is less than zero,
2618 * returns <code>modelColumnIndex</code>.
2619 *
2620 * @param modelColumnIndex the index of the column in the model
2621 * @return the index of the corresponding column in the view
2622 *
2623 * @see #convertColumnIndexToModel
2624 */
2625 public int convertColumnIndexToView(int modelColumnIndex) {
2626 return SwingUtilities2.convertColumnIndexToView(
2627 getColumnModel(), modelColumnIndex);
2628 }
2629
2630 /**
2631 * Maps the index of the row in terms of the
2632 * <code>TableModel</code> to the view. If the contents of the
2633 * model are not sorted the model and view indices are the same.
2634 *
2635 * @param modelRowIndex the index of the row in terms of the model
2636 * @return the index of the corresponding row in the view, or -1 if
2637 * the row isn't visible
2638 * @throws IndexOutOfBoundsException if sorting is enabled and passed an
2639 * index outside the number of rows of the <code>TableModel</code>
2640 * @see javax.swing.table.TableRowSorter
2641 * @since 1.6
2642 */
2643 public int convertRowIndexToView(int modelRowIndex) {
2644 RowSorter<?> sorter = getRowSorter();
2645 if (sorter != null) {
2646 return sorter.convertRowIndexToView(modelRowIndex);
2647 }
2648 return modelRowIndex;
2649 }
2650
2651 /**
2652 * Maps the index of the row in terms of the view to the
2653 * underlying <code>TableModel</code>. If the contents of the
2654 * model are not sorted the model and view indices are the same.
2655 *
2656 * @param viewRowIndex the index of the row in the view
2657 * @return the index of the corresponding row in the model
2658 * @throws IndexOutOfBoundsException if sorting is enabled and passed an
2659 * index outside the range of the <code>JTable</code> as
2660 * determined by the method <code>getRowCount</code>
2661 * @see javax.swing.table.TableRowSorter
2662 * @see #getRowCount
2663 * @since 1.6
2664 */
2665 public int convertRowIndexToModel(int viewRowIndex) {
2666 RowSorter<?> sorter = getRowSorter();
2667 if (sorter != null) {
2668 return sorter.convertRowIndexToModel(viewRowIndex);
2669 }
2670 return viewRowIndex;
2671 }
2672
2673 /**
2674 * Returns the number of rows that can be shown in the
2675 * <code>JTable</code>, given unlimited space. If a
2676 * <code>RowSorter</code> with a filter has been specified, the
2677 * number of rows returned may differ from that of the underlying
2678 * <code>TableModel</code>.
2679 *
2680 * @return the number of rows shown in the <code>JTable</code>
2681 * @see #getColumnCount
2682 */
2683 public int getRowCount() {
2684 RowSorter<?> sorter = getRowSorter();
2685 if (sorter != null) {
2686 return sorter.getViewRowCount();
2687 }
2688 return getModel().getRowCount();
2689 }
2690
2691 /**
2692 * Returns the number of columns in the column model. Note that this may
2693 * be different from the number of columns in the table model.
2694 *
2695 * @return the number of columns in the table
2696 * @see #getRowCount
2697 * @see #removeColumn
2698 */
2699 public int getColumnCount() {
2700 return getColumnModel().getColumnCount();
2701 }
2702
2703 /**
2704 * Returns the name of the column appearing in the view at
2705 * column position <code>column</code>.
2706 *
2707 * @param column the column in the view being queried
2708 * @return the name of the column at position <code>column</code>
2709 in the view where the first column is column 0
2710 */
2711 public String getColumnName(int column) {
2712 return getModel().getColumnName(convertColumnIndexToModel(column));
2713 }
2714
2715 /**
2716 * Returns the type of the column appearing in the view at
2717 * column position <code>column</code>.
2718 *
2719 * @param column the column in the view being queried
2720 * @return the type of the column at position <code>column</code>
2721 * in the view where the first column is column 0
2722 */
2723 public Class<?> getColumnClass(int column) {
2724 return getModel().getColumnClass(convertColumnIndexToModel(column));
2725 }
2726
2727 /**
2728 * Returns the cell value at <code>row</code> and <code>column</code>.
2729 * <p>
2730 * <b>Note</b>: The column is specified in the table view's display
2731 * order, and not in the <code>TableModel</code>'s column
2732 * order. This is an important distinction because as the
2733 * user rearranges the columns in the table,
2734 * the column at a given index in the view will change.
2735 * Meanwhile the user's actions never affect the model's
2736 * column ordering.
2737 *
2738 * @param row the row whose value is to be queried
2739 * @param column the column whose value is to be queried
2740 * @return the Object at the specified cell
2741 */
2742 public Object getValueAt(int row, int column) {
2743 return getModel().getValueAt(convertRowIndexToModel(row),
2744 convertColumnIndexToModel(column));
2745 }
2746
2747 /**
2748 * Sets the value for the cell in the table model at <code>row</code>
2749 * and <code>column</code>.
2750 * <p>
2751 * <b>Note</b>: The column is specified in the table view's display
2752 * order, and not in the <code>TableModel</code>'s column
2753 * order. This is an important distinction because as the
2754 * user rearranges the columns in the table,
2755 * the column at a given index in the view will change.
2756 * Meanwhile the user's actions never affect the model's
2757 * column ordering.
2758 *
2759 * <code>aValue</code> is the new value.
2760 *
2761 * @param aValue the new value
2762 * @param row the row of the cell to be changed
2763 * @param column the column of the cell to be changed
2764 * @see #getValueAt
2765 */
2766 public void setValueAt(Object aValue, int row, int column) {
2767 getModel().setValueAt(aValue, convertRowIndexToModel(row),
2768 convertColumnIndexToModel(column));
2769 }
2770
2771 /**
2772 * Returns true if the cell at <code>row</code> and <code>column</code>
2773 * is editable. Otherwise, invoking <code>setValueAt</code> on the cell
2774 * will have no effect.
2775 * <p>
2776 * <b>Note</b>: The column is specified in the table view's display
2777 * order, and not in the <code>TableModel</code>'s column
2778 * order. This is an important distinction because as the
2779 * user rearranges the columns in the table,
2780 * the column at a given index in the view will change.
2781 * Meanwhile the user's actions never affect the model's
2782 * column ordering.
2783 *
2784 *
2785 * @param row the row whose value is to be queried
2786 * @param column the column whose value is to be queried
2787 * @return true if the cell is editable
2788 * @see #setValueAt
2789 */
2790 public boolean isCellEditable(int row, int column) {
2791 return getModel().isCellEditable(convertRowIndexToModel(row),
2792 convertColumnIndexToModel(column));
2793 }
2794 //
2795 // Adding and removing columns in the view
2796 //
2797
2798 /**
2799 * Appends <code>aColumn</code> to the end of the array of columns held by
2800 * this <code>JTable</code>'s column model.
2801 * If the column name of <code>aColumn</code> is <code>null</code>,
2802 * sets the column name of <code>aColumn</code> to the name
2803 * returned by <code>getModel().getColumnName()</code>.
2804 * <p>
2805 * To add a column to this <code>JTable</code> to display the
2806 * <code>modelColumn</code>'th column of data in the model with a
2807 * given <code>width</code>, <code>cellRenderer</code>,
2808 * and <code>cellEditor</code> you can use:
2809 * <pre>
2810 *
2811 * addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
2812 *
2813 * </pre>
2814 * [Any of the <code>TableColumn</code> constructors can be used
2815 * instead of this one.]
2816 * The model column number is stored inside the <code>TableColumn</code>
2817 * and is used during rendering and editing to locate the appropriates
2818 * data values in the model. The model column number does not change
2819 * when columns are reordered in the view.
2820 *
2821 * @param aColumn the <code>TableColumn</code> to be added
2822 * @see #removeColumn
2823 */
2824 public void addColumn(TableColumn aColumn) {
2825 if (aColumn.getHeaderValue() == null) {
2826 int modelColumn = aColumn.getModelIndex();
2827 String columnName = getModel().getColumnName(modelColumn);
2828 aColumn.setHeaderValue(columnName);
2829 }
2830 getColumnModel().addColumn(aColumn);
2831 }
2832
2833 /**
2834 * Removes <code>aColumn</code> from this <code>JTable</code>'s
2835 * array of columns. Note: this method does not remove the column
2836 * of data from the model; it just removes the <code>TableColumn</code>
2837 * that was responsible for displaying it.
2838 *
2839 * @param aColumn the <code>TableColumn</code> to be removed
2840 * @see #addColumn
2841 */
2842 public void removeColumn(TableColumn aColumn) {
2843 getColumnModel().removeColumn(aColumn);
2844 }
2845
2846 /**
2847 * Moves the column <code>column</code> to the position currently
2848 * occupied by the column <code>targetColumn</code> in the view.
2849 * The old column at <code>targetColumn</code> is
2850 * shifted left or right to make room.
2851 *
2852 * @param column the index of column to be moved
2853 * @param targetColumn the new index of the column
2854 */
2855 public void moveColumn(int column, int targetColumn) {
2856 getColumnModel().moveColumn(column, targetColumn);
2857 }
2858
2859 //
2860 // Cover methods for various models and helper methods
2861 //
2862
2863 /**
2864 * Returns the index of the column that <code>point</code> lies in,
2865 * or -1 if the result is not in the range
2866 * [0, <code>getColumnCount()</code>-1].
2867 *
2868 * @param point the location of interest
2869 * @return the index of the column that <code>point</code> lies in,
2870 * or -1 if the result is not in the range
2871 * [0, <code>getColumnCount()</code>-1]
2872 * @see #rowAtPoint
2873 */
2874 public int columnAtPoint(Point point) {
2875 int x = point.x;
2876 if( !getComponentOrientation().isLeftToRight() ) {
2877 x = getWidth() - x - 1;
2878 }
2879 return getColumnModel().getColumnIndexAtX(x);
2880 }
2881
2882 /**
2883 * Returns the index of the row that <code>point</code> lies in,
2884 * or -1 if the result is not in the range
2885 * [0, <code>getRowCount()</code>-1].
2886 *
2887 * @param point the location of interest
2888 * @return the index of the row that <code>point</code> lies in,
2889 * or -1 if the result is not in the range
2890 * [0, <code>getRowCount()</code>-1]
2891 * @see #columnAtPoint
2892 */
2893 public int rowAtPoint(Point point) {
2894 int y = point.y;
2895 int result = (rowModel == null) ? y/getRowHeight() : rowModel.getIndex(y);
2896 if (result < 0) {
2897 return -1;
2898 }
2899 else if (result >= getRowCount()) {
2900 return -1;
2901 }
2902 else {
2903 return result;
2904 }
2905 }
2906
2907 /**
2908 * Returns a rectangle for the cell that lies at the intersection of
2909 * <code>row</code> and <code>column</code>.
2910 * If <code>includeSpacing</code> is true then the value returned
2911 * has the full height and width of the row and column
2912 * specified. If it is false, the returned rectangle is inset by the
2913 * intercell spacing to return the true bounds of the rendering or
2914 * editing component as it will be set during rendering.
2915 * <p>
2916 * If the column index is valid but the row index is less
2917 * than zero the method returns a rectangle with the
2918 * <code>y</code> and <code>height</code> values set appropriately
2919 * and the <code>x</code> and <code>width</code> values both set
2920 * to zero. In general, when either the row or column indices indicate a
2921 * cell outside the appropriate range, the method returns a rectangle
2922 * depicting the closest edge of the closest cell that is within
2923 * the table's range. When both row and column indices are out
2924 * of range the returned rectangle covers the closest
2925 * point of the closest cell.
2926 * <p>
2927 * In all cases, calculations that use this method to calculate
2928 * results along one axis will not fail because of anomalies in
2929 * calculations along the other axis. When the cell is not valid
2930 * the <code>includeSpacing</code> parameter is ignored.
2931 *
2932 * @param row the row index where the desired cell
2933 * is located
2934 * @param column the column index where the desired cell
2935 * is located in the display; this is not
2936 * necessarily the same as the column index
2937 * in the data model for the table; the
2938 * {@link #convertColumnIndexToView(int)}
2939 * method may be used to convert a data
2940 * model column index to a display
2941 * column index
2942 * @param includeSpacing if false, return the true cell bounds -
2943 * computed by subtracting the intercell
2944 * spacing from the height and widths of
2945 * the column and row models
2946 *
2947 * @return the rectangle containing the cell at location
2948 * <code>row</code>,<code>column</code>
2949 * @see #getIntercellSpacing
2950 */
2951 public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
2952 Rectangle r = new Rectangle();
2953 boolean valid = true;
2954 if (row < 0) {
2955 // y = height = 0;
2956 valid = false;
2957 }
2958 else if (row >= getRowCount()) {
2959 r.y = getHeight();
2960 valid = false;
2961 }
2962 else {
2963 r.height = getRowHeight(row);
2964 r.y = (rowModel == null) ? row * r.height : rowModel.getPosition(row);
2965 }
2966
2967 if (column < 0) {
2968 if( !getComponentOrientation().isLeftToRight() ) {
3001 r.setBounds(r.x + cm/2, r.y + rm/2, r.width - cm, r.height - rm);
3002 }
3003 return r;
3004 }
3005
3006 private int viewIndexForColumn(TableColumn aColumn) {
3007 TableColumnModel cm = getColumnModel();
3008 for (int column = 0; column < cm.getColumnCount(); column++) {
3009 if (cm.getColumn(column) == aColumn) {
3010 return column;
3011 }
3012 }
3013 return -1;
3014 }
3015
3016 /**
3017 * Causes this table to lay out its rows and columns. Overridden so
3018 * that columns can be resized to accommodate a change in the size of
3019 * a containing parent.
3020 * Resizes one or more of the columns in the table
3021 * so that the total width of all of this <code>JTable</code>'s
3022 * columns is equal to the width of the table.
3023 * <p>
3024 * Before the layout begins the method gets the
3025 * <code>resizingColumn</code> of the <code>tableHeader</code>.
3026 * When the method is called as a result of the resizing of an enclosing window,
3027 * the <code>resizingColumn</code> is <code>null</code>. This means that resizing
3028 * has taken place "outside" the <code>JTable</code> and the change -
3029 * or "delta" - should be distributed to all of the columns regardless
3030 * of this <code>JTable</code>'s automatic resize mode.
3031 * <p>
3032 * If the <code>resizingColumn</code> is not <code>null</code>, it is one of
3033 * the columns in the table that has changed size rather than
3034 * the table itself. In this case the auto-resize modes govern
3035 * the way the extra (or deficit) space is distributed
3036 * amongst the available columns.
3037 * <p>
3038 * The modes are:
3039 * <ul>
3040 * <li> AUTO_RESIZE_OFF: Don't automatically adjust the column's
3041 * widths at all. Use a horizontal scrollbar to accommodate the
3042 * columns when their sum exceeds the width of the
3043 * <code>Viewport</code>. If the <code>JTable</code> is not
3044 * enclosed in a <code>JScrollPane</code> this may
3045 * leave parts of the table invisible.
3046 * <li> AUTO_RESIZE_NEXT_COLUMN: Use just the column after the
3047 * resizing column. This results in the "boundary" or divider
3048 * between adjacent cells being independently adjustable.
3049 * <li> AUTO_RESIZE_SUBSEQUENT_COLUMNS: Use all columns after the
3050 * one being adjusted to absorb the changes. This is the
3051 * default behavior.
3052 * <li> AUTO_RESIZE_LAST_COLUMN: Automatically adjust the
3053 * size of the last column only. If the bounds of the last column
3054 * prevent the desired size from being allocated, set the
3055 * width of the last column to the appropriate limit and make
3056 * no further adjustments.
3057 * <li> AUTO_RESIZE_ALL_COLUMNS: Spread the delta amongst all the columns
3058 * in the <code>JTable</code>, including the one that is being
3059 * adjusted.
3060 * </ul>
3061 * <p>
3062 * <b>Note:</b> When a <code>JTable</code> makes adjustments
3063 * to the widths of the columns it respects their minimum and
3064 * maximum values absolutely. It is therefore possible that,
3065 * even after this method is called, the total width of the columns
3066 * is still not equal to the width of the table. When this happens
3067 * the <code>JTable</code> does not put itself
3068 * in AUTO_RESIZE_OFF mode to bring up a scroll bar, or break other
3069 * commitments of its current auto-resize mode -- instead it
3070 * allows its bounds to be set larger (or smaller) than the total of the
3071 * column minimum or maximum, meaning, either that there
3072 * will not be enough room to display all of the columns, or that the
3073 * columns will not fill the <code>JTable</code>'s bounds.
3074 * These respectively, result in the clipping of some columns
3075 * or an area being painted in the <code>JTable</code>'s
3076 * background color during painting.
3077 * <p>
3078 * The mechanism for distributing the delta amongst the available
3079 * columns is provided in a private method in the <code>JTable</code>
3080 * class:
3081 * <pre>
3082 * adjustSizes(long targetSize, final Resizable3 r, boolean inverse)
3083 * </pre>
3084 * an explanation of which is provided in the following section.
3085 * <code>Resizable3</code> is a private
3086 * interface that allows any data structure containing a collection
3087 * of elements with a size, preferred size, maximum size and minimum size
3088 * to have its elements manipulated by the algorithm.
3089 *
3090 * <H3> Distributing the delta </H3>
3091 *
3092 * <H4> Overview </H4>
3093 * <P>
3094 * Call "DELTA" the difference between the target size and the
3095 * sum of the preferred sizes of the elements in r. The individual
3096 * sizes are calculated by taking the original preferred
3097 * sizes and adding a share of the DELTA - that share being based on
3098 * how far each preferred size is from its limiting bound (minimum or
3099 * maximum).
3100 *
3101 * <H4>Definition</H4>
3102 * <P>
3103 * Call the individual constraints min[i], max[i], and pref[i].
3104 * <p>
3105 * Call their respective sums: MIN, MAX, and PREF.
3121 * If (DELTA > 0) we are in expand mode where:
3122 *
3123 * <PRE>
3124 * DELTA
3125 * delta[i] = ------------ * (max[i] - pref[i])
3126 * (MAX - PREF)
3127 * </PRE>
3128 * <P>
3129 * The overall effect is that the total size moves that same percentage,
3130 * k, towards the total minimum or maximum and that percentage guarantees
3131 * accommodation of the required space, DELTA.
3132 *
3133 * <H4>Details</H4>
3134 * <P>
3135 * Naive evaluation of the formulae presented here would be subject to
3136 * the aggregated rounding errors caused by doing this operation in finite
3137 * precision (using ints). To deal with this, the multiplying factor above,
3138 * is constantly recalculated and this takes account of the rounding
3139 * errors in the previous iterations. The result is an algorithm that
3140 * produces a set of integers whose values exactly sum to the supplied
3141 * <code>targetSize</code>, and does so by spreading the rounding
3142 * errors evenly over the given elements.
3143 *
3144 * <H4>When the MAX and MIN bounds are hit</H4>
3145 * <P>
3146 * When <code>targetSize</code> is outside the [MIN, MAX] range,
3147 * the algorithm sets all sizes to their appropriate limiting value
3148 * (maximum or minimum).
3149 *
3150 */
3151 public void doLayout() {
3152 TableColumn resizingColumn = getResizingColumn();
3153 if (resizingColumn == null) {
3154 setWidthsFromPreferredWidths(false);
3155 }
3156 else {
3157 // JTable behaves like a layout manger - but one in which the
3158 // user can come along and dictate how big one of the children
3159 // (columns) is supposed to be.
3160
3161 // A column has been resized and JTable may need to distribute
3162 // any overall delta to other columns, according to the resize mode.
3163 int columnIndex = viewIndexForColumn(resizingColumn);
3164 int delta = getWidth() - getColumnModel().getTotalColumnWidth();
3165 accommodateDelta(columnIndex, delta);
3166 delta = getWidth() - getColumnModel().getTotalColumnWidth();
3184 // Thereafter, during window resizing etc. it has to work off
3185 // the preferred sizes as usual - the idea being that, whatever
3186 // the user does, everything stays in synch and things don't jump
3187 // around.
3188 setWidthsFromPreferredWidths(true);
3189 }
3190
3191 super.doLayout();
3192 }
3193
3194 private TableColumn getResizingColumn() {
3195 return (tableHeader == null) ? null
3196 : tableHeader.getResizingColumn();
3197 }
3198
3199 /**
3200 * Sizes the table columns to fit the available space.
3201 *
3202 * @param lastColumnOnly determines whether to resize last column only
3203 * @deprecated As of Swing version 1.0.3,
3204 * replaced by <code>doLayout()</code>.
3205 * @see #doLayout
3206 */
3207 @Deprecated
3208 public void sizeColumnsToFit(boolean lastColumnOnly) {
3209 int oldAutoResizeMode = autoResizeMode;
3210 setAutoResizeMode(lastColumnOnly ? AUTO_RESIZE_LAST_COLUMN
3211 : AUTO_RESIZE_ALL_COLUMNS);
3212 sizeColumnsToFit(-1);
3213 setAutoResizeMode(oldAutoResizeMode);
3214 }
3215
3216 /**
3217 * Obsolete as of Java 2 platform v1.4. Please use the
3218 * <code>doLayout()</code> method instead.
3219 * @param resizingColumn the column whose resizing made this adjustment
3220 * necessary or -1 if there is no such column
3221 * @see #doLayout
3222 */
3223 public void sizeColumnsToFit(int resizingColumn) {
3224 if (resizingColumn == -1) {
3225 setWidthsFromPreferredWidths(false);
3226 }
3227 else {
3228 if (autoResizeMode == AUTO_RESIZE_OFF) {
3229 TableColumn aColumn = getColumnModel().getColumn(resizingColumn);
3230 aColumn.setPreferredWidth(aColumn.getWidth());
3231 }
3232 else {
3233 int delta = getWidth() - getColumnModel().getTotalColumnWidth();
3234 accommodateDelta(resizingColumn, delta);
3235 setWidthsFromPreferredWidths(true);
3236 }
3237 }
3238 }
3374 // In this case, lowerBound == upperBound, for all subsequent terms.
3375 int newSize;
3376 if (totalLowerBound == totalUpperBound) {
3377 newSize = lowerBound;
3378 }
3379 else {
3380 double f = (double)(target - totalLowerBound)/(totalUpperBound - totalLowerBound);
3381 newSize = (int)Math.round(lowerBound+f*(upperBound - lowerBound));
3382 // We'd need to round manually in an all integer version.
3383 // size[i] = (int)(((totalUpperBound - target) * lowerBound +
3384 // (target - totalLowerBound) * upperBound)/(totalUpperBound-totalLowerBound));
3385 }
3386 r.setSizeAt(newSize, i);
3387 target -= newSize;
3388 totalLowerBound -= lowerBound;
3389 totalUpperBound -= upperBound;
3390 }
3391 }
3392
3393 /**
3394 * Overrides <code>JComponent</code>'s <code>getToolTipText</code>
3395 * method in order to allow the renderer's tips to be used
3396 * if it has text set.
3397 * <p>
3398 * <b>Note:</b> For <code>JTable</code> to properly display
3399 * tooltips of its renderers
3400 * <code>JTable</code> must be a registered component with the
3401 * <code>ToolTipManager</code>.
3402 * This is done automatically in <code>initializeLocalVars</code>,
3403 * but if at a later point <code>JTable</code> is told
3404 * <code>setToolTipText(null)</code> it will unregister the table
3405 * component, and no tips from renderers will display anymore.
3406 *
3407 * @see JComponent#getToolTipText
3408 */
3409 public String getToolTipText(MouseEvent event) {
3410 String tip = null;
3411 Point p = event.getPoint();
3412
3413 // Locate the renderer under the event location
3414 int hitColumnIndex = columnAtPoint(p);
3415 int hitRowIndex = rowAtPoint(p);
3416
3417 if ((hitColumnIndex != -1) && (hitRowIndex != -1)) {
3418 TableCellRenderer renderer = getCellRenderer(hitRowIndex, hitColumnIndex);
3419 Component component = prepareRenderer(renderer, hitRowIndex, hitColumnIndex);
3420
3421 // Now have to see if the component is a JComponent before
3422 // getting the tip
3423 if (component instanceof JComponent) {
3424 // Convert the event to the renderer's coordinate system
3466 public void setSurrendersFocusOnKeystroke(boolean surrendersFocusOnKeystroke) {
3467 this.surrendersFocusOnKeystroke = surrendersFocusOnKeystroke;
3468 }
3469
3470 /**
3471 * Returns true if the editor should get the focus
3472 * when keystrokes cause the editor to be activated
3473 *
3474 * @return true if the editor should get the focus
3475 * when keystrokes cause the editor to be
3476 * activated
3477 *
3478 * @see #setSurrendersFocusOnKeystroke
3479 * @since 1.4
3480 */
3481 public boolean getSurrendersFocusOnKeystroke() {
3482 return surrendersFocusOnKeystroke;
3483 }
3484
3485 /**
3486 * Programmatically starts editing the cell at <code>row</code> and
3487 * <code>column</code>, if those indices are in the valid range, and
3488 * the cell at those indices is editable.
3489 * Note that this is a convenience method for
3490 * <code>editCellAt(int, int, null)</code>.
3491 *
3492 * @param row the row to be edited
3493 * @param column the column to be edited
3494 * @return false if for any reason the cell cannot be edited,
3495 * or if the indices are invalid
3496 */
3497 public boolean editCellAt(int row, int column) {
3498 return editCellAt(row, column, null);
3499 }
3500
3501 /**
3502 * Programmatically starts editing the cell at <code>row</code> and
3503 * <code>column</code>, if those indices are in the valid range, and
3504 * the cell at those indices is editable.
3505 * To prevent the <code>JTable</code> from
3506 * editing a particular table, column or cell value, return false from
3507 * the <code>isCellEditable</code> method in the <code>TableModel</code>
3508 * interface.
3509 *
3510 * @param row the row to be edited
3511 * @param column the column to be edited
3512 * @param e event to pass into <code>shouldSelectCell</code>;
3513 * note that as of Java 2 platform v1.2, the call to
3514 * <code>shouldSelectCell</code> is no longer made
3515 * @return false if for any reason the cell cannot be edited,
3516 * or if the indices are invalid
3517 */
3518 public boolean editCellAt(int row, int column, EventObject e){
3519 if (cellEditor != null && !cellEditor.stopCellEditing()) {
3520 return false;
3521 }
3522
3523 if (row < 0 || row >= getRowCount() ||
3524 column < 0 || column >= getColumnCount()) {
3525 return false;
3526 }
3527
3528 if (!isCellEditable(row, column))
3529 return false;
3530
3531 if (editorRemover == null) {
3532 KeyboardFocusManager fm =
3533 KeyboardFocusManager.getCurrentKeyboardFocusManager();
3534 editorRemover = new CellEditorRemover(fm);
3592
3593 /**
3594 * Returns the index of the row that contains the cell currently
3595 * being edited. If nothing is being edited, returns -1.
3596 *
3597 * @return the index of the row that contains the cell currently
3598 * being edited; returns -1 if nothing being edited
3599 * @see #editingColumn
3600 */
3601 public int getEditingRow() {
3602 return editingRow;
3603 }
3604
3605 //
3606 // Managing TableUI
3607 //
3608
3609 /**
3610 * Returns the L&F object that renders this component.
3611 *
3612 * @return the <code>TableUI</code> object that renders this component
3613 */
3614 public TableUI getUI() {
3615 return (TableUI)ui;
3616 }
3617
3618 /**
3619 * Sets the L&F object that renders this component and repaints.
3620 *
3621 * @param ui the TableUI L&F object
3622 * @see UIDefaults#getUI
3623 * @beaninfo
3624 * bound: true
3625 * hidden: true
3626 * attribute: visualUpdate true
3627 * description: The UI object that implements the Component's LookAndFeel.
3628 */
3629 public void setUI(TableUI ui) {
3630 if (this.ui != ui) {
3631 super.setUI(ui);
3632 repaint();
3633 }
3634 }
3635
3636 /**
3637 * Notification from the <code>UIManager</code> that the L&F has changed.
3638 * Replaces the current UI object with the latest version from the
3639 * <code>UIManager</code>.
3640 *
3641 * @see JComponent#updateUI
3642 */
3643 public void updateUI() {
3644 // Update the UIs of the cell renderers, cell editors and header renderers.
3645 TableColumnModel cm = getColumnModel();
3646 for(int column = 0; column < cm.getColumnCount(); column++) {
3647 TableColumn aColumn = cm.getColumn(column);
3648 SwingUtilities.updateRendererOrEditorUI(aColumn.getCellRenderer());
3649 SwingUtilities.updateRendererOrEditorUI(aColumn.getCellEditor());
3650 SwingUtilities.updateRendererOrEditorUI(aColumn.getHeaderRenderer());
3651 }
3652
3653 // Update the UIs of all the default renderers.
3654 Enumeration<?> defaultRenderers = defaultRenderersByColumnClass.elements();
3655 while (defaultRenderers.hasMoreElements()) {
3656 SwingUtilities.updateRendererOrEditorUI(defaultRenderers.nextElement());
3657 }
3658
3659 // Update the UIs of all the default editors.
3812 }
3813 }
3814
3815 /**
3816 * Returns the {@code ListSelectionModel} that is used to maintain row
3817 * selection state.
3818 *
3819 * @return the object that provides row selection state, {@code null} if row
3820 * selection is not allowed
3821 * @see #setSelectionModel
3822 */
3823 public ListSelectionModel getSelectionModel() {
3824 return selectionModel;
3825 }
3826
3827 //
3828 // RowSorterListener
3829 //
3830
3831 /**
3832 * <code>RowSorterListener</code> notification that the
3833 * <code>RowSorter</code> has changed in some way.
3834 *
3835 * @param e the <code>RowSorterEvent</code> describing the change
3836 * @throws NullPointerException if <code>e</code> is <code>null</code>
3837 * @since 1.6
3838 */
3839 public void sorterChanged(RowSorterEvent e) {
3840 if (e.getType() == RowSorterEvent.Type.SORT_ORDER_CHANGED) {
3841 JTableHeader header = getTableHeader();
3842 if (header != null) {
3843 header.repaint();
3844 }
3845 }
3846 else if (e.getType() == RowSorterEvent.Type.SORTED) {
3847 sorterChanged = true;
3848 if (!ignoreSortChange) {
3849 sortedTableChanged(e, null);
3850 }
3851 }
3852 }
3853
3854
3855 /**
3856 * SortManager provides support for managing the selection and variable
4108 int length;
4109
4110 // True if the event indicates all the contents have changed
4111 boolean allRowsChanged;
4112
4113 ModelChange(TableModelEvent e) {
4114 startModelIndex = Math.max(0, e.getFirstRow());
4115 endModelIndex = e.getLastRow();
4116 modelRowCount = getModel().getRowCount();
4117 if (endModelIndex < 0) {
4118 endModelIndex = Math.max(0, modelRowCount - 1);
4119 }
4120 length = endModelIndex - startModelIndex + 1;
4121 type = e.getType();
4122 event = e;
4123 allRowsChanged = (e.getLastRow() == Integer.MAX_VALUE);
4124 }
4125 }
4126
4127 /**
4128 * Invoked when <code>sorterChanged</code> is invoked, or
4129 * when <code>tableChanged</code> is invoked and sorting is enabled.
4130 */
4131 private void sortedTableChanged(RowSorterEvent sortedEvent,
4132 TableModelEvent e) {
4133 int editingModelIndex = -1;
4134 ModelChange change = (e != null) ? new ModelChange(e) : null;
4135
4136 if ((change == null || !change.allRowsChanged) &&
4137 this.editingRow != -1) {
4138 editingModelIndex = convertRowIndexToModel(sortedEvent,
4139 this.editingRow);
4140 }
4141
4142 sortManager.prepareForChange(sortedEvent, change);
4143
4144 if (e != null) {
4145 if (change.type == TableModelEvent.UPDATE) {
4146 repaintSortedRows(change);
4147 }
4148 notifySorter(change);
4149 if (change.type != TableModelEvent.UPDATE) {
4365 private int convertRowIndexToModel(RowSorterEvent e, int viewIndex) {
4366 if (e != null) {
4367 if (e.getPreviousRowCount() == 0) {
4368 return viewIndex;
4369 }
4370 // range checking handled by RowSorterEvent
4371 return e.convertPreviousRowIndexToModel(viewIndex);
4372 }
4373 // Make sure the viewIndex is valid
4374 if (viewIndex < 0 || viewIndex >= getRowCount()) {
4375 return -1;
4376 }
4377 return convertRowIndexToModel(viewIndex);
4378 }
4379
4380 //
4381 // Implementing TableModelListener interface
4382 //
4383
4384 /**
4385 * Invoked when this table's <code>TableModel</code> generates
4386 * a <code>TableModelEvent</code>.
4387 * The <code>TableModelEvent</code> should be constructed in the
4388 * coordinate system of the model; the appropriate mapping to the
4389 * view coordinate system is performed by this <code>JTable</code>
4390 * when it receives the event.
4391 * <p>
4392 * Application code will not use these methods explicitly, they
4393 * are used internally by <code>JTable</code>.
4394 * <p>
4395 * Note that as of 1.3, this method clears the selection, if any.
4396 */
4397 public void tableChanged(TableModelEvent e) {
4398 if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
4399 // The whole thing changed
4400 clearSelectionAndLeadAnchor();
4401
4402 rowModel = null;
4403
4404 if (sortManager != null) {
4405 try {
4406 ignoreSortChange = true;
4407 sortManager.sorter.modelStructureChanged();
4408 } finally {
4409 ignoreSortChange = false;
4410 }
4411 sortManager.allChanged();
4412 }
4413
4624 * @see TableColumnModelListener
4625 */
4626 public void columnMarginChanged(ChangeEvent e) {
4627 if (isEditing() && !getCellEditor().stopCellEditing()) {
4628 getCellEditor().cancelCellEditing();
4629 }
4630 TableColumn resizingColumn = getResizingColumn();
4631 // Need to do this here, before the parent's
4632 // layout manager calls getPreferredSize().
4633 if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF) {
4634 resizingColumn.setPreferredWidth(resizingColumn.getWidth());
4635 }
4636 resizeAndRepaint();
4637 }
4638
4639 private int limit(int i, int a, int b) {
4640 return Math.min(b, Math.max(i, a));
4641 }
4642
4643 /**
4644 * Invoked when the selection model of the <code>TableColumnModel</code>
4645 * is changed.
4646 * <p>
4647 * Application code will not use these methods explicitly, they
4648 * are used internally by JTable.
4649 *
4650 * @param e the event received
4651 * @see TableColumnModelListener
4652 */
4653 public void columnSelectionChanged(ListSelectionEvent e) {
4654 boolean isAdjusting = e.getValueIsAdjusting();
4655 if (columnSelectionAdjusting && !isAdjusting) {
4656 // The assumption is that when the model is no longer adjusting
4657 // we will have already gotten all the changes, and therefore
4658 // don't need to do an additional paint.
4659 columnSelectionAdjusting = false;
4660 return;
4661 }
4662 columnSelectionAdjusting = isAdjusting;
4663 // The getCellRect() call will fail unless there is at least one row.
4664 if (getRowCount() <= 0 || getColumnCount() <= 0) {
4764 * Invoked when editing is canceled. The editor object is discarded
4765 * and the cell is rendered once again.
4766 * <p>
4767 * Application code will not use these methods explicitly, they
4768 * are used internally by JTable.
4769 *
4770 * @param e the event received
4771 * @see CellEditorListener
4772 */
4773 public void editingCanceled(ChangeEvent e) {
4774 removeEditor();
4775 }
4776
4777 //
4778 // Implementing the Scrollable interface
4779 //
4780
4781 /**
4782 * Sets the preferred size of the viewport for this table.
4783 *
4784 * @param size a <code>Dimension</code> object specifying the <code>preferredSize</code> of a
4785 * <code>JViewport</code> whose view is this table
4786 * @see Scrollable#getPreferredScrollableViewportSize
4787 * @beaninfo
4788 * description: The preferred size of the viewport.
4789 */
4790 public void setPreferredScrollableViewportSize(Dimension size) {
4791 preferredViewportSize = size;
4792 }
4793
4794 /**
4795 * Returns the preferred size of the viewport for this table.
4796 *
4797 * @return a <code>Dimension</code> object containing the <code>preferredSize</code> of the <code>JViewport</code>
4798 * which displays this table
4799 * @see Scrollable#getPreferredScrollableViewportSize
4800 */
4801 public Dimension getPreferredScrollableViewportSize() {
4802 return preferredViewportSize;
4803 }
4804
4805 /**
4806 * Returns the scroll increment (in pixels) that completely exposes one new
4807 * row or column (depending on the orientation).
4808 * <p>
4809 * This method is called each time the user requests a unit scroll.
4810 *
4811 * @param visibleRect the view area visible within the viewport
4812 * @param orientation either <code>SwingConstants.VERTICAL</code>
4813 * or <code>SwingConstants.HORIZONTAL</code>
4814 * @param direction less than zero to scroll up/left,
4815 * greater than zero for down/right
4816 * @return the "unit" increment for scrolling in the specified direction
4817 * @see Scrollable#getScrollableUnitIncrement
4818 */
4819 public int getScrollableUnitIncrement(Rectangle visibleRect,
4820 int orientation,
4821 int direction) {
4822 int leadingRow;
4823 int leadingCol;
4824 Rectangle leadingCellRect;
4825
4826 int leadingVisibleEdge;
4827 int leadingCellEdge;
4828 int leadingCellSize;
4829
4830 leadingRow = getLeadingRow(visibleRect);
4831 leadingCol = getLeadingCol(visibleRect);
4832 if (orientation == SwingConstants.VERTICAL && leadingRow < 0) {
4833 // Couldn't find leading row - return some default value
4888 else { // Case #2: hide leading cell
4889 return leadingCellSize;
4890 }
4891 }
4892 else { // Leading cell is partially hidden
4893 // Compute visible, hidden portions
4894 int hiddenAmt = Math.abs(leadingVisibleEdge - leadingCellEdge);
4895 int visibleAmt = leadingCellSize - hiddenAmt;
4896
4897 if (direction > 0) {
4898 // Case #3: hide showing portion of leading cell
4899 return visibleAmt;
4900 }
4901 else { // Case #4: reveal hidden portion of leading cell
4902 return hiddenAmt;
4903 }
4904 }
4905 }
4906
4907 /**
4908 * Returns <code>visibleRect.height</code> or
4909 * <code>visibleRect.width</code>,
4910 * depending on this table's orientation. Note that as of Swing 1.1.1
4911 * (Java 2 v 1.2.2) the value
4912 * returned will ensure that the viewport is cleanly aligned on
4913 * a row boundary.
4914 *
4915 * @return <code>visibleRect.height</code> or
4916 * <code>visibleRect.width</code>
4917 * per the orientation
4918 * @see Scrollable#getScrollableBlockIncrement
4919 */
4920 public int getScrollableBlockIncrement(Rectangle visibleRect,
4921 int orientation, int direction) {
4922
4923 if (getRowCount() == 0) {
4924 // Short-circuit empty table model
4925 if (SwingConstants.VERTICAL == orientation) {
4926 int rh = getRowHeight();
4927 return (rh > 0) ? Math.max(rh, (visibleRect.height / rh) * rh) :
4928 visibleRect.height;
4929 }
4930 else {
4931 return visibleRect.width;
4932 }
4933 }
4934 // Shortcut for vertical scrolling of a table w/ uniform row height
4935 if (null == rowModel && SwingConstants.VERTICAL == orientation) {
4936 int row = rowAtPoint(visibleRect.getLocation());
5196 }
5197
5198 /*
5199 * Returns the trailing edge ("end") of the given Rectangle.
5200 * For VERTICAL, this is the bottom, for left-to-right, the right side, and
5201 * for right-to-left, the left side.
5202 */
5203 private int trailingEdge(Rectangle rect, int orientation) {
5204 if (orientation == SwingConstants.VERTICAL) {
5205 return rect.y + rect.height;
5206 }
5207 else if (getComponentOrientation().isLeftToRight()) {
5208 return rect.x + rect.width;
5209 }
5210 else { // Horizontal, right-to-left
5211 return rect.x;
5212 }
5213 }
5214
5215 /**
5216 * Returns false if <code>autoResizeMode</code> is set to
5217 * <code>AUTO_RESIZE_OFF</code>, which indicates that the
5218 * width of the viewport does not determine the width
5219 * of the table. Otherwise returns true.
5220 *
5221 * @return false if <code>autoResizeMode</code> is set
5222 * to <code>AUTO_RESIZE_OFF</code>, otherwise returns true
5223 * @see Scrollable#getScrollableTracksViewportWidth
5224 */
5225 public boolean getScrollableTracksViewportWidth() {
5226 return !(autoResizeMode == AUTO_RESIZE_OFF);
5227 }
5228
5229 /**
5230 * Returns {@code false} to indicate that the height of the viewport does
5231 * not determine the height of the table, unless
5232 * {@code getFillsViewportHeight} is {@code true} and the preferred height
5233 * of the table is smaller than the viewport's height.
5234 *
5235 * @return {@code false} unless {@code getFillsViewportHeight} is
5236 * {@code true} and the table needs to be stretched to fill
5237 * the viewport
5238 * @see Scrollable#getScrollableTracksViewportHeight
5239 * @see #setFillsViewportHeight
5240 * @see #getFillsViewportHeight
5241 */
5242 public boolean getScrollableTracksViewportHeight() {
5572 setAutoResizeMode(AUTO_RESIZE_SUBSEQUENT_COLUMNS);
5573 setRowHeight(16);
5574 isRowHeightSet = false;
5575 setRowMargin(1);
5576 setRowSelectionAllowed(true);
5577 setCellEditor(null);
5578 setEditingColumn(-1);
5579 setEditingRow(-1);
5580 setSurrendersFocusOnKeystroke(false);
5581 setPreferredScrollableViewportSize(new Dimension(450, 400));
5582
5583 // I'm registered to do tool tips so we can draw tips for the renderers
5584 ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
5585 toolTipManager.registerComponent(this);
5586
5587 setAutoscrolls(true);
5588 }
5589
5590 /**
5591 * Returns the default table model object, which is
5592 * a <code>DefaultTableModel</code>. A subclass can override this
5593 * method to return a different table model object.
5594 *
5595 * @return the default table model object
5596 * @see javax.swing.table.DefaultTableModel
5597 */
5598 protected TableModel createDefaultDataModel() {
5599 return new DefaultTableModel();
5600 }
5601
5602 /**
5603 * Returns the default column model object, which is
5604 * a <code>DefaultTableColumnModel</code>. A subclass can override this
5605 * method to return a different column model object.
5606 *
5607 * @return the default column model object
5608 * @see javax.swing.table.DefaultTableColumnModel
5609 */
5610 protected TableColumnModel createDefaultColumnModel() {
5611 return new DefaultTableColumnModel();
5612 }
5613
5614 /**
5615 * Returns the default selection model object, which is
5616 * a <code>DefaultListSelectionModel</code>. A subclass can override this
5617 * method to return a different selection model object.
5618 *
5619 * @return the default selection model object
5620 * @see javax.swing.DefaultListSelectionModel
5621 */
5622 protected ListSelectionModel createDefaultSelectionModel() {
5623 return new DefaultListSelectionModel();
5624 }
5625
5626 /**
5627 * Returns the default table header object, which is
5628 * a <code>JTableHeader</code>. A subclass can override this
5629 * method to return a different table header object.
5630 *
5631 * @return the default table header object
5632 * @see javax.swing.table.JTableHeader
5633 */
5634 protected JTableHeader createDefaultTableHeader() {
5635 return new JTableHeader(columnModel);
5636 }
5637
5638 /**
5639 * Equivalent to <code>revalidate</code> followed by <code>repaint</code>.
5640 */
5641 protected void resizeAndRepaint() {
5642 revalidate();
5643 repaint();
5644 }
5645
5646 /**
5647 * Returns the active cell editor, which is {@code null} if the table
5648 * is not currently editing.
5649 *
5650 * @return the {@code TableCellEditor} that does the editing,
5651 * or {@code null} if the table is not currently editing.
5652 * @see #cellEditor
5653 * @see #getCellEditor(int, int)
5654 */
5655 public TableCellEditor getCellEditor() {
5656 return cellEditor;
5657 }
5658
5659 /**
5660 * Sets the active cell editor.
5661 *
5662 * @param anEditor the active cell editor
5663 * @see #cellEditor
5664 * @beaninfo
5665 * bound: true
5666 * description: The table's active cell editor.
5667 */
5668 public void setCellEditor(TableCellEditor anEditor) {
5669 TableCellEditor oldEditor = cellEditor;
5670 cellEditor = anEditor;
5671 firePropertyChange("tableCellEditor", oldEditor, anEditor);
5672 }
5673
5674 /**
5675 * Sets the <code>editingColumn</code> variable.
5676 * @param aColumn the column of the cell to be edited
5677 *
5678 * @see #editingColumn
5679 */
5680 public void setEditingColumn(int aColumn) {
5681 editingColumn = aColumn;
5682 }
5683
5684 /**
5685 * Sets the <code>editingRow</code> variable.
5686 * @param aRow the row of the cell to be edited
5687 *
5688 * @see #editingRow
5689 */
5690 public void setEditingRow(int aRow) {
5691 editingRow = aRow;
5692 }
5693
5694 /**
5695 * Returns an appropriate renderer for the cell specified by this row and
5696 * column. If the <code>TableColumn</code> for this column has a non-null
5697 * renderer, returns that. If not, finds the class of the data in
5698 * this column (using <code>getColumnClass</code>)
5699 * and returns the default renderer for this type of data.
5700 * <p>
5701 * <b>Note:</b>
5702 * Throughout the table package, the internal implementations always
5703 * use this method to provide renderers so that this default behavior
5704 * can be safely overridden by a subclass.
5705 *
5706 * @param row the row of the cell to render, where 0 is the first row
5707 * @param column the column of the cell to render,
5708 * where 0 is the first column
5709 * @return the assigned renderer; if <code>null</code>
5710 * returns the default renderer
5711 * for this type of object
5712 * @see javax.swing.table.DefaultTableCellRenderer
5713 * @see javax.swing.table.TableColumn#setCellRenderer
5714 * @see #setDefaultRenderer
5715 */
5716 public TableCellRenderer getCellRenderer(int row, int column) {
5717 TableColumn tableColumn = getColumnModel().getColumn(column);
5718 TableCellRenderer renderer = tableColumn.getCellRenderer();
5719 if (renderer == null) {
5720 renderer = getDefaultRenderer(getColumnClass(column));
5721 }
5722 return renderer;
5723 }
5724
5725 /**
5726 * Prepares the renderer by querying the data model for the
5727 * value and selection state
5728 * of the cell at <code>row</code>, <code>column</code>.
5729 * Returns the component (may be a <code>Component</code>
5730 * or a <code>JComponent</code>) under the event location.
5731 * <p>
5732 * During a printing operation, this method will configure the
5733 * renderer without indicating selection or focus, to prevent
5734 * them from appearing in the printed output. To do other
5735 * customizations based on whether or not the table is being
5736 * printed, you can check the value of
5737 * {@link javax.swing.JComponent#isPaintingForPrint()}, either here
5738 * or within custom renderers.
5739 * <p>
5740 * <b>Note:</b>
5741 * Throughout the table package, the internal implementations always
5742 * use this method to prepare renderers so that this default behavior
5743 * can be safely overridden by a subclass.
5744 *
5745 * @param renderer the <code>TableCellRenderer</code> to prepare
5746 * @param row the row of the cell to render, where 0 is the first row
5747 * @param column the column of the cell to render,
5748 * where 0 is the first column
5749 * @return the <code>Component</code> under the event location
5750 */
5751 public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
5752 Object value = getValueAt(row, column);
5753
5754 boolean isSelected = false;
5755 boolean hasFocus = false;
5756
5757 // Only indicate the selection and focused cell if not printing
5758 if (!isPaintingForPrint()) {
5759 isSelected = isCellSelected(row, column);
5760
5761 boolean rowIsLead =
5762 (selectionModel.getLeadSelectionIndex() == row);
5763 boolean colIsLead =
5764 (columnModel.getSelectionModel().getLeadSelectionIndex() == column);
5765
5766 hasFocus = (rowIsLead && colIsLead) && isFocusOwner();
5767 }
5768
5769 return renderer.getTableCellRendererComponent(this, value,
5770 isSelected, hasFocus,
5771 row, column);
5772 }
5773
5774 /**
5775 * Returns an appropriate editor for the cell specified by
5776 * <code>row</code> and <code>column</code>. If the
5777 * <code>TableColumn</code> for this column has a non-null editor,
5778 * returns that. If not, finds the class of the data in this
5779 * column (using <code>getColumnClass</code>)
5780 * and returns the default editor for this type of data.
5781 * <p>
5782 * <b>Note:</b>
5783 * Throughout the table package, the internal implementations always
5784 * use this method to provide editors so that this default behavior
5785 * can be safely overridden by a subclass.
5786 *
5787 * @param row the row of the cell to edit, where 0 is the first row
5788 * @param column the column of the cell to edit,
5789 * where 0 is the first column
5790 * @return the editor for this cell;
5791 * if <code>null</code> return the default editor for
5792 * this type of cell
5793 * @see DefaultCellEditor
5794 */
5795 public TableCellEditor getCellEditor(int row, int column) {
5796 TableColumn tableColumn = getColumnModel().getColumn(column);
5797 TableCellEditor editor = tableColumn.getCellEditor();
5798 if (editor == null) {
5799 editor = getDefaultEditor(getColumnClass(column));
5800 }
5801 return editor;
5802 }
5803
5804
5805 /**
5806 * Prepares the editor by querying the data model for the value and
5807 * selection state of the cell at <code>row</code>, <code>column</code>.
5808 * <p>
5809 * <b>Note:</b>
5810 * Throughout the table package, the internal implementations always
5811 * use this method to prepare editors so that this default behavior
5812 * can be safely overridden by a subclass.
5813 *
5814 * @param editor the <code>TableCellEditor</code> to set up
5815 * @param row the row of the cell to edit,
5816 * where 0 is the first row
5817 * @param column the column of the cell to edit,
5818 * where 0 is the first column
5819 * @return the <code>Component</code> being edited
5820 */
5821 @SuppressWarnings("deprecation")
5822 public Component prepareEditor(TableCellEditor editor, int row, int column) {
5823 Object value = getValueAt(row, column);
5824 boolean isSelected = isCellSelected(row, column);
5825 Component comp = editor.getTableCellEditorComponent(this, value, isSelected,
5826 row, column);
5827 if (comp instanceof JComponent) {
5828 JComponent jComp = (JComponent)comp;
5829 if (jComp.getNextFocusableComponent() == null) {
5830 jComp.setNextFocusableComponent(this);
5831 }
5832 }
5833 return comp;
5834 }
5835
5836 /**
5837 * Discards the editor object and frees the real estate it used for
5838 * cell rendering.
5839 */
5972 }
5973 }
5974
5975 /* Called from the JComponent's EnableSerializationFocusListener to
5976 * do any Swing-specific pre-serialization configuration.
5977 */
5978 void compWriteObjectNotify() {
5979 super.compWriteObjectNotify();
5980 // If ToolTipText != null, then the tooltip has already been
5981 // unregistered by JComponent.compWriteObjectNotify()
5982 if (getToolTipText() == null) {
5983 ToolTipManager.sharedInstance().unregisterComponent(this);
5984 }
5985 }
5986
5987 /**
5988 * Returns a string representation of this table. This method
5989 * is intended to be used only for debugging purposes, and the
5990 * content and format of the returned string may vary between
5991 * implementations. The returned string may be empty but may not
5992 * be <code>null</code>.
5993 *
5994 * @return a string representation of this table
5995 */
5996 protected String paramString() {
5997 String gridColorString = (gridColor != null ?
5998 gridColor.toString() : "");
5999 String showHorizontalLinesString = (showHorizontalLines ?
6000 "true" : "false");
6001 String showVerticalLinesString = (showVerticalLines ?
6002 "true" : "false");
6003 String autoResizeModeString;
6004 if (autoResizeMode == AUTO_RESIZE_OFF) {
6005 autoResizeModeString = "AUTO_RESIZE_OFF";
6006 } else if (autoResizeMode == AUTO_RESIZE_NEXT_COLUMN) {
6007 autoResizeModeString = "AUTO_RESIZE_NEXT_COLUMN";
6008 } else if (autoResizeMode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) {
6009 autoResizeModeString = "AUTO_RESIZE_SUBSEQUENT_COLUMNS";
6010 } else if (autoResizeMode == AUTO_RESIZE_LAST_COLUMN) {
6011 autoResizeModeString = "AUTO_RESIZE_LAST_COLUMN";
6012 } else if (autoResizeMode == AUTO_RESIZE_ALL_COLUMNS) {
6069 } else if ((c instanceof Window) ||
6070 (c instanceof Applet && c.getParent() == null)) {
6071 if (c == SwingUtilities.getRoot(JTable.this)) {
6072 if (!getCellEditor().stopCellEditing()) {
6073 getCellEditor().cancelCellEditing();
6074 }
6075 }
6076 break;
6077 }
6078 c = c.getParent();
6079 }
6080 }
6081 }
6082
6083 /////////////////
6084 // Printing Support
6085 /////////////////
6086
6087 /**
6088 * A convenience method that displays a printing dialog, and then prints
6089 * this <code>JTable</code> in mode <code>PrintMode.FIT_WIDTH</code>,
6090 * with no header or footer text. A modal progress dialog, with an abort
6091 * option, will be shown for the duration of printing.
6092 * <p>
6093 * Note: In headless mode, no dialogs are shown and printing
6094 * occurs on the default printer.
6095 *
6096 * @return true, unless printing is cancelled by the user
6097 * @throws SecurityException if this thread is not allowed to
6098 * initiate a print job request
6099 * @throws PrinterException if an error in the print system causes the job
6100 * to be aborted
6101 * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6102 * boolean, PrintRequestAttributeSet, boolean, PrintService)
6103 * @see #getPrintable
6104 *
6105 * @since 1.5
6106 */
6107 public boolean print() throws PrinterException {
6108
6109 return print(PrintMode.FIT_WIDTH);
6110 }
6111
6112 /**
6113 * A convenience method that displays a printing dialog, and then prints
6114 * this <code>JTable</code> in the given printing mode,
6115 * with no header or footer text. A modal progress dialog, with an abort
6116 * option, will be shown for the duration of printing.
6117 * <p>
6118 * Note: In headless mode, no dialogs are shown and printing
6119 * occurs on the default printer.
6120 *
6121 * @param printMode the printing mode that the printable should use
6122 * @return true, unless printing is cancelled by the user
6123 * @throws SecurityException if this thread is not allowed to
6124 * initiate a print job request
6125 * @throws PrinterException if an error in the print system causes the job
6126 * to be aborted
6127 * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6128 * boolean, PrintRequestAttributeSet, boolean, PrintService)
6129 * @see #getPrintable
6130 *
6131 * @since 1.5
6132 */
6133 public boolean print(PrintMode printMode) throws PrinterException {
6134
6135 return print(printMode, null, null);
6136 }
6137
6138 /**
6139 * A convenience method that displays a printing dialog, and then prints
6140 * this <code>JTable</code> in the given printing mode,
6141 * with the specified header and footer text. A modal progress dialog,
6142 * with an abort option, will be shown for the duration of printing.
6143 * <p>
6144 * Note: In headless mode, no dialogs are shown and printing
6145 * occurs on the default printer.
6146 *
6147 * @param printMode the printing mode that the printable should use
6148 * @param headerFormat a <code>MessageFormat</code> specifying the text
6149 * to be used in printing a header,
6150 * or null for none
6151 * @param footerFormat a <code>MessageFormat</code> specifying the text
6152 * to be used in printing a footer,
6153 * or null for none
6154 * @return true, unless printing is cancelled by the user
6155 * @throws SecurityException if this thread is not allowed to
6156 * initiate a print job request
6157 * @throws PrinterException if an error in the print system causes the job
6158 * to be aborted
6159 * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6160 * boolean, PrintRequestAttributeSet, boolean, PrintService)
6161 * @see #getPrintable
6162 *
6163 * @since 1.5
6164 */
6165 public boolean print(PrintMode printMode,
6166 MessageFormat headerFormat,
6167 MessageFormat footerFormat) throws PrinterException {
6168
6169 boolean showDialogs = !GraphicsEnvironment.isHeadless();
6170 return print(printMode, headerFormat, footerFormat,
6171 showDialogs, null, showDialogs);
6172 }
6173
6174 /**
6175 * Prints this table, as specified by the fully featured
6176 * {@link #print(JTable.PrintMode, MessageFormat, MessageFormat,
6177 * boolean, PrintRequestAttributeSet, boolean, PrintService) print}
6178 * method, with the default printer specified as the print service.
6179 *
6180 * @param printMode the printing mode that the printable should use
6181 * @param headerFormat a <code>MessageFormat</code> specifying the text
6182 * to be used in printing a header,
6183 * or <code>null</code> for none
6184 * @param footerFormat a <code>MessageFormat</code> specifying the text
6185 * to be used in printing a footer,
6186 * or <code>null</code> for none
6187 * @param showPrintDialog whether or not to display a print dialog
6188 * @param attr a <code>PrintRequestAttributeSet</code>
6189 * specifying any printing attributes,
6190 * or <code>null</code> for none
6191 * @param interactive whether or not to print in an interactive mode
6192 * @return true, unless printing is cancelled by the user
6193 * @throws HeadlessException if the method is asked to show a printing
6194 * dialog or run interactively, and
6195 * <code>GraphicsEnvironment.isHeadless</code>
6196 * returns <code>true</code>
6197 * @throws SecurityException if this thread is not allowed to
6198 * initiate a print job request
6199 * @throws PrinterException if an error in the print system causes the job
6200 * to be aborted
6201 * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6202 * boolean, PrintRequestAttributeSet, boolean, PrintService)
6203 * @see #getPrintable
6204 *
6205 * @since 1.5
6206 */
6207 public boolean print(PrintMode printMode,
6208 MessageFormat headerFormat,
6209 MessageFormat footerFormat,
6210 boolean showPrintDialog,
6211 PrintRequestAttributeSet attr,
6212 boolean interactive) throws PrinterException,
6213 HeadlessException {
6214
6215 return print(printMode,
6216 headerFormat,
6217 footerFormat,
6218 showPrintDialog,
6219 attr,
6220 interactive,
6221 null);
6222 }
6223
6224 /**
6225 * Prints this <code>JTable</code>. Takes steps that the majority of
6226 * developers would take in order to print a <code>JTable</code>.
6227 * In short, it prepares the table, calls <code>getPrintable</code> to
6228 * fetch an appropriate <code>Printable</code>, and then sends it to the
6229 * printer.
6230 * <p>
6231 * A <code>boolean</code> parameter allows you to specify whether or not
6232 * a printing dialog is displayed to the user. When it is, the user may
6233 * use the dialog to change the destination printer or printing attributes,
6234 * or even to cancel the print. Another two parameters allow for a
6235 * <code>PrintService</code> and printing attributes to be specified.
6236 * These parameters can be used either to provide initial values for the
6237 * print dialog, or to specify values when the dialog is not shown.
6238 * <p>
6239 * A second <code>boolean</code> parameter allows you to specify whether
6240 * or not to perform printing in an interactive mode. If <code>true</code>,
6241 * a modal progress dialog, with an abort option, is displayed for the
6242 * duration of printing . This dialog also prevents any user action which
6243 * may affect the table. However, it can not prevent the table from being
6244 * modified by code (for example, another thread that posts updates using
6245 * <code>SwingUtilities.invokeLater</code>). It is therefore the
6246 * responsibility of the developer to ensure that no other code modifies
6247 * the table in any way during printing (invalid modifications include
6248 * changes in: size, renderers, or underlying data). Printing behavior is
6249 * undefined when the table is changed during printing.
6250 * <p>
6251 * If <code>false</code> is specified for this parameter, no dialog will
6252 * be displayed and printing will begin immediately on the event-dispatch
6253 * thread. This blocks any other events, including repaints, from being
6254 * processed until printing is complete. Although this effectively prevents
6255 * the table from being changed, it doesn't provide a good user experience.
6256 * For this reason, specifying <code>false</code> is only recommended when
6257 * printing from an application with no visible GUI.
6258 * <p>
6259 * Note: Attempting to show the printing dialog or run interactively, while
6260 * in headless mode, will result in a <code>HeadlessException</code>.
6261 * <p>
6262 * Before fetching the printable, this method will gracefully terminate
6263 * editing, if necessary, to prevent an editor from showing in the printed
6264 * result. Additionally, <code>JTable</code> will prepare its renderers
6265 * during printing such that selection and focus are not indicated.
6266 * As far as customizing further how the table looks in the printout,
6267 * developers can provide custom renderers or paint code that conditionalize
6268 * on the value of {@link javax.swing.JComponent#isPaintingForPrint()}.
6269 * <p>
6270 * See {@link #getPrintable} for more description on how the table is
6271 * printed.
6272 *
6273 * @param printMode the printing mode that the printable should use
6274 * @param headerFormat a <code>MessageFormat</code> specifying the text
6275 * to be used in printing a header,
6276 * or <code>null</code> for none
6277 * @param footerFormat a <code>MessageFormat</code> specifying the text
6278 * to be used in printing a footer,
6279 * or <code>null</code> for none
6280 * @param showPrintDialog whether or not to display a print dialog
6281 * @param attr a <code>PrintRequestAttributeSet</code>
6282 * specifying any printing attributes,
6283 * or <code>null</code> for none
6284 * @param interactive whether or not to print in an interactive mode
6285 * @param service the destination <code>PrintService</code>,
6286 * or <code>null</code> to use the default printer
6287 * @return true, unless printing is cancelled by the user
6288 * @throws HeadlessException if the method is asked to show a printing
6289 * dialog or run interactively, and
6290 * <code>GraphicsEnvironment.isHeadless</code>
6291 * returns <code>true</code>
6292 * @throws SecurityException if a security manager exists and its
6293 * {@link java.lang.SecurityManager#checkPrintJobAccess}
6294 * method disallows this thread from creating a print job request
6295 * @throws PrinterException if an error in the print system causes the job
6296 * to be aborted
6297 * @see #getPrintable
6298 * @see java.awt.GraphicsEnvironment#isHeadless
6299 *
6300 * @since 1.6
6301 */
6302 public boolean print(PrintMode printMode,
6303 MessageFormat headerFormat,
6304 MessageFormat footerFormat,
6305 boolean showPrintDialog,
6306 PrintRequestAttributeSet attr,
6307 boolean interactive,
6308 PrintService service) throws PrinterException,
6309 HeadlessException {
6310
6311 // complain early if an invalid parameter is specified for headless mode
6419 // a subclass of PrinterException meaning the job was aborted,
6420 // in this case, by the user
6421 if (pe instanceof PrinterAbortException) {
6422 return false;
6423 } else if (pe instanceof PrinterException) {
6424 throw (PrinterException)pe;
6425 } else if (pe instanceof RuntimeException) {
6426 throw (RuntimeException)pe;
6427 } else if (pe instanceof Error) {
6428 throw (Error)pe;
6429 }
6430
6431 // can not happen
6432 throw new AssertionError(pe);
6433 }
6434
6435 return true;
6436 }
6437
6438 /**
6439 * Return a <code>Printable</code> for use in printing this JTable.
6440 * <p>
6441 * This method is meant for those wishing to customize the default
6442 * <code>Printable</code> implementation used by <code>JTable</code>'s
6443 * <code>print</code> methods. Developers wanting simply to print the table
6444 * should use one of those methods directly.
6445 * <p>
6446 * The <code>Printable</code> can be requested in one of two printing modes.
6447 * In both modes, it spreads table rows naturally in sequence across
6448 * multiple pages, fitting as many rows as possible per page.
6449 * <code>PrintMode.NORMAL</code> specifies that the table be
6450 * printed at its current size. In this mode, there may be a need to spread
6451 * columns across pages in a similar manner to that of the rows. When the
6452 * need arises, columns are distributed in an order consistent with the
6453 * table's <code>ComponentOrientation</code>.
6454 * <code>PrintMode.FIT_WIDTH</code> specifies that the output be
6455 * scaled smaller, if necessary, to fit the table's entire width
6456 * (and thereby all columns) on each page. Width and height are scaled
6457 * equally, maintaining the aspect ratio of the output.
6458 * <p>
6459 * The <code>Printable</code> heads the portion of table on each page
6460 * with the appropriate section from the table's <code>JTableHeader</code>,
6461 * if it has one.
6462 * <p>
6463 * Header and footer text can be added to the output by providing
6464 * <code>MessageFormat</code> arguments. The printing code requests
6465 * Strings from the formats, providing a single item which may be included
6466 * in the formatted string: an <code>Integer</code> representing the current
6467 * page number.
6468 * <p>
6469 * You are encouraged to read the documentation for
6470 * <code>MessageFormat</code> as some characters, such as single-quote,
6471 * are special and need to be escaped.
6472 * <p>
6473 * Here's an example of creating a <code>MessageFormat</code> that can be
6474 * used to print "Duke's Table: Page - " and the current page number:
6475 *
6476 * <pre>
6477 * // notice the escaping of the single quote
6478 * // notice how the page number is included with "{0}"
6479 * MessageFormat format = new MessageFormat("Duke''s Table: Page - {0}");
6480 * </pre>
6481 * <p>
6482 * The <code>Printable</code> constrains what it draws to the printable
6483 * area of each page that it prints. Under certain circumstances, it may
6484 * find it impossible to fit all of a page's content into that area. In
6485 * these cases the output may be clipped, but the implementation
6486 * makes an effort to do something reasonable. Here are a few situations
6487 * where this is known to occur, and how they may be handled by this
6488 * particular implementation:
6489 * <ul>
6490 * <li>In any mode, when the header or footer text is too wide to fit
6491 * completely in the printable area -- print as much of the text as
6492 * possible starting from the beginning, as determined by the table's
6493 * <code>ComponentOrientation</code>.
6494 * <li>In any mode, when a row is too tall to fit in the
6495 * printable area -- print the upper-most portion of the row
6496 * and paint no lower border on the table.
6497 * <li>In <code>PrintMode.NORMAL</code> when a column
6498 * is too wide to fit in the printable area -- print the center
6499 * portion of the column and leave the left and right borders
6500 * off the table.
6501 * </ul>
6502 * <p>
6503 * It is entirely valid for this <code>Printable</code> to be wrapped
6504 * inside another in order to create complex reports and documents. You may
6505 * even request that different pages be rendered into different sized
6506 * printable areas. The implementation must be prepared to handle this
6507 * (possibly by doing its layout calculations on the fly). However,
6508 * providing different heights to each page will likely not work well
6509 * with <code>PrintMode.NORMAL</code> when it has to spread columns
6510 * across pages.
6511 * <p>
6512 * As far as customizing how the table looks in the printed result,
6513 * <code>JTable</code> itself will take care of hiding the selection
6514 * and focus during printing. For additional customizations, your
6515 * renderers or painting code can customize the look based on the value
6516 * of {@link javax.swing.JComponent#isPaintingForPrint()}
6517 * <p>
6518 * Also, <i>before</i> calling this method you may wish to <i>first</i>
6519 * modify the state of the table, such as to cancel cell editing or
6520 * have the user size the table appropriately. However, you must not
6521 * modify the state of the table <i>after</i> this <code>Printable</code>
6522 * has been fetched (invalid modifications include changes in size or
6523 * underlying data). The behavior of the returned <code>Printable</code>
6524 * is undefined once the table has been changed.
6525 *
6526 * @param printMode the printing mode that the printable should use
6527 * @param headerFormat a <code>MessageFormat</code> specifying the text to
6528 * be used in printing a header, or null for none
6529 * @param footerFormat a <code>MessageFormat</code> specifying the text to
6530 * be used in printing a footer, or null for none
6531 * @return a <code>Printable</code> for printing this JTable
6532 * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6533 * boolean, PrintRequestAttributeSet, boolean)
6534 * @see Printable
6535 * @see PrinterJob
6536 *
6537 * @since 1.5
6538 */
6539 public Printable getPrintable(PrintMode printMode,
6540 MessageFormat headerFormat,
6541 MessageFormat footerFormat) {
6542
6543 return new TablePrintable(this, printMode, headerFormat, footerFormat);
6544 }
6545
6546
6547 /**
6548 * A <code>Printable</code> implementation that wraps another
6549 * <code>Printable</code>, making it safe for printing on another thread.
6550 */
6551 private class ThreadSafePrintable implements Printable {
6552
6553 /** The delegate <code>Printable</code>. */
6554 private Printable printDelegate;
6555
6556 /**
6557 * To communicate any return value when delegating.
6558 */
6559 private int retVal;
6560
6561 /**
6562 * To communicate any <code>Throwable</code> when delegating.
6563 */
6564 private Throwable retThrowable;
6565
6566 /**
6567 * Construct a <code>ThreadSafePrintable</code> around the given
6568 * delegate.
6569 *
6570 * @param printDelegate the <code>Printable</code> to delegate to
6571 */
6572 public ThreadSafePrintable(Printable printDelegate) {
6573 this.printDelegate = printDelegate;
6574 }
6575
6576 /**
6577 * Prints the specified page into the given {@link Graphics}
6578 * context, in the specified format.
6579 * <p>
6580 * Regardless of what thread this method is called on, all calls into
6581 * the delegate will be done on the event-dispatch thread.
6582 *
6583 * @param graphics the context into which the page is drawn
6584 * @param pageFormat the size and orientation of the page being drawn
6585 * @param pageIndex the zero based index of the page to be drawn
6586 * @return PAGE_EXISTS if the page is rendered successfully, or
6587 * NO_SUCH_PAGE if a non-existent page index is specified
6588 * @throws PrinterException if an error causes printing to be aborted
6589 */
6590 public int print(final Graphics graphics,
6652 * For tables, the AccessibleContext takes the form of an
6653 * AccessibleJTable.
6654 * A new AccessibleJTable instance is created if necessary.
6655 *
6656 * @return an AccessibleJTable that serves as the
6657 * AccessibleContext of this JTable
6658 */
6659 public AccessibleContext getAccessibleContext() {
6660 if (accessibleContext == null) {
6661 accessibleContext = new AccessibleJTable();
6662 }
6663 return accessibleContext;
6664 }
6665
6666 //
6667 // *** should also implement AccessibleSelection?
6668 // *** and what's up with keyboard navigation/manipulation?
6669 //
6670 /**
6671 * This class implements accessibility support for the
6672 * <code>JTable</code> class. It provides an implementation of the
6673 * Java Accessibility API appropriate to table user-interface elements.
6674 * <p>
6675 * <strong>Warning:</strong>
6676 * Serialized objects of this class will not be compatible with
6677 * future Swing releases. The current serialization support is
6678 * appropriate for short term storage or RMI between applications running
6679 * the same version of Swing. As of 1.4, support for long term storage
6680 * of all JavaBeans™
6681 * has been added to the <code>java.beans</code> package.
6682 * Please see {@link java.beans.XMLEncoder}.
6683 */
6684 @SuppressWarnings("serial") // Same-version serialization only
6685 protected class AccessibleJTable extends AccessibleJComponent
6686 implements AccessibleSelection, ListSelectionListener, TableModelListener,
6687 TableColumnModelListener, CellEditorListener, PropertyChangeListener,
6688 AccessibleExtendedTable {
6689
6690 int previousFocusedRow;
6691 int previousFocusedCol;
6692
6693 /**
6694 * AccessibleJTable constructor
6695 *
6696 * @since 1.5
6697 */
6698 protected AccessibleJTable() {
6699 super();
6700 JTable.this.addPropertyChangeListener(this);
6701 JTable.this.getSelectionModel().addListSelectionListener(this);
7102 * AccessibleSelection interface on behalf of itself.
7103 *
7104 * @return this object
7105 */
7106 public AccessibleSelection getAccessibleSelection() {
7107 return this;
7108 }
7109
7110 /**
7111 * Gets the role of this object.
7112 *
7113 * @return an instance of AccessibleRole describing the role of the
7114 * object
7115 * @see AccessibleRole
7116 */
7117 public AccessibleRole getAccessibleRole() {
7118 return AccessibleRole.TABLE;
7119 }
7120
7121 /**
7122 * Returns the <code>Accessible</code> child, if one exists,
7123 * contained at the local coordinate <code>Point</code>.
7124 *
7125 * @param p the point defining the top-left corner of the
7126 * <code>Accessible</code>, given in the coordinate space
7127 * of the object's parent
7128 * @return the <code>Accessible</code>, if it exists,
7129 * at the specified location; else <code>null</code>
7130 */
7131 public Accessible getAccessibleAt(Point p) {
7132 int column = columnAtPoint(p);
7133 int row = rowAtPoint(p);
7134
7135 if ((column != -1) && (row != -1)) {
7136 TableColumn aColumn = getColumnModel().getColumn(column);
7137 TableCellRenderer renderer = aColumn.getCellRenderer();
7138 if (renderer == null) {
7139 Class<?> columnClass = getColumnClass(column);
7140 renderer = getDefaultRenderer(columnClass);
7141 }
7142 Component component = renderer.getTableCellRendererComponent(
7143 JTable.this, null, false, false,
7144 row, column);
7145 return new AccessibleJTableCell(JTable.this, row, column,
7146 getAccessibleIndexAt(row, column));
7147 }
7148 return null;
7149 }
7150
7151 /**
7152 * Returns the number of accessible children in the object. If all
7153 * of the children of this object implement <code>Accessible</code>,
7154 * then this method should return the number of children of this object.
7155 *
7156 * @return the number of accessible children in the object
7157 */
7158 public int getAccessibleChildrenCount() {
7159 return (JTable.this.getColumnCount() * JTable.this.getRowCount());
7160 }
7161
7162 /**
7163 * Returns the nth <code>Accessible</code> child of the object.
7164 *
7165 * @param i zero-based index of child
7166 * @return the nth Accessible child of the object
7167 */
7168 public Accessible getAccessibleChild(int i) {
7169 if (i < 0 || i >= getAccessibleChildrenCount()) {
7170 return null;
7171 } else {
7172 // children increase across, and then down, for tables
7173 // (arbitrary decision)
7174 int column = getAccessibleColumnAtIndex(i);
7175 int row = getAccessibleRowAtIndex(i);
7176
7177 TableColumn aColumn = getColumnModel().getColumn(column);
7178 TableCellRenderer renderer = aColumn.getCellRenderer();
7179 if (renderer == null) {
7180 Class<?> columnClass = getColumnClass(column);
7181 renderer = getDefaultRenderer(columnClass);
7182 }
7183 Component component = renderer.getTableCellRendererComponent(
7184 JTable.this, null, false, false,
7185 row, column);
7186 return new AccessibleJTableCell(JTable.this, row, column,
7187 getAccessibleIndexAt(row, column));
7188 }
7189 }
7190
7191 // AccessibleSelection support
7192
7193 /**
7194 * Returns the number of <code>Accessible</code> children
7195 * currently selected.
7196 * If no children are selected, the return value will be 0.
7197 *
7198 * @return the number of items currently selected
7199 */
7200 public int getAccessibleSelectionCount() {
7201 int rowsSel = JTable.this.getSelectedRowCount();
7202 int colsSel = JTable.this.getSelectedColumnCount();
7203
7204 if (JTable.this.cellSelectionEnabled) { // a contiguous block
7205 return rowsSel * colsSel;
7206
7207 } else {
7208 // a column swath and a row swath, with a shared block
7209 if (JTable.this.getRowSelectionAllowed() &&
7210 JTable.this.getColumnSelectionAllowed()) {
7211 return rowsSel * JTable.this.getColumnCount() +
7212 colsSel * JTable.this.getRowCount() -
7213 rowsSel * colsSel;
7214
7215 // just one or more rows in selection
7216 } else if (JTable.this.getRowSelectionAllowed()) {
7217 return rowsSel * JTable.this.getColumnCount();
7218
7219 // just one or more rows in selection
7220 } else if (JTable.this.getColumnSelectionAllowed()) {
7221 return colsSel * JTable.this.getRowCount();
7222
7223 } else {
7224 return 0; // JTable doesn't allow selections
7225 }
7226 }
7227 }
7228
7229 /**
7230 * Returns an <code>Accessible</code> representing the
7231 * specified selected child in the object. If there
7232 * isn't a selection, or there are fewer children selected
7233 * than the integer passed in, the return
7234 * value will be <code>null</code>.
7235 * <p>Note that the index represents the i-th selected child, which
7236 * is different from the i-th child.
7237 *
7238 * @param i the zero-based index of selected children
7239 * @return the i-th selected child
7240 * @see #getAccessibleSelectionCount
7241 */
7242 public Accessible getAccessibleSelection(int i) {
7243 if (i < 0 || i > getAccessibleSelectionCount()) {
7244 return null;
7245 }
7246
7247 int rowsSel = JTable.this.getSelectedRowCount();
7248 int colsSel = JTable.this.getSelectedColumnCount();
7249 int rowIndicies[] = getSelectedRows();
7250 int colIndicies[] = getSelectedColumns();
7251 int ttlCols = JTable.this.getColumnCount();
7252 int ttlRows = JTable.this.getRowCount();
7253 int r;
7254 int c;
7344 // one or more rows selected
7345 } else if (JTable.this.getRowSelectionAllowed()) {
7346 c = i % ttlCols;
7347 r = rowIndicies[i / ttlCols];
7348 return getAccessibleChild((r * ttlCols) + c);
7349
7350 // one or more columns selected
7351 } else if (JTable.this.getColumnSelectionAllowed()) {
7352 c = colIndicies[i % colsSel];
7353 r = i / colsSel;
7354 return getAccessibleChild((r * ttlCols) + c);
7355 }
7356 }
7357 return null;
7358 }
7359
7360 /**
7361 * Determines if the current child of this object is selected.
7362 *
7363 * @param i the zero-based index of the child in this
7364 * <code>Accessible</code> object
7365 * @return true if the current child of this object is selected
7366 * @see AccessibleContext#getAccessibleChild
7367 */
7368 public boolean isAccessibleChildSelected(int i) {
7369 int column = getAccessibleColumnAtIndex(i);
7370 int row = getAccessibleRowAtIndex(i);
7371 return JTable.this.isCellSelected(row, column);
7372 }
7373
7374 /**
7375 * Adds the specified <code>Accessible</code> child of the
7376 * object to the object's selection. If the object supports
7377 * multiple selections, the specified child is added to
7378 * any existing selection, otherwise
7379 * it replaces any existing selection in the object. If the
7380 * specified child is already selected, this method has no effect.
7381 * <p>
7382 * This method only works on <code>JTable</code>s which have
7383 * individual cell selection enabled.
7384 *
7385 * @param i the zero-based index of the child
7386 * @see AccessibleContext#getAccessibleChild
7387 */
7388 public void addAccessibleSelection(int i) {
7389 // TIGER - 4495286
7390 int column = getAccessibleColumnAtIndex(i);
7391 int row = getAccessibleRowAtIndex(i);
7392 JTable.this.changeSelection(row, column, true, false);
7393 }
7394
7395 /**
7396 * Removes the specified child of the object from the object's
7397 * selection. If the specified item isn't currently selected, this
7398 * method has no effect.
7399 * <p>
7400 * This method only works on <code>JTables</code> which have
7401 * individual cell selection enabled.
7402 *
7403 * @param i the zero-based index of the child
7404 * @see AccessibleContext#getAccessibleChild
7405 */
7406 public void removeAccessibleSelection(int i) {
7407 if (JTable.this.cellSelectionEnabled) {
7408 int column = getAccessibleColumnAtIndex(i);
7409 int row = getAccessibleRowAtIndex(i);
7410 JTable.this.removeRowSelectionInterval(row, row);
7411 JTable.this.removeColumnSelectionInterval(column, column);
7412 }
7413 }
7414
7415 /**
7416 * Clears the selection in the object, so that no children in the
7417 * object are selected.
7418 */
7419 public void clearAccessibleSelection() {
7420 JTable.this.clearSelection();
7421 }
7422
7423 /**
7424 * Causes every child of the object to be selected, but only
7425 * if the <code>JTable</code> supports multiple selections,
7426 * and if individual cell selection is enabled.
7427 */
7428 public void selectAllAccessibleSelection() {
7429 if (JTable.this.cellSelectionEnabled) {
7430 JTable.this.selectAll();
7431 }
7432 }
7433
7434 // begin AccessibleExtendedTable implementation -------------
7435
7436 /**
7437 * Returns the row number of an index in the table.
7438 *
7439 * @param index the zero-based index in the table
7440 * @return the zero-based row of the table if one exists;
7441 * otherwise -1.
7442 * @since 1.4
7443 */
7444 public int getAccessibleRow(int index) {
7445 return getAccessibleRowAtIndex(index);
7463 * @param r zero-based row of the table
7464 * @param c zero-based column of the table
7465 * @return the zero-based index in the table if one exists;
7466 * otherwise -1.
7467 * @since 1.4
7468 */
7469 public int getAccessibleIndex(int r, int c) {
7470 return getAccessibleIndexAt(r, c);
7471 }
7472
7473 // end of AccessibleExtendedTable implementation ------------
7474
7475 // start of AccessibleTable implementation ------------------
7476
7477 private Accessible caption;
7478 private Accessible summary;
7479 private Accessible [] rowDescription;
7480 private Accessible [] columnDescription;
7481
7482 /**
7483 * Gets the <code>AccessibleTable</code> associated with this
7484 * object. In the implementation of the Java Accessibility
7485 * API for this class, return this object, which is responsible
7486 * for implementing the <code>AccessibleTables</code> interface
7487 * on behalf of itself.
7488 *
7489 * @return this object
7490 * @since 1.3
7491 */
7492 public AccessibleTable getAccessibleTable() {
7493 return this;
7494 }
7495
7496 /**
7497 * Returns the caption for the table.
7498 *
7499 * @return the caption for the table
7500 * @since 1.3
7501 */
7502 public Accessible getAccessibleCaption() {
7503 return this.caption;
7504 }
7505
7506 /**
7541
7542 /*
7543 * Returns the total number of rows in this table.
7544 *
7545 * @return the total number of rows in this table
7546 */
7547 public int getAccessibleRowCount() {
7548 return JTable.this.getRowCount();
7549 }
7550
7551 /*
7552 * Returns the total number of columns in the table.
7553 *
7554 * @return the total number of columns in the table
7555 */
7556 public int getAccessibleColumnCount() {
7557 return JTable.this.getColumnCount();
7558 }
7559
7560 /*
7561 * Returns the <code>Accessible</code> at a specified row
7562 * and column in the table.
7563 *
7564 * @param r zero-based row of the table
7565 * @param c zero-based column of the table
7566 * @return the <code>Accessible</code> at the specified row and column
7567 * in the table
7568 */
7569 public Accessible getAccessibleAt(int r, int c) {
7570 return getAccessibleChild((r * getAccessibleColumnCount()) + c);
7571 }
7572
7573 /**
7574 * Returns the number of rows occupied by the <code>Accessible</code>
7575 * at a specified row and column in the table.
7576 *
7577 * @return the number of rows occupied by the <code>Accessible</code>
7578 * at a specified row and column in the table
7579 * @since 1.3
7580 */
7581 public int getAccessibleRowExtentAt(int r, int c) {
7582 return 1;
7583 }
7584
7585 /**
7586 * Returns the number of columns occupied by the
7587 * <code>Accessible</code> at a given (row, column).
7588 *
7589 * @return the number of columns occupied by the <code>Accessible</code>
7590 * at a specified row and column in the table
7591 * @since 1.3
7592 */
7593 public int getAccessibleColumnExtentAt(int r, int c) {
7594 return 1;
7595 }
7596
7597 /**
7598 * Returns the row headers as an <code>AccessibleTable</code>.
7599 *
7600 * @return an <code>AccessibleTable</code> representing the row
7601 * headers
7602 * @since 1.3
7603 */
7604 public AccessibleTable getAccessibleRowHeader() {
7605 // row headers are not supported
7606 return null;
7607 }
7608
7609 /**
7610 * Sets the row headers as an <code>AccessibleTable</code>.
7611 *
7612 * @param a an <code>AccessibleTable</code> representing the row
7613 * headers
7614 * @since 1.3
7615 */
7616 public void setAccessibleRowHeader(AccessibleTable a) {
7617 // row headers are not supported
7618 }
7619
7620 /**
7621 * Returns the column headers as an <code>AccessibleTable</code>.
7622 *
7623 * @return an <code>AccessibleTable</code> representing the column
7624 * headers, or <code>null</code> if the table header is
7625 * <code>null</code>
7626 * @since 1.3
7627 */
7628 public AccessibleTable getAccessibleColumnHeader() {
7629 JTableHeader header = JTable.this.getTableHeader();
7630 return header == null ? null : new AccessibleTableHeader(header);
7631 }
7632
7633 /*
7634 * Private class representing a table column header
7635 */
7636 private class AccessibleTableHeader implements AccessibleTable {
7637 private JTableHeader header;
7638 private TableColumnModel headerModel;
7639
7640 AccessibleTableHeader(JTableHeader header) {
7641 this.header = header;
7642 this.headerModel = header.getColumnModel();
7643 }
7644
7645 /**
7840 * Returns the selected rows in a table.
7841 *
7842 * @return an array of selected rows where each element is a
7843 * zero-based row of the table
7844 * @since 1.3
7845 */
7846 public int [] getSelectedAccessibleRows() { return new int[0]; }
7847
7848 /**
7849 * Returns the selected columns in a table.
7850 *
7851 * @return an array of selected columns where each element is a
7852 * zero-based column of the table
7853 * @since 1.3
7854 */
7855 public int [] getSelectedAccessibleColumns() { return new int[0]; }
7856 }
7857
7858
7859 /**
7860 * Sets the column headers as an <code>AccessibleTable</code>.
7861 *
7862 * @param a an <code>AccessibleTable</code> representing the
7863 * column headers
7864 * @since 1.3
7865 */
7866 public void setAccessibleColumnHeader(AccessibleTable a) {
7867 // XXX not implemented
7868 }
7869
7870 /**
7871 * Returns the description of the specified row in the table.
7872 *
7873 * @param r zero-based row of the table
7874 * @return the description of the row
7875 * @since 1.3
7876 */
7877 public Accessible getAccessibleRowDescription(int r) {
7878 if (r < 0 || r >= getAccessibleRowCount()) {
7879 throw new IllegalArgumentException(Integer.toString(r));
7880 }
7881 if (rowDescription == null) {
7882 return null;
8043 */
8044 public int getAccessibleIndexAt(int r, int c) {
8045 return ((r * getAccessibleColumnCount()) + c);
8046 }
8047
8048 // end of AccessibleTable implementation --------------------
8049
8050 /**
8051 * The class provides an implementation of the Java Accessibility
8052 * API appropriate to table cells.
8053 */
8054 protected class AccessibleJTableCell extends AccessibleContext
8055 implements Accessible, AccessibleComponent {
8056
8057 private JTable parent;
8058 private int row;
8059 private int column;
8060 private int index;
8061
8062 /**
8063 * Constructs an <code>AccessibleJTableHeaderEntry</code>.
8064 *
8065 * @param t a {@code JTable}
8066 * @param r an {@code int} specifying a row
8067 * @param c an {@code int} specifying a column
8068 * @param i an {@code int} specifying the index to this cell
8069 * @since 1.4
8070 */
8071 public AccessibleJTableCell(JTable t, int r, int c, int i) {
8072 parent = t;
8073 row = r;
8074 column = c;
8075 index = i;
8076 this.setAccessibleParent(parent);
8077 }
8078
8079 /**
8080 * Gets the <code>AccessibleContext</code> associated with this
8081 * component. In the implementation of the Java Accessibility
8082 * API for this class, return this object, which is its own
8083 * <code>AccessibleContext</code>.
8084 *
8085 * @return this object
8086 */
8087 public AccessibleContext getAccessibleContext() {
8088 return this;
8089 }
8090
8091 /**
8092 * Gets the AccessibleContext for the table cell renderer.
8093 *
8094 * @return the <code>AccessibleContext</code> for the table
8095 * cell renderer if one exists;
8096 * otherwise, returns <code>null</code>.
8097 * @since 1.6
8098 */
8099 protected AccessibleContext getCurrentAccessibleContext() {
8100 TableColumn aColumn = getColumnModel().getColumn(column);
8101 TableCellRenderer renderer = aColumn.getCellRenderer();
8102 if (renderer == null) {
8103 Class<?> columnClass = getColumnClass(column);
8104 renderer = getDefaultRenderer(columnClass);
8105 }
8106 Component component = renderer.getTableCellRendererComponent(
8107 JTable.this, getValueAt(row, column),
8108 false, false, row, column);
8109 if (component instanceof Accessible) {
8110 return component.getAccessibleContext();
8111 } else {
8112 return null;
8113 }
8114 }
8115
8116 /**
8117 * Gets the table cell renderer component.
8118 *
8119 * @return the table cell renderer component if one exists;
8120 * otherwise, returns <code>null</code>.
8121 * @since 1.6
8122 */
8123 protected Component getCurrentComponent() {
8124 TableColumn aColumn = getColumnModel().getColumn(column);
8125 TableCellRenderer renderer = aColumn.getCellRenderer();
8126 if (renderer == null) {
8127 Class<?> columnClass = getColumnClass(column);
8128 renderer = getDefaultRenderer(columnClass);
8129 }
8130 return renderer.getTableCellRendererComponent(
8131 JTable.this, null, false, false,
8132 row, column);
8133 }
8134
8135 // AccessibleContext methods
8136
8137 /**
8138 * Gets the accessible name of this object.
8139 *
8140 * @return the localized name of the object; <code>null</code>
8141 * if this object does not have a name
8142 */
8143 public String getAccessibleName() {
8144 AccessibleContext ac = getCurrentAccessibleContext();
8145 if (ac != null) {
8146 String name = ac.getAccessibleName();
8147 if ((name != null) && (name != "")) {
8148 // return the cell renderer's AccessibleName
8149 return name;
8150 }
8151 }
8152 if ((accessibleName != null) && (accessibleName != "")) {
8153 return accessibleName;
8154 } else {
8155 // fall back to the client property
8156 return (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
8157 }
8158 }
8159
8160 /**
8161 * Sets the localized accessible name of this object.
8162 *
8163 * @param s the new localized name of the object
8164 */
8165 public void setAccessibleName(String s) {
8166 AccessibleContext ac = getCurrentAccessibleContext();
8167 if (ac != null) {
8168 ac.setAccessibleName(s);
8169 } else {
8170 super.setAccessibleName(s);
8171 }
8172 }
8173
8174 //
8175 // *** should check toolTip text for desc. (needs MouseEvent)
8176 //
8177 /**
8178 * Gets the accessible description of this object.
8179 *
8180 * @return the localized description of the object;
8181 * <code>null</code> if this object does not have
8182 * a description
8183 */
8184 public String getAccessibleDescription() {
8185 AccessibleContext ac = getCurrentAccessibleContext();
8186 if (ac != null) {
8187 return ac.getAccessibleDescription();
8188 } else {
8189 return super.getAccessibleDescription();
8190 }
8191 }
8192
8193 /**
8194 * Sets the accessible description of this object.
8195 *
8196 * @param s the new localized description of the object
8197 */
8198 public void setAccessibleDescription(String s) {
8199 AccessibleContext ac = getCurrentAccessibleContext();
8200 if (ac != null) {
8201 ac.setAccessibleDescription(s);
8202 } else {
8203 super.setAccessibleDescription(s);
8204 }
8205 }
8206
8207 /**
8208 * Gets the role of this object.
8209 *
8210 * @return an instance of <code>AccessibleRole</code>
8211 * describing the role of the object
8212 * @see AccessibleRole
8213 */
8214 public AccessibleRole getAccessibleRole() {
8215 AccessibleContext ac = getCurrentAccessibleContext();
8216 if (ac != null) {
8217 return ac.getAccessibleRole();
8218 } else {
8219 return AccessibleRole.UNKNOWN;
8220 }
8221 }
8222
8223 /**
8224 * Gets the state set of this object.
8225 *
8226 * @return an instance of <code>AccessibleStateSet</code>
8227 * containing the current state set of the object
8228 * @see AccessibleState
8229 */
8230 public AccessibleStateSet getAccessibleStateSet() {
8231 AccessibleContext ac = getCurrentAccessibleContext();
8232 AccessibleStateSet as = null;
8233
8234 if (ac != null) {
8235 as = ac.getAccessibleStateSet();
8236 }
8237 if (as == null) {
8238 as = new AccessibleStateSet();
8239 }
8240 Rectangle rjt = JTable.this.getVisibleRect();
8241 Rectangle rcell = JTable.this.getCellRect(row, column, false);
8242 if (rjt.intersects(rcell)) {
8243 as.add(AccessibleState.SHOWING);
8244 } else {
8245 if (as.contains(AccessibleState.SHOWING)) {
8246 as.remove(AccessibleState.SHOWING);
8247 }
8248 }
8249 if (parent.isCellSelected(row, column)) {
8250 as.add(AccessibleState.SELECTED);
8251 } else if (as.contains(AccessibleState.SELECTED)) {
8252 as.remove(AccessibleState.SELECTED);
8253 }
8254 if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
8255 as.add(AccessibleState.ACTIVE);
8256 }
8257 as.add(AccessibleState.TRANSIENT);
8258 return as;
8259 }
8260
8261 /**
8262 * Gets the <code>Accessible</code> parent of this object.
8263 *
8264 * @return the Accessible parent of this object;
8265 * <code>null</code> if this object does not
8266 * have an <code>Accessible</code> parent
8267 */
8268 public Accessible getAccessibleParent() {
8269 return parent;
8270 }
8271
8272 /**
8273 * Gets the index of this object in its accessible parent.
8274 *
8275 * @return the index of this object in its parent; -1 if this
8276 * object does not have an accessible parent
8277 * @see #getAccessibleParent
8278 */
8279 public int getAccessibleIndexInParent() {
8280 return index;
8281 }
8282
8283 /**
8284 * Returns the number of accessible children in the object.
8285 *
8286 * @return the number of accessible children in the object
8287 */
8288 public int getAccessibleChildrenCount() {
8289 AccessibleContext ac = getCurrentAccessibleContext();
8290 if (ac != null) {
8291 return ac.getAccessibleChildrenCount();
8292 } else {
8293 return 0;
8294 }
8295 }
8296
8297 /**
8298 * Returns the specified <code>Accessible</code> child of the
8299 * object.
8300 *
8301 * @param i zero-based index of child
8302 * @return the <code>Accessible</code> child of the object
8303 */
8304 public Accessible getAccessibleChild(int i) {
8305 AccessibleContext ac = getCurrentAccessibleContext();
8306 if (ac != null) {
8307 Accessible accessibleChild = ac.getAccessibleChild(i);
8308 ac.setAccessibleParent(this);
8309 return accessibleChild;
8310 } else {
8311 return null;
8312 }
8313 }
8314
8315 /**
8316 * Gets the locale of the component. If the component
8317 * does not have a locale, then the locale of its parent
8318 * is returned.
8319 *
8320 * @return this component's locale; if this component does
8321 * not have a locale, the locale of its parent is returned
8322 * @exception IllegalComponentStateException if the
8323 * <code>Component</code> does not have its own locale
8324 * and has not yet been added to a containment hierarchy
8325 * such that the locale can be determined from the
8326 * containing parent
8327 * @see #setLocale
8328 */
8329 public Locale getLocale() {
8330 AccessibleContext ac = getCurrentAccessibleContext();
8331 if (ac != null) {
8332 return ac.getLocale();
8333 } else {
8334 return null;
8335 }
8336 }
8337
8338 /**
8339 * Adds a <code>PropertyChangeListener</code> to the listener list.
8340 * The listener is registered for all properties.
8341 *
8342 * @param l the <code>PropertyChangeListener</code>
8343 * to be added
8344 */
8345 public void addPropertyChangeListener(PropertyChangeListener l) {
8346 AccessibleContext ac = getCurrentAccessibleContext();
8347 if (ac != null) {
8348 ac.addPropertyChangeListener(l);
8349 } else {
8350 super.addPropertyChangeListener(l);
8351 }
8352 }
8353
8354 /**
8355 * Removes a <code>PropertyChangeListener</code> from the
8356 * listener list. This removes a <code>PropertyChangeListener</code>
8357 * that was registered for all properties.
8358 *
8359 * @param l the <code>PropertyChangeListener</code>
8360 * to be removed
8361 */
8362 public void removePropertyChangeListener(PropertyChangeListener l) {
8363 AccessibleContext ac = getCurrentAccessibleContext();
8364 if (ac != null) {
8365 ac.removePropertyChangeListener(l);
8366 } else {
8367 super.removePropertyChangeListener(l);
8368 }
8369 }
8370
8371 /**
8372 * Gets the <code>AccessibleAction</code> associated with this
8373 * object if one exists. Otherwise returns <code>null</code>.
8374 *
8375 * @return the <code>AccessibleAction</code>, or <code>null</code>
8376 */
8377 public AccessibleAction getAccessibleAction() {
8378 return getCurrentAccessibleContext().getAccessibleAction();
8379 }
8380
8381 /**
8382 * Gets the <code>AccessibleComponent</code> associated with
8383 * this object if one exists. Otherwise returns <code>null</code>.
8384 *
8385 * @return the <code>AccessibleComponent</code>, or
8386 * <code>null</code>
8387 */
8388 public AccessibleComponent getAccessibleComponent() {
8389 return this; // to override getBounds()
8390 }
8391
8392 /**
8393 * Gets the <code>AccessibleSelection</code> associated with
8394 * this object if one exists. Otherwise returns <code>null</code>.
8395 *
8396 * @return the <code>AccessibleSelection</code>, or
8397 * <code>null</code>
8398 */
8399 public AccessibleSelection getAccessibleSelection() {
8400 return getCurrentAccessibleContext().getAccessibleSelection();
8401 }
8402
8403 /**
8404 * Gets the <code>AccessibleText</code> associated with this
8405 * object if one exists. Otherwise returns <code>null</code>.
8406 *
8407 * @return the <code>AccessibleText</code>, or <code>null</code>
8408 */
8409 public AccessibleText getAccessibleText() {
8410 return getCurrentAccessibleContext().getAccessibleText();
8411 }
8412
8413 /**
8414 * Gets the <code>AccessibleValue</code> associated with
8415 * this object if one exists. Otherwise returns <code>null</code>.
8416 *
8417 * @return the <code>AccessibleValue</code>, or <code>null</code>
8418 */
8419 public AccessibleValue getAccessibleValue() {
8420 return getCurrentAccessibleContext().getAccessibleValue();
8421 }
8422
8423
8424 // AccessibleComponent methods
8425
8426 /**
8427 * Gets the background color of this object.
8428 *
8429 * @return the background color, if supported, of the object;
8430 * otherwise, <code>null</code>
8431 */
8432 public Color getBackground() {
8433 AccessibleContext ac = getCurrentAccessibleContext();
8434 if (ac instanceof AccessibleComponent) {
8435 return ((AccessibleComponent) ac).getBackground();
8436 } else {
8437 Component c = getCurrentComponent();
8438 if (c != null) {
8439 return c.getBackground();
8440 } else {
8441 return null;
8442 }
8443 }
8444 }
8445
8446 /**
8447 * Sets the background color of this object.
8448 *
8449 * @param c the new <code>Color</code> for the background
8450 */
8451 public void setBackground(Color c) {
8452 AccessibleContext ac = getCurrentAccessibleContext();
8453 if (ac instanceof AccessibleComponent) {
8454 ((AccessibleComponent) ac).setBackground(c);
8455 } else {
8456 Component cp = getCurrentComponent();
8457 if (cp != null) {
8458 cp.setBackground(c);
8459 }
8460 }
8461 }
8462
8463 /**
8464 * Gets the foreground color of this object.
8465 *
8466 * @return the foreground color, if supported, of the object;
8467 * otherwise, <code>null</code>
8468 */
8469 public Color getForeground() {
8470 AccessibleContext ac = getCurrentAccessibleContext();
8471 if (ac instanceof AccessibleComponent) {
8472 return ((AccessibleComponent) ac).getForeground();
8473 } else {
8474 Component c = getCurrentComponent();
8475 if (c != null) {
8476 return c.getForeground();
8477 } else {
8478 return null;
8479 }
8480 }
8481 }
8482
8483 /**
8484 * Sets the foreground color of this object.
8485 *
8486 * @param c the new <code>Color</code> for the foreground
8487 */
8488 public void setForeground(Color c) {
8489 AccessibleContext ac = getCurrentAccessibleContext();
8490 if (ac instanceof AccessibleComponent) {
8491 ((AccessibleComponent) ac).setForeground(c);
8492 } else {
8493 Component cp = getCurrentComponent();
8494 if (cp != null) {
8495 cp.setForeground(c);
8496 }
8497 }
8498 }
8499
8500 /**
8501 * Gets the <code>Cursor</code> of this object.
8502 *
8503 * @return the <code>Cursor</code>, if supported,
8504 * of the object; otherwise, <code>null</code>
8505 */
8506 public Cursor getCursor() {
8507 AccessibleContext ac = getCurrentAccessibleContext();
8508 if (ac instanceof AccessibleComponent) {
8509 return ((AccessibleComponent) ac).getCursor();
8510 } else {
8511 Component c = getCurrentComponent();
8512 if (c != null) {
8513 return c.getCursor();
8514 } else {
8515 Accessible ap = getAccessibleParent();
8516 if (ap instanceof AccessibleComponent) {
8517 return ((AccessibleComponent) ap).getCursor();
8518 } else {
8519 return null;
8520 }
8521 }
8522 }
8523 }
8524
8525 /**
8526 * Sets the <code>Cursor</code> of this object.
8527 *
8528 * @param c the new <code>Cursor</code> for the object
8529 */
8530 public void setCursor(Cursor c) {
8531 AccessibleContext ac = getCurrentAccessibleContext();
8532 if (ac instanceof AccessibleComponent) {
8533 ((AccessibleComponent) ac).setCursor(c);
8534 } else {
8535 Component cp = getCurrentComponent();
8536 if (cp != null) {
8537 cp.setCursor(c);
8538 }
8539 }
8540 }
8541
8542 /**
8543 * Gets the <code>Font</code> of this object.
8544 *
8545 * @return the <code>Font</code>,if supported,
8546 * for the object; otherwise, <code>null</code>
8547 */
8548 public Font getFont() {
8549 AccessibleContext ac = getCurrentAccessibleContext();
8550 if (ac instanceof AccessibleComponent) {
8551 return ((AccessibleComponent) ac).getFont();
8552 } else {
8553 Component c = getCurrentComponent();
8554 if (c != null) {
8555 return c.getFont();
8556 } else {
8557 return null;
8558 }
8559 }
8560 }
8561
8562 /**
8563 * Sets the <code>Font</code> of this object.
8564 *
8565 * @param f the new <code>Font</code> for the object
8566 */
8567 public void setFont(Font f) {
8568 AccessibleContext ac = getCurrentAccessibleContext();
8569 if (ac instanceof AccessibleComponent) {
8570 ((AccessibleComponent) ac).setFont(f);
8571 } else {
8572 Component c = getCurrentComponent();
8573 if (c != null) {
8574 c.setFont(f);
8575 }
8576 }
8577 }
8578
8579 /**
8580 * Gets the <code>FontMetrics</code> of this object.
8581 *
8582 * @param f the <code>Font</code>
8583 * @return the <code>FontMetrics</code> object, if supported;
8584 * otherwise <code>null</code>
8585 * @see #getFont
8586 */
8587 public FontMetrics getFontMetrics(Font f) {
8588 AccessibleContext ac = getCurrentAccessibleContext();
8589 if (ac instanceof AccessibleComponent) {
8590 return ((AccessibleComponent) ac).getFontMetrics(f);
8591 } else {
8592 Component c = getCurrentComponent();
8593 if (c != null) {
8594 return c.getFontMetrics(f);
8595 } else {
8596 return null;
8597 }
8598 }
8599 }
8600
8601 /**
8602 * Determines if the object is enabled.
8603 *
8604 * @return true if object is enabled; otherwise, false
8622 *
8623 * @param b if true, enables this object; otherwise, disables it
8624 */
8625 public void setEnabled(boolean b) {
8626 AccessibleContext ac = getCurrentAccessibleContext();
8627 if (ac instanceof AccessibleComponent) {
8628 ((AccessibleComponent) ac).setEnabled(b);
8629 } else {
8630 Component c = getCurrentComponent();
8631 if (c != null) {
8632 c.setEnabled(b);
8633 }
8634 }
8635 }
8636
8637 /**
8638 * Determines if this object is visible. Note: this means that the
8639 * object intends to be visible; however, it may not in fact be
8640 * showing on the screen because one of the objects that this object
8641 * is contained by is not visible. To determine if an object is
8642 * showing on the screen, use <code>isShowing</code>.
8643 *
8644 * @return true if object is visible; otherwise, false
8645 */
8646 public boolean isVisible() {
8647 AccessibleContext ac = getCurrentAccessibleContext();
8648 if (ac instanceof AccessibleComponent) {
8649 return ((AccessibleComponent) ac).isVisible();
8650 } else {
8651 Component c = getCurrentComponent();
8652 if (c != null) {
8653 return c.isVisible();
8654 } else {
8655 return false;
8656 }
8657 }
8658 }
8659
8660 /**
8661 * Sets the visible state of the object.
8662 *
8693 // returns false when the cell on the screen
8694 // if no parent
8695 return isVisible();
8696 }
8697 } else {
8698 Component c = getCurrentComponent();
8699 if (c != null) {
8700 return c.isShowing();
8701 } else {
8702 return false;
8703 }
8704 }
8705 }
8706
8707 /**
8708 * Checks whether the specified point is within this
8709 * object's bounds, where the point's x and y coordinates
8710 * are defined to be relative to the coordinate system of
8711 * the object.
8712 *
8713 * @param p the <code>Point</code> relative to the
8714 * coordinate system of the object
8715 * @return true if object contains <code>Point</code>;
8716 * otherwise false
8717 */
8718 public boolean contains(Point p) {
8719 AccessibleContext ac = getCurrentAccessibleContext();
8720 if (ac instanceof AccessibleComponent) {
8721 Rectangle r = ((AccessibleComponent) ac).getBounds();
8722 return r.contains(p);
8723 } else {
8724 Component c = getCurrentComponent();
8725 if (c != null) {
8726 Rectangle r = c.getBounds();
8727 return r.contains(p);
8728 } else {
8729 return getBounds().contains(p);
8730 }
8731 }
8732 }
8733
8734 /**
8735 * Returns the location of the object on the screen.
8736 *
8737 * @return location of object on screen -- can be
8738 * <code>null</code> if this object is not on the screen
8739 */
8740 public Point getLocationOnScreen() {
8741 if (parent != null && parent.isShowing()) {
8742 Point parentLocation = parent.getLocationOnScreen();
8743 Point componentLocation = getLocation();
8744 componentLocation.translate(parentLocation.x, parentLocation.y);
8745 return componentLocation;
8746 } else {
8747 return null;
8748 }
8749 }
8750
8751 /**
8752 * Gets the location of the object relative to the parent
8753 * in the form of a point specifying the object's
8754 * top-left corner in the screen's coordinate space.
8755 *
8756 * @return an instance of <code>Point</code> representing
8757 * the top-left corner of the object's bounds in the
8758 * coordinate space of the screen; <code>null</code> if
8759 * this object or its parent are not on the screen
8760 */
8761 public Point getLocation() {
8762 if (parent != null) {
8763 Rectangle r = parent.getCellRect(row, column, false);
8764 if (r != null) {
8765 return r.getLocation();
8766 }
8767 }
8768 return null;
8769 }
8770
8771 /**
8772 * Sets the location of the object relative to the parent.
8773 */
8774 public void setLocation(Point p) {
8775 // if ((parent != null) && (parent.contains(p))) {
8776 // ensureIndexIsVisible(indexInParent);
8777 // }
8778 }
8878 }
8879 }
8880 }
8881
8882 } // inner class AccessibleJTableCell
8883
8884 // Begin AccessibleJTableHeader ========== // TIGER - 4715503
8885
8886 /**
8887 * This class implements accessibility for JTable header cells.
8888 */
8889 private class AccessibleJTableHeaderCell extends AccessibleContext
8890 implements Accessible, AccessibleComponent {
8891
8892 private int row;
8893 private int column;
8894 private JTableHeader parent;
8895 private Component rendererComponent;
8896
8897 /**
8898 * Constructs an <code>AccessibleJTableHeaderEntry</code> instance.
8899 *
8900 * @param row header cell row index
8901 * @param column header cell column index
8902 * @param parent header cell parent
8903 * @param rendererComponent component that renders the header cell
8904 */
8905 public AccessibleJTableHeaderCell(int row, int column,
8906 JTableHeader parent,
8907 Component rendererComponent) {
8908 this.row = row;
8909 this.column = column;
8910 this.parent = parent;
8911 this.rendererComponent = rendererComponent;
8912 this.setAccessibleParent(parent);
8913 }
8914
8915 /**
8916 * Gets the <code>AccessibleContext</code> associated with this
8917 * component. In the implementation of the Java Accessibility
8918 * API for this class, return this object, which is its own
8919 * <code>AccessibleContext</code>.
8920 *
8921 * @return this object
8922 */
8923 public AccessibleContext getAccessibleContext() {
8924 return this;
8925 }
8926
8927 /*
8928 * Returns the AccessibleContext for the header cell
8929 * renderer.
8930 */
8931 private AccessibleContext getCurrentAccessibleContext() {
8932 return rendererComponent.getAccessibleContext();
8933 }
8934
8935 /*
8936 * Returns the component that renders the header cell.
8937 */
8938 private Component getCurrentComponent() {
8939 return rendererComponent;
8940 }
8941
8942 // AccessibleContext methods ==========
8943
8944 /**
8945 * Gets the accessible name of this object.
8946 *
8947 * @return the localized name of the object; <code>null</code>
8948 * if this object does not have a name
8949 */
8950 public String getAccessibleName() {
8951 AccessibleContext ac = getCurrentAccessibleContext();
8952 if (ac != null) {
8953 String name = ac.getAccessibleName();
8954 if ((name != null) && (name != "")) {
8955 return ac.getAccessibleName();
8956 }
8957 }
8958 if ((accessibleName != null) && (accessibleName != "")) {
8959 return accessibleName;
8960 } else {
8961 return null;
8962 }
8963 }
8964
8965 /**
8966 * Sets the localized accessible name of this object.
8967 *
8968 * @param s the new localized name of the object
8969 */
8970 public void setAccessibleName(String s) {
8971 AccessibleContext ac = getCurrentAccessibleContext();
8972 if (ac != null) {
8973 ac.setAccessibleName(s);
8974 } else {
8975 super.setAccessibleName(s);
8976 }
8977 }
8978
8979 /**
8980 * Gets the accessible description of this object.
8981 *
8982 * @return the localized description of the object;
8983 * <code>null</code> if this object does not have
8984 * a description
8985 */
8986 public String getAccessibleDescription() {
8987 AccessibleContext ac = getCurrentAccessibleContext();
8988 if (ac != null) {
8989 return ac.getAccessibleDescription();
8990 } else {
8991 return super.getAccessibleDescription();
8992 }
8993 }
8994
8995 /**
8996 * Sets the accessible description of this object.
8997 *
8998 * @param s the new localized description of the object
8999 */
9000 public void setAccessibleDescription(String s) {
9001 AccessibleContext ac = getCurrentAccessibleContext();
9002 if (ac != null) {
9003 ac.setAccessibleDescription(s);
9004 } else {
9005 super.setAccessibleDescription(s);
9006 }
9007 }
9008
9009 /**
9010 * Gets the role of this object.
9011 *
9012 * @return an instance of <code>AccessibleRole</code>
9013 * describing the role of the object
9014 * @see AccessibleRole
9015 */
9016 public AccessibleRole getAccessibleRole() {
9017 AccessibleContext ac = getCurrentAccessibleContext();
9018 if (ac != null) {
9019 return ac.getAccessibleRole();
9020 } else {
9021 return AccessibleRole.UNKNOWN;
9022 }
9023 }
9024
9025 /**
9026 * Gets the state set of this object.
9027 *
9028 * @return an instance of <code>AccessibleStateSet</code>
9029 * containing the current state set of the object
9030 * @see AccessibleState
9031 */
9032 public AccessibleStateSet getAccessibleStateSet() {
9033 AccessibleContext ac = getCurrentAccessibleContext();
9034 AccessibleStateSet as = null;
9035
9036 if (ac != null) {
9037 as = ac.getAccessibleStateSet();
9038 }
9039 if (as == null) {
9040 as = new AccessibleStateSet();
9041 }
9042 Rectangle rjt = JTable.this.getVisibleRect();
9043 Rectangle rcell = JTable.this.getCellRect(row, column, false);
9044 if (rjt.intersects(rcell)) {
9045 as.add(AccessibleState.SHOWING);
9046 } else {
9047 if (as.contains(AccessibleState.SHOWING)) {
9048 as.remove(AccessibleState.SHOWING);
9049 }
9050 }
9051 if (JTable.this.isCellSelected(row, column)) {
9052 as.add(AccessibleState.SELECTED);
9053 } else if (as.contains(AccessibleState.SELECTED)) {
9054 as.remove(AccessibleState.SELECTED);
9055 }
9056 if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
9057 as.add(AccessibleState.ACTIVE);
9058 }
9059 as.add(AccessibleState.TRANSIENT);
9060 return as;
9061 }
9062
9063 /**
9064 * Gets the <code>Accessible</code> parent of this object.
9065 *
9066 * @return the Accessible parent of this object;
9067 * <code>null</code> if this object does not
9068 * have an <code>Accessible</code> parent
9069 */
9070 public Accessible getAccessibleParent() {
9071 return parent;
9072 }
9073
9074 /**
9075 * Gets the index of this object in its accessible parent.
9076 *
9077 * @return the index of this object in its parent; -1 if this
9078 * object does not have an accessible parent
9079 * @see #getAccessibleParent
9080 */
9081 public int getAccessibleIndexInParent() {
9082 return column;
9083 }
9084
9085 /**
9086 * Returns the number of accessible children in the object.
9087 *
9088 * @return the number of accessible children in the object
9089 */
9090 public int getAccessibleChildrenCount() {
9091 AccessibleContext ac = getCurrentAccessibleContext();
9092 if (ac != null) {
9093 return ac.getAccessibleChildrenCount();
9094 } else {
9095 return 0;
9096 }
9097 }
9098
9099 /**
9100 * Returns the specified <code>Accessible</code> child of the
9101 * object.
9102 *
9103 * @param i zero-based index of child
9104 * @return the <code>Accessible</code> child of the object
9105 */
9106 public Accessible getAccessibleChild(int i) {
9107 AccessibleContext ac = getCurrentAccessibleContext();
9108 if (ac != null) {
9109 Accessible accessibleChild = ac.getAccessibleChild(i);
9110 ac.setAccessibleParent(this);
9111 return accessibleChild;
9112 } else {
9113 return null;
9114 }
9115 }
9116
9117 /**
9118 * Gets the locale of the component. If the component
9119 * does not have a locale, then the locale of its parent
9120 * is returned.
9121 *
9122 * @return this component's locale; if this component does
9123 * not have a locale, the locale of its parent is returned
9124 * @exception IllegalComponentStateException if the
9125 * <code>Component</code> does not have its own locale
9126 * and has not yet been added to a containment hierarchy
9127 * such that the locale can be determined from the
9128 * containing parent
9129 * @see #setLocale
9130 */
9131 public Locale getLocale() {
9132 AccessibleContext ac = getCurrentAccessibleContext();
9133 if (ac != null) {
9134 return ac.getLocale();
9135 } else {
9136 return null;
9137 }
9138 }
9139
9140 /**
9141 * Adds a <code>PropertyChangeListener</code> to the listener list.
9142 * The listener is registered for all properties.
9143 *
9144 * @param l the <code>PropertyChangeListener</code>
9145 * to be added
9146 */
9147 public void addPropertyChangeListener(PropertyChangeListener l) {
9148 AccessibleContext ac = getCurrentAccessibleContext();
9149 if (ac != null) {
9150 ac.addPropertyChangeListener(l);
9151 } else {
9152 super.addPropertyChangeListener(l);
9153 }
9154 }
9155
9156 /**
9157 * Removes a <code>PropertyChangeListener</code> from the
9158 * listener list. This removes a <code>PropertyChangeListener</code>
9159 * that was registered for all properties.
9160 *
9161 * @param l the <code>PropertyChangeListener</code>
9162 * to be removed
9163 */
9164 public void removePropertyChangeListener(PropertyChangeListener l) {
9165 AccessibleContext ac = getCurrentAccessibleContext();
9166 if (ac != null) {
9167 ac.removePropertyChangeListener(l);
9168 } else {
9169 super.removePropertyChangeListener(l);
9170 }
9171 }
9172
9173 /**
9174 * Gets the <code>AccessibleAction</code> associated with this
9175 * object if one exists. Otherwise returns <code>null</code>.
9176 *
9177 * @return the <code>AccessibleAction</code>, or <code>null</code>
9178 */
9179 public AccessibleAction getAccessibleAction() {
9180 return getCurrentAccessibleContext().getAccessibleAction();
9181 }
9182
9183 /**
9184 * Gets the <code>AccessibleComponent</code> associated with
9185 * this object if one exists. Otherwise returns <code>null</code>.
9186 *
9187 * @return the <code>AccessibleComponent</code>, or
9188 * <code>null</code>
9189 */
9190 public AccessibleComponent getAccessibleComponent() {
9191 return this; // to override getBounds()
9192 }
9193
9194 /**
9195 * Gets the <code>AccessibleSelection</code> associated with
9196 * this object if one exists. Otherwise returns <code>null</code>.
9197 *
9198 * @return the <code>AccessibleSelection</code>, or
9199 * <code>null</code>
9200 */
9201 public AccessibleSelection getAccessibleSelection() {
9202 return getCurrentAccessibleContext().getAccessibleSelection();
9203 }
9204
9205 /**
9206 * Gets the <code>AccessibleText</code> associated with this
9207 * object if one exists. Otherwise returns <code>null</code>.
9208 *
9209 * @return the <code>AccessibleText</code>, or <code>null</code>
9210 */
9211 public AccessibleText getAccessibleText() {
9212 return getCurrentAccessibleContext().getAccessibleText();
9213 }
9214
9215 /**
9216 * Gets the <code>AccessibleValue</code> associated with
9217 * this object if one exists. Otherwise returns <code>null</code>.
9218 *
9219 * @return the <code>AccessibleValue</code>, or <code>null</code>
9220 */
9221 public AccessibleValue getAccessibleValue() {
9222 return getCurrentAccessibleContext().getAccessibleValue();
9223 }
9224
9225
9226 // AccessibleComponent methods ==========
9227
9228 /**
9229 * Gets the background color of this object.
9230 *
9231 * @return the background color, if supported, of the object;
9232 * otherwise, <code>null</code>
9233 */
9234 public Color getBackground() {
9235 AccessibleContext ac = getCurrentAccessibleContext();
9236 if (ac instanceof AccessibleComponent) {
9237 return ((AccessibleComponent) ac).getBackground();
9238 } else {
9239 Component c = getCurrentComponent();
9240 if (c != null) {
9241 return c.getBackground();
9242 } else {
9243 return null;
9244 }
9245 }
9246 }
9247
9248 /**
9249 * Sets the background color of this object.
9250 *
9251 * @param c the new <code>Color</code> for the background
9252 */
9253 public void setBackground(Color c) {
9254 AccessibleContext ac = getCurrentAccessibleContext();
9255 if (ac instanceof AccessibleComponent) {
9256 ((AccessibleComponent) ac).setBackground(c);
9257 } else {
9258 Component cp = getCurrentComponent();
9259 if (cp != null) {
9260 cp.setBackground(c);
9261 }
9262 }
9263 }
9264
9265 /**
9266 * Gets the foreground color of this object.
9267 *
9268 * @return the foreground color, if supported, of the object;
9269 * otherwise, <code>null</code>
9270 */
9271 public Color getForeground() {
9272 AccessibleContext ac = getCurrentAccessibleContext();
9273 if (ac instanceof AccessibleComponent) {
9274 return ((AccessibleComponent) ac).getForeground();
9275 } else {
9276 Component c = getCurrentComponent();
9277 if (c != null) {
9278 return c.getForeground();
9279 } else {
9280 return null;
9281 }
9282 }
9283 }
9284
9285 /**
9286 * Sets the foreground color of this object.
9287 *
9288 * @param c the new <code>Color</code> for the foreground
9289 */
9290 public void setForeground(Color c) {
9291 AccessibleContext ac = getCurrentAccessibleContext();
9292 if (ac instanceof AccessibleComponent) {
9293 ((AccessibleComponent) ac).setForeground(c);
9294 } else {
9295 Component cp = getCurrentComponent();
9296 if (cp != null) {
9297 cp.setForeground(c);
9298 }
9299 }
9300 }
9301
9302 /**
9303 * Gets the <code>Cursor</code> of this object.
9304 *
9305 * @return the <code>Cursor</code>, if supported,
9306 * of the object; otherwise, <code>null</code>
9307 */
9308 public Cursor getCursor() {
9309 AccessibleContext ac = getCurrentAccessibleContext();
9310 if (ac instanceof AccessibleComponent) {
9311 return ((AccessibleComponent) ac).getCursor();
9312 } else {
9313 Component c = getCurrentComponent();
9314 if (c != null) {
9315 return c.getCursor();
9316 } else {
9317 Accessible ap = getAccessibleParent();
9318 if (ap instanceof AccessibleComponent) {
9319 return ((AccessibleComponent) ap).getCursor();
9320 } else {
9321 return null;
9322 }
9323 }
9324 }
9325 }
9326
9327 /**
9328 * Sets the <code>Cursor</code> of this object.
9329 *
9330 * @param c the new <code>Cursor</code> for the object
9331 */
9332 public void setCursor(Cursor c) {
9333 AccessibleContext ac = getCurrentAccessibleContext();
9334 if (ac instanceof AccessibleComponent) {
9335 ((AccessibleComponent) ac).setCursor(c);
9336 } else {
9337 Component cp = getCurrentComponent();
9338 if (cp != null) {
9339 cp.setCursor(c);
9340 }
9341 }
9342 }
9343
9344 /**
9345 * Gets the <code>Font</code> of this object.
9346 *
9347 * @return the <code>Font</code>,if supported,
9348 * for the object; otherwise, <code>null</code>
9349 */
9350 public Font getFont() {
9351 AccessibleContext ac = getCurrentAccessibleContext();
9352 if (ac instanceof AccessibleComponent) {
9353 return ((AccessibleComponent) ac).getFont();
9354 } else {
9355 Component c = getCurrentComponent();
9356 if (c != null) {
9357 return c.getFont();
9358 } else {
9359 return null;
9360 }
9361 }
9362 }
9363
9364 /**
9365 * Sets the <code>Font</code> of this object.
9366 *
9367 * @param f the new <code>Font</code> for the object
9368 */
9369 public void setFont(Font f) {
9370 AccessibleContext ac = getCurrentAccessibleContext();
9371 if (ac instanceof AccessibleComponent) {
9372 ((AccessibleComponent) ac).setFont(f);
9373 } else {
9374 Component c = getCurrentComponent();
9375 if (c != null) {
9376 c.setFont(f);
9377 }
9378 }
9379 }
9380
9381 /**
9382 * Gets the <code>FontMetrics</code> of this object.
9383 *
9384 * @param f the <code>Font</code>
9385 * @return the <code>FontMetrics</code> object, if supported;
9386 * otherwise <code>null</code>
9387 * @see #getFont
9388 */
9389 public FontMetrics getFontMetrics(Font f) {
9390 AccessibleContext ac = getCurrentAccessibleContext();
9391 if (ac instanceof AccessibleComponent) {
9392 return ((AccessibleComponent) ac).getFontMetrics(f);
9393 } else {
9394 Component c = getCurrentComponent();
9395 if (c != null) {
9396 return c.getFontMetrics(f);
9397 } else {
9398 return null;
9399 }
9400 }
9401 }
9402
9403 /**
9404 * Determines if the object is enabled.
9405 *
9406 * @return true if object is enabled; otherwise, false
9424 *
9425 * @param b if true, enables this object; otherwise, disables it
9426 */
9427 public void setEnabled(boolean b) {
9428 AccessibleContext ac = getCurrentAccessibleContext();
9429 if (ac instanceof AccessibleComponent) {
9430 ((AccessibleComponent) ac).setEnabled(b);
9431 } else {
9432 Component c = getCurrentComponent();
9433 if (c != null) {
9434 c.setEnabled(b);
9435 }
9436 }
9437 }
9438
9439 /**
9440 * Determines if this object is visible. Note: this means that the
9441 * object intends to be visible; however, it may not in fact be
9442 * showing on the screen because one of the objects that this object
9443 * is contained by is not visible. To determine if an object is
9444 * showing on the screen, use <code>isShowing</code>.
9445 *
9446 * @return true if object is visible; otherwise, false
9447 */
9448 public boolean isVisible() {
9449 AccessibleContext ac = getCurrentAccessibleContext();
9450 if (ac instanceof AccessibleComponent) {
9451 return ((AccessibleComponent) ac).isVisible();
9452 } else {
9453 Component c = getCurrentComponent();
9454 if (c != null) {
9455 return c.isVisible();
9456 } else {
9457 return false;
9458 }
9459 }
9460 }
9461
9462 /**
9463 * Sets the visible state of the object.
9464 *
9495 // returns false when the cell on the screen
9496 // if no parent
9497 return isVisible();
9498 }
9499 } else {
9500 Component c = getCurrentComponent();
9501 if (c != null) {
9502 return c.isShowing();
9503 } else {
9504 return false;
9505 }
9506 }
9507 }
9508
9509 /**
9510 * Checks whether the specified point is within this
9511 * object's bounds, where the point's x and y coordinates
9512 * are defined to be relative to the coordinate system of
9513 * the object.
9514 *
9515 * @param p the <code>Point</code> relative to the
9516 * coordinate system of the object
9517 * @return true if object contains <code>Point</code>;
9518 * otherwise false
9519 */
9520 public boolean contains(Point p) {
9521 AccessibleContext ac = getCurrentAccessibleContext();
9522 if (ac instanceof AccessibleComponent) {
9523 Rectangle r = ((AccessibleComponent) ac).getBounds();
9524 return r.contains(p);
9525 } else {
9526 Component c = getCurrentComponent();
9527 if (c != null) {
9528 Rectangle r = c.getBounds();
9529 return r.contains(p);
9530 } else {
9531 return getBounds().contains(p);
9532 }
9533 }
9534 }
9535
9536 /**
9537 * Returns the location of the object on the screen.
9538 *
9539 * @return location of object on screen -- can be
9540 * <code>null</code> if this object is not on the screen
9541 */
9542 public Point getLocationOnScreen() {
9543 if (parent != null && parent.isShowing()) {
9544 Point parentLocation = parent.getLocationOnScreen();
9545 Point componentLocation = getLocation();
9546 componentLocation.translate(parentLocation.x, parentLocation.y);
9547 return componentLocation;
9548 } else {
9549 return null;
9550 }
9551 }
9552
9553 /**
9554 * Gets the location of the object relative to the parent
9555 * in the form of a point specifying the object's
9556 * top-left corner in the screen's coordinate space.
9557 *
9558 * @return an instance of <code>Point</code> representing
9559 * the top-left corner of the object's bounds in the
9560 * coordinate space of the screen; <code>null</code> if
9561 * this object or its parent are not on the screen
9562 */
9563 public Point getLocation() {
9564 if (parent != null) {
9565 Rectangle r = parent.getHeaderRect(column);
9566 if (r != null) {
9567 return r.getLocation();
9568 }
9569 }
9570 return null;
9571 }
9572
9573 /**
9574 * Sets the location of the object relative to the parent.
9575 * @param p the new position for the top-left corner
9576 * @see #getLocation
9577 */
9578 public void setLocation(Point p) {
9579 }
9580
|
46 import javax.swing.table.*;
47 import javax.swing.border.*;
48
49 import java.text.NumberFormat;
50 import java.text.DateFormat;
51 import java.text.MessageFormat;
52 import java.util.List;
53
54 import javax.print.attribute.*;
55 import javax.print.PrintService;
56
57 import sun.misc.ManagedLocalsThread;
58 import sun.reflect.misc.ReflectUtil;
59
60 import sun.swing.SwingUtilities2;
61 import sun.swing.SwingUtilities2.Section;
62 import static sun.swing.SwingUtilities2.Section.*;
63 import sun.swing.PrintingStatus;
64
65 /**
66 * The {@code JTable} is used to display and edit regular two-dimensional tables
67 * of cells.
68 * See <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/table.html">How to Use Tables</a>
69 * in <em>The Java Tutorial</em>
70 * for task-oriented documentation and examples of using {@code JTable}.
71 *
72 * <p>
73 * The {@code JTable} has many
74 * facilities that make it possible to customize its rendering and editing
75 * but provides defaults for these features so that simple tables can be
76 * set up easily. For example, to set up a table with 10 rows and 10
77 * columns of numbers:
78 *
79 * <pre>
80 * TableModel dataModel = new AbstractTableModel() {
81 * public int getColumnCount() { return 10; }
82 * public int getRowCount() { return 10;}
83 * public Object getValueAt(int row, int col) { return new Integer(row*col); }
84 * };
85 * JTable table = new JTable(dataModel);
86 * JScrollPane scrollpane = new JScrollPane(table);
87 * </pre>
88 * <p>
89 * {@code JTable}s are typically placed inside of a {@code JScrollPane}. By
90 * default, a {@code JTable} will adjust its width such that
91 * a horizontal scrollbar is unnecessary. To allow for a horizontal scrollbar,
92 * invoke {@link #setAutoResizeMode} with {@code AUTO_RESIZE_OFF}.
93 * Note that if you wish to use a {@code JTable} in a standalone
94 * view (outside of a {@code JScrollPane}) and want the header
95 * displayed, you can get it using {@link #getTableHeader} and
96 * display it separately.
97 * <p>
98 * To enable sorting and filtering of rows, use a
99 * {@code RowSorter}.
100 * You can set up a row sorter in either of two ways:
101 * <ul>
102 * <li>Directly set the {@code RowSorter}. For example:
103 * {@code table.setRowSorter(new TableRowSorter(model))}.
104 * <li>Set the {@code autoCreateRowSorter}
105 * property to {@code true}, so that the {@code JTable}
106 * creates a {@code RowSorter} for
107 * you. For example: {@code setAutoCreateRowSorter(true)}.
108 * </ul>
109 * <p>
110 * When designing applications that use the {@code JTable} it is worth paying
111 * close attention to the data structures that will represent the table's data.
112 * The {@code DefaultTableModel} is a model implementation that
113 * uses a {@code Vector} of {@code Vector}s of {@code Object}s to
114 * store the cell values. As well as copying the data from an
115 * application into the {@code DefaultTableModel},
116 * it is also possible to wrap the data in the methods of the
117 * {@code TableModel} interface so that the data can be passed to the
118 * {@code JTable} directly, as in the example above. This often results
119 * in more efficient applications because the model is free to choose the
120 * internal representation that best suits the data.
121 * A good rule of thumb for deciding whether to use the {@code AbstractTableModel}
122 * or the {@code DefaultTableModel} is to use the {@code AbstractTableModel}
123 * as the base class for creating subclasses and the {@code DefaultTableModel}
124 * when subclassing is not required.
125 * <p>
126 * The "TableExample" directory in the demo area of the source distribution
127 * gives a number of complete examples of {@code JTable} usage,
128 * covering how the {@code JTable} can be used to provide an
129 * editable view of data taken from a database and how to modify
130 * the columns in the display to use specialized renderers and editors.
131 * <p>
132 * The {@code JTable} uses integers exclusively to refer to both the rows and the columns
133 * of the model that it displays. The {@code JTable} simply takes a tabular range of cells
134 * and uses {@code getValueAt(int, int)} to retrieve the
135 * values from the model during painting. It is important to remember that
136 * the column and row indexes returned by various {@code JTable} methods
137 * are in terms of the {@code JTable} (the view) and are not
138 * necessarily the same indexes used by the model.
139 * <p>
140 * By default, columns may be rearranged in the {@code JTable} so that the
141 * view's columns appear in a different order to the columns in the model.
142 * This does not affect the implementation of the model at all: when the
143 * columns are reordered, the {@code JTable} maintains the new order of the columns
144 * internally and converts its column indices before querying the model.
145 * <p>
146 * So, when writing a {@code TableModel}, it is not necessary to listen for column
147 * reordering events as the model will be queried in its own coordinate
148 * system regardless of what is happening in the view.
149 * In the examples area there is a demonstration of a sorting algorithm making
150 * use of exactly this technique to interpose yet another coordinate system
151 * where the order of the rows is changed, rather than the order of the columns.
152 * <p>
153 * Similarly when using the sorting and filtering functionality
154 * provided by {@code RowSorter} the underlying
155 * {@code TableModel} does not need to know how to do sorting,
156 * rather {@code RowSorter} will handle it. Coordinate
157 * conversions will be necessary when using the row based methods of
158 * {@code JTable} with the underlying {@code TableModel}.
159 * All of {@code JTable}s row based methods are in terms of the
160 * {@code RowSorter}, which is not necessarily the same as that
161 * of the underlying {@code TableModel}. For example, the
162 * selection is always in terms of {@code JTable} so that when
163 * using {@code RowSorter} you will need to convert using
164 * {@code convertRowIndexToView} or
165 * {@code convertRowIndexToModel}. The following shows how to
166 * convert coordinates from {@code JTable} to that of the
167 * underlying model:
168 * <pre>
169 * int[] selection = table.getSelectedRows();
170 * for (int i = 0; i < selection.length; i++) {
171 * selection[i] = table.convertRowIndexToModel(selection[i]);
172 * }
173 * // selection is now in terms of the underlying TableModel
174 * </pre>
175 * <p>
176 * By default if sorting is enabled {@code JTable} will persist the
177 * selection and variable row heights in terms of the model on
178 * sorting. For example if row 0, in terms of the underlying model,
179 * is currently selected, after the sort row 0, in terms of the
180 * underlying model will be selected. Visually the selection may
181 * change, but in terms of the underlying model it will remain the
182 * same. The one exception to that is if the model index is no longer
183 * visible or was removed. For example, if row 0 in terms of model
184 * was filtered out the selection will be empty after the sort.
185 * <p>
186 * J2SE 5 adds methods to {@code JTable} to provide convenient access to some
187 * common printing needs. Simple new {@link #print()} methods allow for quick
188 * and easy addition of printing support to your application. In addition, a new
189 * {@link #getPrintable} method is available for more advanced printing needs.
190 * <p>
191 * As for all {@code JComponent} classes, you can use
192 * {@link InputMap} and {@link ActionMap} to associate an
193 * {@link Action} object with a {@link KeyStroke} and execute the
194 * action under specified conditions.
195 * <p>
196 * <strong>Warning:</strong> Swing is not thread safe. For more
197 * information see <a
198 * href="package-summary.html#threading">Swing's Threading
199 * Policy</a>.
200 * <p>
201 * <strong>Warning:</strong>
202 * Serialized objects of this class will not be compatible with
203 * future Swing releases. The current serialization support is
204 * appropriate for short term storage or RMI between applications running
205 * the same version of Swing. As of 1.4, support for long term storage
206 * of all JavaBeans™
207 * has been added to the {@code java.beans} package.
208 * Please see {@link java.beans.XMLEncoder}.
209 *
210 *
211 * @beaninfo
212 * attribute: isContainer false
213 * description: A component which displays data in a two dimensional grid.
214 *
215 * @author Philip Milne
216 * @author Shannon Hickey (printing support)
217 * @see javax.swing.table.DefaultTableModel
218 * @see javax.swing.table.TableRowSorter
219 * @since 1.2
220 */
221 /* The first versions of the JTable, contained in Swing-0.1 through
222 * Swing-0.4, were written by Alan Chung.
223 */
224 @SuppressWarnings("serial") // Same-version serialization only
225 public class JTable extends JComponent implements TableModelListener, Scrollable,
226 TableColumnModelListener, ListSelectionListener, CellEditorListener,
227 Accessible, RowSorterListener
237 private static final String uiClassID = "TableUI";
238
239 /** Do not adjust column widths automatically; use a horizontal scrollbar instead. */
240 public static final int AUTO_RESIZE_OFF = 0;
241
242 /** When a column is adjusted in the UI, adjust the next column the opposite way. */
243 public static final int AUTO_RESIZE_NEXT_COLUMN = 1;
244
245 /** During UI adjustment, change subsequent columns to preserve the total width;
246 * this is the default behavior. */
247 public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
248
249 /** During all resize operations, apply adjustments to the last column only. */
250 public static final int AUTO_RESIZE_LAST_COLUMN = 3;
251
252 /** During all resize operations, proportionately resize all columns. */
253 public static final int AUTO_RESIZE_ALL_COLUMNS = 4;
254
255
256 /**
257 * Printing modes, used in printing {@code JTable}s.
258 *
259 * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
260 * boolean, PrintRequestAttributeSet, boolean)
261 * @see #getPrintable
262 * @since 1.5
263 */
264 public enum PrintMode {
265
266 /**
267 * Printing mode that prints the table at its current size,
268 * spreading both columns and rows across multiple pages if necessary.
269 */
270 NORMAL,
271
272 /**
273 * Printing mode that scales the output smaller, if necessary,
274 * to fit the table's entire width (and thereby all columns) on each page;
275 * Rows are spread across multiple pages as necessary.
276 */
277 FIT_WIDTH
278 }
279
280
281 //
282 // Instance Variables
283 //
284
285 /** The {@code TableModel} of the table. */
286 protected TableModel dataModel;
287
288 /** The {@code TableColumnModel} of the table. */
289 protected TableColumnModel columnModel;
290
291 /** The {@code ListSelectionModel} of the table, used to keep track of row selections. */
292 protected ListSelectionModel selectionModel;
293
294 /** The {@code TableHeader} working with the table. */
295 protected JTableHeader tableHeader;
296
297 /** The height in pixels of each row in the table. */
298 protected int rowHeight;
299
300 /** The height in pixels of the margin between the cells in each row. */
301 protected int rowMargin;
302
303 /** The color of the grid. */
304 protected Color gridColor;
305
306 /** The table draws horizontal lines between cells if {@code showHorizontalLines} is true. */
307 protected boolean showHorizontalLines;
308
309 /** The table draws vertical lines between cells if {@code showVerticalLines} is true. */
310 protected boolean showVerticalLines;
311
312 /**
313 * Determines if the table automatically resizes the
314 * width of the table's columns to take up the entire width of the
315 * table, and how it does the resizing.
316 */
317 protected int autoResizeMode;
318
319 /**
320 * The table will query the {@code TableModel} to build the default
321 * set of columns if this is true.
322 */
323 protected boolean autoCreateColumnsFromModel;
324
325 /** Used by the {@code Scrollable} interface to determine the initial visible area. */
326 protected Dimension preferredViewportSize;
327
328 /** True if row selection is allowed in this table. */
329 protected boolean rowSelectionAllowed;
330
331 /**
332 * Obsolete as of Java 2 platform v1.3. Please use the
333 * {@code rowSelectionAllowed} property and the
334 * {@code columnSelectionAllowed} property of the
335 * {@code columnModel} instead. Or use the
336 * method {@code getCellSelectionEnabled}.
337 */
338 /*
339 * If true, both a row selection and a column selection
340 * can be non-empty at the same time, the selected cells are the
341 * the cells whose row and column are both selected.
342 */
343 protected boolean cellSelectionEnabled;
344
345 /** If editing, the {@code Component} that is handling the editing. */
346 protected transient Component editorComp;
347
348 /**
349 * The active cell editor object, that overwrites the screen real estate
350 * occupied by the current cell and allows the user to change its contents.
351 * {@code null} if the table isn't currently editing.
352 */
353 protected transient TableCellEditor cellEditor;
354
355 /** Identifies the column of the cell being edited. */
356 protected transient int editingColumn;
357
358 /** Identifies the row of the cell being edited. */
359 protected transient int editingRow;
360
361 /**
362 * A table of objects that display the contents of a cell,
363 * indexed by class as declared in {@code getColumnClass}
364 * in the {@code TableModel} interface.
365 */
366 protected transient Hashtable<Object, Object> defaultRenderersByColumnClass;
367 // Logicaly, the above is a Hashtable<Class<?>, TableCellRenderer>.
368 // It is declared otherwise to accomodate using UIDefaults.
369
370 /**
371 * A table of objects that display and edit the contents of a cell,
372 * indexed by class as declared in {@code getColumnClass}
373 * in the {@code TableModel} interface.
374 */
375 protected transient Hashtable<Object, Object> defaultEditorsByColumnClass;
376 // Logicaly, the above is a Hashtable<Class<?>, TableCellEditor>.
377 // It is declared otherwise to accomodate using UIDefaults.
378
379 /** The foreground color of selected cells. */
380 protected Color selectionForeground;
381
382 /** The background color of selected cells. */
383 protected Color selectionBackground;
384
385 //
386 // Private state
387 //
388
389 // WARNING: If you directly access this field you should also change the
390 // SortManager.modelRowSizes field as well.
391 private SizeSequence rowModel;
392 private boolean dragEnabled;
393 private boolean surrendersFocusOnKeystroke;
440 private boolean autoCreateRowSorter;
441
442 /**
443 * Whether or not the table always fills the viewport height.
444 * @see #setFillsViewportHeight
445 * @see #getScrollableTracksViewportHeight
446 */
447 private boolean fillsViewportHeight;
448
449 /**
450 * The drop mode for this component.
451 */
452 private DropMode dropMode = DropMode.USE_SELECTION;
453
454 /**
455 * The drop location.
456 */
457 private transient DropLocation dropLocation;
458
459 /**
460 * A subclass of {@code TransferHandler.DropLocation} representing
461 * a drop location for a {@code JTable}.
462 *
463 * @see #getDropLocation
464 * @since 1.6
465 */
466 public static final class DropLocation extends TransferHandler.DropLocation {
467 private final int row;
468 private final int col;
469 private final boolean isInsertRow;
470 private final boolean isInsertCol;
471
472 private DropLocation(Point p, int row, int col,
473 boolean isInsertRow, boolean isInsertCol) {
474
475 super(p);
476 this.row = row;
477 this.col = col;
478 this.isInsertRow = isInsertRow;
479 this.isInsertCol = isInsertCol;
480 }
481
482 /**
483 * Returns the row index where a dropped item should be placed in the
484 * table. Interpretation of the value depends on the return of
485 * {@code isInsertRow()}. If that method returns
486 * {@code true} this value indicates the index where a new
487 * row should be inserted. Otherwise, it represents the value
488 * of an existing row on which the data was dropped. This index is
489 * in terms of the view.
490 * <p>
491 * {@code -1} indicates that the drop occurred over empty space,
492 * and no row could be calculated.
493 *
494 * @return the drop row
495 */
496 public int getRow() {
497 return row;
498 }
499
500 /**
501 * Returns the column index where a dropped item should be placed in the
502 * table. Interpretation of the value depends on the return of
503 * {@code isInsertColumn()}. If that method returns
504 * {@code true} this value indicates the index where a new
505 * column should be inserted. Otherwise, it represents the value
506 * of an existing column on which the data was dropped. This index is
507 * in terms of the view.
508 * <p>
509 * {@code -1} indicates that the drop occurred over empty space,
510 * and no column could be calculated.
511 *
512 * @return the drop row
513 */
514 public int getColumn() {
515 return col;
516 }
517
518 /**
519 * Returns whether or not this location represents an insert
520 * of a row.
521 *
522 * @return whether or not this is an insert row
523 */
524 public boolean isInsertRow() {
525 return isInsertRow;
526 }
527
528 /**
529 * Returns whether or not this location represents an insert
541 * and the content and format of the returned string may vary
542 * between implementations.
543 *
544 * @return a string representation of this drop location
545 */
546 public String toString() {
547 return getClass().getName()
548 + "[dropPoint=" + getDropPoint() + ","
549 + "row=" + row + ","
550 + "column=" + col + ","
551 + "insertRow=" + isInsertRow + ","
552 + "insertColumn=" + isInsertCol + "]";
553 }
554 }
555
556 //
557 // Constructors
558 //
559
560 /**
561 * Constructs a default {@code JTable} that is initialized with a default
562 * data model, a default column model, and a default selection
563 * model.
564 *
565 * @see #createDefaultDataModel
566 * @see #createDefaultColumnModel
567 * @see #createDefaultSelectionModel
568 */
569 public JTable() {
570 this(null, null, null);
571 }
572
573 /**
574 * Constructs a {@code JTable} that is initialized with
575 * {@code dm} as the data model, a default column model,
576 * and a default selection model.
577 *
578 * @param dm the data model for the table
579 * @see #createDefaultColumnModel
580 * @see #createDefaultSelectionModel
581 */
582 public JTable(TableModel dm) {
583 this(dm, null, null);
584 }
585
586 /**
587 * Constructs a {@code JTable} that is initialized with
588 * {@code dm} as the data model, {@code cm}
589 * as the column model, and a default selection model.
590 *
591 * @param dm the data model for the table
592 * @param cm the column model for the table
593 * @see #createDefaultSelectionModel
594 */
595 public JTable(TableModel dm, TableColumnModel cm) {
596 this(dm, cm, null);
597 }
598
599 /**
600 * Constructs a {@code JTable} that is initialized with
601 * {@code dm} as the data model, {@code cm} as the
602 * column model, and {@code sm} as the selection model.
603 * If any of the parameters are {@code null} this method
604 * will initialize the table with the corresponding default model.
605 * The {@code autoCreateColumnsFromModel} flag is set to false
606 * if {@code cm} is non-null, otherwise it is set to true
607 * and the column model is populated with suitable
608 * {@code TableColumns} for the columns in {@code dm}.
609 *
610 * @param dm the data model for the table
611 * @param cm the column model for the table
612 * @param sm the row selection model for the table
613 * @see #createDefaultDataModel
614 * @see #createDefaultColumnModel
615 * @see #createDefaultSelectionModel
616 */
617 public JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
618 super();
619 setLayout(null);
620
621 setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
622 JComponent.getManagingFocusForwardTraversalKeys());
623 setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
624 JComponent.getManagingFocusBackwardTraversalKeys());
625 if (cm == null) {
626 cm = createDefaultColumnModel();
627 autoCreateColumnsFromModel = true;
628 }
629 setColumnModel(cm);
630
631 if (sm == null) {
632 sm = createDefaultSelectionModel();
633 }
634 setSelectionModel(sm);
635
636 // Set the model last, that way if the autoCreatColumnsFromModel has
637 // been set above, we will automatically populate an empty columnModel
638 // with suitable columns for the new model.
639 if (dm == null) {
640 dm = createDefaultDataModel();
641 }
642 setModel(dm);
643
644 initializeLocalVars();
645 updateUI();
646 }
647
648 /**
649 * Constructs a {@code JTable} with {@code numRows}
650 * and {@code numColumns} of empty cells using
651 * {@code DefaultTableModel}. The columns will have
652 * names of the form "A", "B", "C", etc.
653 *
654 * @param numRows the number of rows the table holds
655 * @param numColumns the number of columns the table holds
656 * @see javax.swing.table.DefaultTableModel
657 */
658 public JTable(int numRows, int numColumns) {
659 this(new DefaultTableModel(numRows, numColumns));
660 }
661
662 /**
663 * Constructs a {@code JTable} to display the values in the
664 * {@code Vector} of {@code Vectors}, {@code rowData},
665 * with column names, {@code columnNames}. The
666 * {@code Vectors} contained in {@code rowData}
667 * should contain the values for that row. In other words,
668 * the value of the cell at row 1, column 5 can be obtained
669 * with the following code:
670 *
671 * <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
672 *
673 * @param rowData the data for the new table
674 * @param columnNames names of each column
675 */
676 @SuppressWarnings("rawtypes")
677 public JTable(Vector<? extends Vector> rowData, Vector<?> columnNames) {
678 this(new DefaultTableModel(rowData, columnNames));
679 }
680
681 /**
682 * Constructs a {@code JTable} to display the values in the two dimensional array,
683 * {@code rowData}, with column names, {@code columnNames}.
684 * {@code rowData} is an array of rows, so the value of the cell at row 1,
685 * column 5 can be obtained with the following code:
686 *
687 * <pre> rowData[1][5]; </pre>
688 * <p>
689 * All rows must be of the same length as {@code columnNames}.
690 *
691 * @param rowData the data for the new table
692 * @param columnNames names of each column
693 */
694 public JTable(final Object[][] rowData, final Object[] columnNames) {
695 this(new AbstractTableModel() {
696 public String getColumnName(int column) { return columnNames[column].toString(); }
697 public int getRowCount() { return rowData.length; }
698 public int getColumnCount() { return columnNames.length; }
699 public Object getValueAt(int row, int col) { return rowData[row][col]; }
700 public boolean isCellEditable(int row, int column) { return true; }
701 public void setValueAt(Object value, int row, int col) {
702 rowData[row][col] = value;
703 fireTableCellUpdated(row, col);
704 }
705 });
706 }
707
708 /**
709 * Calls the {@code configureEnclosingScrollPane} method.
710 *
711 * @see #configureEnclosingScrollPane
712 */
713 public void addNotify() {
714 super.addNotify();
715 configureEnclosingScrollPane();
716 }
717
718 /**
719 * If this {@code JTable} is the {@code viewportView} of an enclosing {@code JScrollPane}
720 * (the usual situation), configure this {@code ScrollPane} by, amongst other things,
721 * installing the table's {@code tableHeader} as the {@code columnHeaderView} of the scroll pane.
722 * When a {@code JTable} is added to a {@code JScrollPane} in the usual way,
723 * using {@code new JScrollPane(myTable)}, {@code addNotify} is
724 * called in the {@code JTable} (when the table is added to the viewport).
725 * {@code JTable}'s {@code addNotify} method in turn calls this method,
726 * which is protected so that this default installation procedure can
727 * be overridden by a subclass.
728 *
729 * @see #addNotify
730 */
731 protected void configureEnclosingScrollPane() {
732 Container parent = SwingUtilities.getUnwrappedParent(this);
733 if (parent instanceof JViewport) {
734 JViewport port = (JViewport) parent;
735 Container gp = port.getParent();
736 if (gp instanceof JScrollPane) {
737 JScrollPane scrollPane = (JScrollPane)gp;
738 // Make certain we are the viewPort's view and not, for
739 // example, the rowHeaderView of the scrollPane -
740 // an implementor of fixed columns might do this.
741 JViewport viewport = scrollPane.getViewport();
742 if (viewport == null ||
743 SwingUtilities.getUnwrappedView(viewport) != this) {
744 return;
745 }
788 }
789 // add JScrollBar corner component if available from LAF and not already set by the user
790 Component corner =
791 scrollPane.getCorner(JScrollPane.UPPER_TRAILING_CORNER);
792 if (corner == null || corner instanceof UIResource){
793 corner = null;
794 try {
795 corner = (Component) UIManager.get(
796 "Table.scrollPaneCornerComponent");
797 } catch (Exception e) {
798 // just ignore and don't set corner
799 }
800 scrollPane.setCorner(JScrollPane.UPPER_TRAILING_CORNER,
801 corner);
802 }
803 }
804 }
805 }
806
807 /**
808 * Calls the {@code unconfigureEnclosingScrollPane} method.
809 *
810 * @see #unconfigureEnclosingScrollPane
811 */
812 public void removeNotify() {
813 KeyboardFocusManager.getCurrentKeyboardFocusManager().
814 removePropertyChangeListener("permanentFocusOwner", editorRemover);
815 editorRemover = null;
816 unconfigureEnclosingScrollPane();
817 super.removeNotify();
818 }
819
820 /**
821 * Reverses the effect of {@code configureEnclosingScrollPane}
822 * by replacing the {@code columnHeaderView} of the enclosing
823 * scroll pane with {@code null}. {@code JTable}'s
824 * {@code removeNotify} method calls
825 * this method, which is protected so that this default uninstallation
826 * procedure can be overridden by a subclass.
827 *
828 * @see #removeNotify
829 * @see #configureEnclosingScrollPane
830 * @since 1.3
831 */
832 protected void unconfigureEnclosingScrollPane() {
833 Container parent = SwingUtilities.getUnwrappedParent(this);
834 if (parent instanceof JViewport) {
835 JViewport port = (JViewport) parent;
836 Container gp = port.getParent();
837 if (gp instanceof JScrollPane) {
838 JScrollPane scrollPane = (JScrollPane)gp;
839 // Make certain we are the viewPort's view and not, for
840 // example, the rowHeaderView of the scrollPane -
841 // an implementor of fixed columns might do this.
842 JViewport viewport = scrollPane.getViewport();
843 if (viewport == null ||
844 SwingUtilities.getUnwrappedView(viewport) != this) {
855 }
856 }
857 }
858
859 void setUIProperty(String propertyName, Object value) {
860 if (propertyName == "rowHeight") {
861 if (!isRowHeightSet) {
862 setRowHeight(((Number)value).intValue());
863 isRowHeightSet = false;
864 }
865 return;
866 }
867 super.setUIProperty(propertyName, value);
868 }
869
870 //
871 // Static Methods
872 //
873
874 /**
875 * Equivalent to {@code new JScrollPane(aTable)}.
876 *
877 * @param aTable a {@code JTable} to be used for the scroll pane
878 * @return a {@code JScrollPane} created using {@code aTable}
879 * @deprecated As of Swing version 1.0.2,
880 * replaced by {@code new JScrollPane(aTable)}.
881 */
882 @Deprecated
883 public static JScrollPane createScrollPaneForTable(JTable aTable) {
884 return new JScrollPane(aTable);
885 }
886
887 //
888 // Table Attributes
889 //
890
891 /**
892 * Sets the {@code tableHeader} working with this {@code JTable} to {@code newHeader}.
893 * It is legal to have a {@code null tableHeader}.
894 *
895 * @param tableHeader new tableHeader
896 * @see #getTableHeader
897 * @beaninfo
898 * bound: true
899 * description: The JTableHeader instance which renders the column headers.
900 */
901 public void setTableHeader(JTableHeader tableHeader) {
902 if (this.tableHeader != tableHeader) {
903 JTableHeader old = this.tableHeader;
904 // Release the old header
905 if (old != null) {
906 old.setTable(null);
907 }
908 this.tableHeader = tableHeader;
909 if (tableHeader != null) {
910 tableHeader.setTable(this);
911 }
912 firePropertyChange("tableHeader", old, tableHeader);
913 }
914 }
915
916 /**
917 * Returns the {@code tableHeader} used by this {@code JTable}.
918 *
919 * @return the {@code tableHeader} used by this table
920 * @see #setTableHeader
921 */
922 public JTableHeader getTableHeader() {
923 return tableHeader;
924 }
925
926 /**
927 * Sets the height, in pixels, of all cells to {@code rowHeight},
928 * revalidates, and repaints.
929 * The height of the cells will be equal to the row height minus
930 * the row margin.
931 *
932 * @param rowHeight new row height
933 * @exception IllegalArgumentException if {@code rowHeight} is
934 * less than 1
935 * @see #getRowHeight
936 * @beaninfo
937 * bound: true
938 * description: The height of the specified row.
939 */
940 public void setRowHeight(int rowHeight) {
941 if (rowHeight <= 0) {
942 throw new IllegalArgumentException("New row height less than 1");
943 }
944 int old = this.rowHeight;
945 this.rowHeight = rowHeight;
946 rowModel = null;
947 if (sortManager != null) {
948 sortManager.modelRowSizes = null;
949 }
950 isRowHeightSet = true;
951 resizeAndRepaint();
952 firePropertyChange("rowHeight", old, rowHeight);
953 }
954
955 /**
956 * Returns the height of a table row, in pixels.
957 *
958 * @return the height in pixels of a table row
959 * @see #setRowHeight
960 */
961 public int getRowHeight() {
962 return rowHeight;
963 }
964
965 private SizeSequence getRowModel() {
966 if (rowModel == null) {
967 rowModel = new SizeSequence(getRowCount(), getRowHeight());
968 }
969 return rowModel;
970 }
971
972 /**
973 * Sets the height for {@code row} to {@code rowHeight},
974 * revalidates, and repaints. The height of the cells in this row
975 * will be equal to the row height minus the row margin.
976 *
977 * @param row the row whose height is being
978 changed
979 * @param rowHeight new row height, in pixels
980 * @exception IllegalArgumentException if {@code rowHeight} is
981 * less than 1
982 * @beaninfo
983 * bound: true
984 * description: The height in pixels of the cells in {@code row}
985 * @since 1.3
986 */
987 public void setRowHeight(int row, int rowHeight) {
988 if (rowHeight <= 0) {
989 throw new IllegalArgumentException("New row height less than 1");
990 }
991 getRowModel().setSize(row, rowHeight);
992 if (sortManager != null) {
993 sortManager.setViewRowHeight(row, rowHeight);
994 }
995 resizeAndRepaint();
996 }
997
998 /**
999 * Returns the height, in pixels, of the cells in {@code row}.
1000 * @param row the row whose height is to be returned
1001 * @return the height, in pixels, of the cells in the row
1002 * @since 1.3
1003 */
1004 public int getRowHeight(int row) {
1005 return (rowModel == null) ? getRowHeight() : rowModel.getSize(row);
1006 }
1007
1008 /**
1009 * Sets the amount of empty space between cells in adjacent rows.
1010 *
1011 * @param rowMargin the number of pixels between cells in a row
1012 * @see #getRowMargin
1013 * @beaninfo
1014 * bound: true
1015 * description: The amount of space between cells.
1016 */
1017 public void setRowMargin(int rowMargin) {
1018 int old = this.rowMargin;
1019 this.rowMargin = rowMargin;
1020 resizeAndRepaint();
1021 firePropertyChange("rowMargin", old, rowMargin);
1022 }
1023
1024 /**
1025 * Gets the amount of empty space, in pixels, between cells. Equivalent to:
1026 * {@code getIntercellSpacing().height}.
1027 * @return the number of pixels between cells in a row
1028 *
1029 * @see #setRowMargin
1030 */
1031 public int getRowMargin() {
1032 return rowMargin;
1033 }
1034
1035 /**
1036 * Sets the {@code rowMargin} and the {@code columnMargin} --
1037 * the height and width of the space between cells -- to
1038 * {@code intercellSpacing}.
1039 *
1040 * @param intercellSpacing a {@code Dimension}
1041 * specifying the new width
1042 * and height between cells
1043 * @see #getIntercellSpacing
1044 * @beaninfo
1045 * description: The spacing between the cells,
1046 * drawn in the background color of the JTable.
1047 */
1048 public void setIntercellSpacing(Dimension intercellSpacing) {
1049 // Set the rowMargin here and columnMargin in the TableColumnModel
1050 setRowMargin(intercellSpacing.height);
1051 getColumnModel().setColumnMargin(intercellSpacing.width);
1052
1053 resizeAndRepaint();
1054 }
1055
1056 /**
1057 * Returns the horizontal and vertical space between cells.
1058 * The default spacing is look and feel dependent.
1059 *
1060 * @return the horizontal and vertical spacing between cells
1061 * @see #setIntercellSpacing
1062 */
1063 public Dimension getIntercellSpacing() {
1064 return new Dimension(getColumnModel().getColumnMargin(), rowMargin);
1065 }
1066
1067 /**
1068 * Sets the color used to draw grid lines to {@code gridColor} and redisplays.
1069 * The default color is look and feel dependent.
1070 *
1071 * @param gridColor the new color of the grid lines
1072 * @exception IllegalArgumentException if {@code gridColor} is {@code null}
1073 * @see #getGridColor
1074 * @beaninfo
1075 * bound: true
1076 * description: The grid color.
1077 */
1078 public void setGridColor(Color gridColor) {
1079 if (gridColor == null) {
1080 throw new IllegalArgumentException("New color is null");
1081 }
1082 Color old = this.gridColor;
1083 this.gridColor = gridColor;
1084 firePropertyChange("gridColor", old, gridColor);
1085 // Redraw
1086 repaint();
1087 }
1088
1089 /**
1090 * Returns the color used to draw grid lines.
1091 * The default color is look and feel dependent.
1092 *
1093 * @return the color used to draw grid lines
1094 * @see #setGridColor
1095 */
1096 public Color getGridColor() {
1097 return gridColor;
1098 }
1099
1100 /**
1101 * Sets whether the table draws grid lines around cells.
1102 * If {@code showGrid} is true it does; if it is false it doesn't.
1103 * There is no {@code getShowGrid} method as this state is held
1104 * in two variables -- {@code showHorizontalLines} and {@code showVerticalLines} --
1105 * each of which can be queried independently.
1106 *
1107 * @param showGrid true if table view should draw grid lines
1108 *
1109 * @see #setShowVerticalLines
1110 * @see #setShowHorizontalLines
1111 * @beaninfo
1112 * description: The color used to draw the grid lines.
1113 */
1114 public void setShowGrid(boolean showGrid) {
1115 setShowHorizontalLines(showGrid);
1116 setShowVerticalLines(showGrid);
1117
1118 // Redraw
1119 repaint();
1120 }
1121
1122 /**
1123 * Sets whether the table draws horizontal lines between cells.
1124 * If {@code showHorizontalLines} is true it does; if it is false it doesn't.
1125 *
1126 * @param showHorizontalLines true if table view should draw horizontal lines
1127 * @see #getShowHorizontalLines
1128 * @see #setShowGrid
1129 * @see #setShowVerticalLines
1130 * @beaninfo
1131 * bound: true
1132 * description: Whether horizontal lines should be drawn in between the cells.
1133 */
1134 public void setShowHorizontalLines(boolean showHorizontalLines) {
1135 boolean old = this.showHorizontalLines;
1136 this.showHorizontalLines = showHorizontalLines;
1137 firePropertyChange("showHorizontalLines", old, showHorizontalLines);
1138
1139 // Redraw
1140 repaint();
1141 }
1142
1143 /**
1144 * Sets whether the table draws vertical lines between cells.
1145 * If {@code showVerticalLines} is true it does; if it is false it doesn't.
1146 *
1147 * @param showVerticalLines true if table view should draw vertical lines
1148 * @see #getShowVerticalLines
1149 * @see #setShowGrid
1150 * @see #setShowHorizontalLines
1151 * @beaninfo
1152 * bound: true
1153 * description: Whether vertical lines should be drawn in between the cells.
1154 */
1155 public void setShowVerticalLines(boolean showVerticalLines) {
1156 boolean old = this.showVerticalLines;
1157 this.showVerticalLines = showVerticalLines;
1158 firePropertyChange("showVerticalLines", old, showVerticalLines);
1159 // Redraw
1160 repaint();
1161 }
1162
1163 /**
1164 * Returns true if the table draws horizontal lines between cells, false if it
1165 * doesn't. The default value is look and feel dependent.
1224 || (mode == AUTO_RESIZE_NEXT_COLUMN)
1225 || (mode == AUTO_RESIZE_SUBSEQUENT_COLUMNS)
1226 || (mode == AUTO_RESIZE_LAST_COLUMN)
1227 || (mode == AUTO_RESIZE_ALL_COLUMNS);
1228 }
1229
1230 /**
1231 * Returns the auto resize mode of the table. The default mode
1232 * is AUTO_RESIZE_SUBSEQUENT_COLUMNS.
1233 *
1234 * @return the autoResizeMode of the table
1235 *
1236 * @see #setAutoResizeMode
1237 * @see #doLayout
1238 */
1239 public int getAutoResizeMode() {
1240 return autoResizeMode;
1241 }
1242
1243 /**
1244 * Sets this table's {@code autoCreateColumnsFromModel} flag.
1245 * This method calls {@code createDefaultColumnsFromModel} if
1246 * {@code autoCreateColumnsFromModel} changes from false to true.
1247 *
1248 * @param autoCreateColumnsFromModel true if {@code JTable} should automatically create columns
1249 * @see #getAutoCreateColumnsFromModel
1250 * @see #createDefaultColumnsFromModel
1251 * @beaninfo
1252 * bound: true
1253 * description: Automatically populates the columnModel when a new TableModel is submitted.
1254 */
1255 public void setAutoCreateColumnsFromModel(boolean autoCreateColumnsFromModel) {
1256 if (this.autoCreateColumnsFromModel != autoCreateColumnsFromModel) {
1257 boolean old = this.autoCreateColumnsFromModel;
1258 this.autoCreateColumnsFromModel = autoCreateColumnsFromModel;
1259 if (autoCreateColumnsFromModel) {
1260 createDefaultColumnsFromModel();
1261 }
1262 firePropertyChange("autoCreateColumnsFromModel", old, autoCreateColumnsFromModel);
1263 }
1264 }
1265
1266 /**
1267 * Determines whether the table will create default columns from the model.
1268 * If true, {@code setModel} will clear any existing columns and
1269 * create new columns from the new model. Also, if the event in
1270 * the {@code tableChanged} notification specifies that the
1271 * entire table changed, then the columns will be rebuilt.
1272 * The default is true.
1273 *
1274 * @return the autoCreateColumnsFromModel of the table
1275 * @see #setAutoCreateColumnsFromModel
1276 * @see #createDefaultColumnsFromModel
1277 */
1278 public boolean getAutoCreateColumnsFromModel() {
1279 return autoCreateColumnsFromModel;
1280 }
1281
1282 /**
1283 * Creates default columns for the table from
1284 * the data model using the {@code getColumnCount} method
1285 * defined in the {@code TableModel} interface.
1286 * <p>
1287 * Clears any existing columns before creating the
1288 * new columns based on information from the model.
1289 *
1290 * @see #getAutoCreateColumnsFromModel
1291 */
1292 public void createDefaultColumnsFromModel() {
1293 TableModel m = getModel();
1294 if (m != null) {
1295 // Remove any current columns
1296 TableColumnModel cm = getColumnModel();
1297 while (cm.getColumnCount() > 0) {
1298 cm.removeColumn(cm.getColumn(0));
1299 }
1300
1301 // Create new columns from the data model info
1302 for (int i = 0; i < m.getColumnCount(); i++) {
1303 TableColumn newColumn = new TableColumn(i);
1304 addColumn(newColumn);
1305 }
1306 }
1307 }
1308
1309 /**
1310 * Sets a default cell renderer to be used if no renderer has been set in
1311 * a {@code TableColumn}. If renderer is {@code null},
1312 * removes the default renderer for this column class.
1313 *
1314 * @param columnClass set the default cell renderer for this columnClass
1315 * @param renderer default cell renderer to be used for this
1316 * columnClass
1317 * @see #getDefaultRenderer
1318 * @see #setDefaultEditor
1319 */
1320 public void setDefaultRenderer(Class<?> columnClass, TableCellRenderer renderer) {
1321 if (renderer != null) {
1322 defaultRenderersByColumnClass.put(columnClass, renderer);
1323 }
1324 else {
1325 defaultRenderersByColumnClass.remove(columnClass);
1326 }
1327 }
1328
1329 /**
1330 * Returns the cell renderer to be used when no renderer has been set in
1331 * a {@code TableColumn}. During the rendering of cells the renderer is fetched from
1332 * a {@code Hashtable} of entries according to the class of the cells in the column. If
1333 * there is no entry for this {@code columnClass} the method returns
1334 * the entry for the most specific superclass. The {@code JTable} installs entries
1335 * for {@code Object}, {@code Number}, and {@code Boolean}, all of which can be modified
1336 * or replaced.
1337 *
1338 * @param columnClass return the default cell renderer
1339 * for this columnClass
1340 * @return the renderer for this columnClass
1341 * @see #setDefaultRenderer
1342 * @see #getColumnClass
1343 */
1344 public TableCellRenderer getDefaultRenderer(Class<?> columnClass) {
1345 if (columnClass == null) {
1346 return null;
1347 }
1348 else {
1349 Object renderer = defaultRenderersByColumnClass.get(columnClass);
1350 if (renderer != null) {
1351 return (TableCellRenderer)renderer;
1352 }
1353 else {
1354 Class<?> c = columnClass.getSuperclass();
1355 if (c == null && columnClass != Object.class) {
1356 c = Object.class;
1357 }
1358 return getDefaultRenderer(c);
1359 }
1360 }
1361 }
1362
1363 /**
1364 * Sets a default cell editor to be used if no editor has been set in
1365 * a {@code TableColumn}. If no editing is required in a table, or a
1366 * particular column in a table, uses the {@code isCellEditable}
1367 * method in the {@code TableModel} interface to ensure that this
1368 * {@code JTable} will not start an editor in these columns.
1369 * If editor is {@code null}, removes the default editor for this
1370 * column class.
1371 *
1372 * @param columnClass set the default cell editor for this columnClass
1373 * @param editor default cell editor to be used for this columnClass
1374 * @see TableModel#isCellEditable
1375 * @see #getDefaultEditor
1376 * @see #setDefaultRenderer
1377 */
1378 public void setDefaultEditor(Class<?> columnClass, TableCellEditor editor) {
1379 if (editor != null) {
1380 defaultEditorsByColumnClass.put(columnClass, editor);
1381 }
1382 else {
1383 defaultEditorsByColumnClass.remove(columnClass);
1384 }
1385 }
1386
1387 /**
1388 * Returns the editor to be used when no editor has been set in
1389 * a {@code TableColumn}. During the editing of cells the editor is fetched from
1390 * a {@code Hashtable} of entries according to the class of the cells in the column. If
1391 * there is no entry for this {@code columnClass} the method returns
1392 * the entry for the most specific superclass. The {@code JTable} installs entries
1393 * for {@code Object}, {@code Number}, and {@code Boolean}, all of which can be modified
1394 * or replaced.
1395 *
1396 * @param columnClass return the default cell editor for this columnClass
1397 * @return the default cell editor to be used for this columnClass
1398 * @see #setDefaultEditor
1399 * @see #getColumnClass
1400 */
1401 public TableCellEditor getDefaultEditor(Class<?> columnClass) {
1402 if (columnClass == null) {
1403 return null;
1404 }
1405 else {
1406 Object editor = defaultEditorsByColumnClass.get(columnClass);
1407 if (editor != null) {
1408 return (TableCellEditor)editor;
1409 }
1410 else {
1411 return getDefaultEditor(columnClass.getSuperclass());
1412 }
1413 }
1417 * Turns on or off automatic drag handling. In order to enable automatic
1418 * drag handling, this property should be set to {@code true}, and the
1419 * table's {@code TransferHandler} needs to be {@code non-null}.
1420 * The default value of the {@code dragEnabled} property is {@code false}.
1421 * <p>
1422 * The job of honoring this property, and recognizing a user drag gesture,
1423 * lies with the look and feel implementation, and in particular, the table's
1424 * {@code TableUI}. When automatic drag handling is enabled, most look and
1425 * feels (including those that subclass {@code BasicLookAndFeel}) begin a
1426 * drag and drop operation whenever the user presses the mouse button over
1427 * an item (in single selection mode) or a selection (in other selection
1428 * modes) and then moves the mouse a few pixels. Setting this property to
1429 * {@code true} can therefore have a subtle effect on how selections behave.
1430 * <p>
1431 * If a look and feel is used that ignores this property, you can still
1432 * begin a drag and drop operation by calling {@code exportAsDrag} on the
1433 * table's {@code TransferHandler}.
1434 *
1435 * @param b whether or not to enable automatic drag handling
1436 * @exception HeadlessException if
1437 * {@code b} is {@code true} and
1438 * {@code GraphicsEnvironment.isHeadless()}
1439 * returns {@code true}
1440 * @see java.awt.GraphicsEnvironment#isHeadless
1441 * @see #getDragEnabled
1442 * @see #setTransferHandler
1443 * @see TransferHandler
1444 * @since 1.4
1445 *
1446 * @beaninfo
1447 * description: determines whether automatic drag handling is enabled
1448 * bound: false
1449 */
1450 public void setDragEnabled(boolean b) {
1451 checkDragEnabled(b);
1452 dragEnabled = b;
1453 }
1454
1455 private void checkDragEnabled(boolean b) {
1456 if (b && GraphicsEnvironment.isHeadless()) {
1457 throw new HeadlessException();
1458 }
1459 }
1460
1461 /**
1462 * Returns whether or not automatic drag handling is enabled.
1463 *
1464 * @return the value of the {@code dragEnabled} property
1465 * @see #setDragEnabled
1466 * @since 1.4
1467 */
1468 public boolean getDragEnabled() {
1469 return dragEnabled;
1470 }
1471
1472 /**
1473 * Sets the drop mode for this component. For backward compatibility,
1474 * the default for this property is {@code DropMode.USE_SELECTION}.
1475 * Usage of one of the other modes is recommended, however, for an
1476 * improved user experience. {@code DropMode.ON}, for instance,
1477 * offers similar behavior of showing items as selected, but does so without
1478 * affecting the actual selection in the table.
1479 * <p>
1480 * {@code JTable} supports the following drop modes:
1481 * <ul>
1482 * <li>{@code DropMode.USE_SELECTION}</li>
1483 * <li>{@code DropMode.ON}</li>
1484 * <li>{@code DropMode.INSERT}</li>
1485 * <li>{@code DropMode.INSERT_ROWS}</li>
1486 * <li>{@code DropMode.INSERT_COLS}</li>
1487 * <li>{@code DropMode.ON_OR_INSERT}</li>
1488 * <li>{@code DropMode.ON_OR_INSERT_ROWS}</li>
1489 * <li>{@code DropMode.ON_OR_INSERT_COLS}</li>
1490 * </ul>
1491 * <p>
1492 * The drop mode is only meaningful if this component has a
1493 * {@code TransferHandler} that accepts drops.
1494 *
1495 * @param dropMode the drop mode to use
1496 * @throws IllegalArgumentException if the drop mode is unsupported
1497 * or {@code null}
1498 * @see #getDropMode
1499 * @see #getDropLocation
1500 * @see #setTransferHandler
1501 * @see TransferHandler
1502 * @since 1.6
1503 */
1504 public final void setDropMode(DropMode dropMode) {
1505 checkDropMode(dropMode);
1506 this.dropMode = dropMode;
1507 }
1508
1509 private static void checkDropMode(DropMode dropMode) {
1510 if (dropMode != null) {
1511 switch (dropMode) {
1512 case USE_SELECTION:
1513 case ON:
1514 case INSERT:
1515 case INSERT_ROWS:
1516 case INSERT_COLS:
1517 case ON_OR_INSERT:
1522 }
1523 throw new IllegalArgumentException(dropMode
1524 + ": Unsupported drop mode for table");
1525 }
1526 /**
1527 * Returns the drop mode for this component.
1528 *
1529 * @return the drop mode for this component
1530 * @see #setDropMode
1531 * @since 1.6
1532 */
1533 public final DropMode getDropMode() {
1534 return dropMode;
1535 }
1536
1537 /**
1538 * Calculates a drop location in this component, representing where a
1539 * drop at the given point should insert data.
1540 *
1541 * @param p the point to calculate a drop location for
1542 * @return the drop location, or {@code null}
1543 */
1544 DropLocation dropLocationForPoint(Point p) {
1545 DropLocation location = null;
1546
1547 int row = rowAtPoint(p);
1548 int col = columnAtPoint(p);
1549 boolean outside = Boolean.TRUE == getClientProperty("Table.isFileList")
1550 && SwingUtilities2.pointOutsidePrefSize(this, row, col, p);
1551
1552 Rectangle rect = getCellRect(row, col, true);
1553 Section xSection, ySection;
1554 boolean between = false;
1555 boolean ltr = getComponentOrientation().isLeftToRight();
1556
1557 switch(dropMode) {
1558 case USE_SELECTION:
1559 case ON:
1560 if (row == -1 || col == -1 || outside) {
1561 location = new DropLocation(p, -1, -1, false, false);
1562 } else {
1718 }
1719
1720 /**
1721 * Called to set or clear the drop location during a DnD operation.
1722 * In some cases, the component may need to use it's internal selection
1723 * temporarily to indicate the drop location. To help facilitate this,
1724 * this method returns and accepts as a parameter a state object.
1725 * This state object can be used to store, and later restore, the selection
1726 * state. Whatever this method returns will be passed back to it in
1727 * future calls, as the state parameter. If it wants the DnD system to
1728 * continue storing the same state, it must pass it back every time.
1729 * Here's how this is used:
1730 * <p>
1731 * Let's say that on the first call to this method the component decides
1732 * to save some state (because it is about to use the selection to show
1733 * a drop index). It can return a state object to the caller encapsulating
1734 * any saved selection state. On a second call, let's say the drop location
1735 * is being changed to something else. The component doesn't need to
1736 * restore anything yet, so it simply passes back the same state object
1737 * to have the DnD system continue storing it. Finally, let's say this
1738 * method is messaged with {@code null}. This means DnD
1739 * is finished with this component for now, meaning it should restore
1740 * state. At this point, it can use the state parameter to restore
1741 * said state, and of course return {@code null} since there's
1742 * no longer anything to store.
1743 *
1744 * @param location the drop location (as calculated by
1745 * {@code dropLocationForPoint}) or {@code null}
1746 * if there's no longer a valid drop location
1747 * @param state the state object saved earlier for this component,
1748 * or {@code null}
1749 * @param forDrop whether or not the method is being called because an
1750 * actual drop occurred
1751 * @return any saved state for this component, or {@code null} if none
1752 */
1753 Object setDropLocation(TransferHandler.DropLocation location,
1754 Object state,
1755 boolean forDrop) {
1756
1757 Object retVal = null;
1758 DropLocation tableLocation = (DropLocation)location;
1759
1760 if (dropMode == DropMode.USE_SELECTION) {
1761 if (tableLocation == null) {
1762 if (!forDrop && state != null) {
1763 clearSelection();
1764
1765 int[] rows = ((int[][])state)[0];
1766 int[] cols = ((int[][])state)[1];
1767 int[] anchleads = ((int[][])state)[2];
1768
1769 for (int row : rows) {
1770 addRowSelectionInterval(row, row);
1771 }
1806 setColumnSelectionInterval(tableLocation.getColumn(),
1807 tableLocation.getColumn());
1808 }
1809 }
1810 }
1811
1812 DropLocation old = dropLocation;
1813 dropLocation = tableLocation;
1814 firePropertyChange("dropLocation", old, dropLocation);
1815
1816 return retVal;
1817 }
1818
1819 /**
1820 * Returns the location that this component should visually indicate
1821 * as the drop location during a DnD operation over the component,
1822 * or {@code null} if no location is to currently be shown.
1823 * <p>
1824 * This method is not meant for querying the drop location
1825 * from a {@code TransferHandler}, as the drop location is only
1826 * set after the {@code TransferHandler}'s {@code canImport}
1827 * has returned and has allowed for the location to be shown.
1828 * <p>
1829 * When this property changes, a property change event with
1830 * name "dropLocation" is fired by the component.
1831 *
1832 * @return the drop location
1833 * @see #setDropMode
1834 * @see TransferHandler#canImport(TransferHandler.TransferSupport)
1835 * @since 1.6
1836 */
1837 public final DropLocation getDropLocation() {
1838 return dropLocation;
1839 }
1840
1841 /**
1842 * Specifies whether a {@code RowSorter} should be created for the
1843 * table whenever its model changes.
1844 * <p>
1845 * When {@code setAutoCreateRowSorter(true)} is invoked, a {@code
1846 * TableRowSorter} is immediately created and installed on the
1896 * @since 1.6
1897 */
1898 public void setUpdateSelectionOnSort(boolean update) {
1899 if (updateSelectionOnSort != update) {
1900 updateSelectionOnSort = update;
1901 firePropertyChange("updateSelectionOnSort", !update, update);
1902 }
1903 }
1904
1905 /**
1906 * Returns true if the selection should be updated after sorting.
1907 *
1908 * @return whether to update the selection on a sort
1909 * @since 1.6
1910 */
1911 public boolean getUpdateSelectionOnSort() {
1912 return updateSelectionOnSort;
1913 }
1914
1915 /**
1916 * Sets the {@code RowSorter}. {@code RowSorter} is used
1917 * to provide sorting and filtering to a {@code JTable}.
1918 * <p>
1919 * This method clears the selection and resets any variable row heights.
1920 * <p>
1921 * This method fires a {@code PropertyChangeEvent} when appropriate,
1922 * with the property name {@code "rowSorter"}. For
1923 * backward-compatibility, this method fires an additional event with the
1924 * property name {@code "sorter"}.
1925 * <p>
1926 * If the underlying model of the {@code RowSorter} differs from
1927 * that of this {@code JTable} undefined behavior will result.
1928 *
1929 * @param sorter the {@code RowSorter}; {@code null} turns
1930 * sorting off
1931 * @see javax.swing.table.TableRowSorter
1932 * @beaninfo
1933 * bound: true
1934 * description: The table's RowSorter
1935 * @since 1.6
1936 */
1937 public void setRowSorter(RowSorter<? extends TableModel> sorter) {
1938 RowSorter<? extends TableModel> oldRowSorter = null;
1939 if (sortManager != null) {
1940 oldRowSorter = sortManager.sorter;
1941 sortManager.dispose();
1942 sortManager = null;
1943 }
1944 rowModel = null;
1945 clearSelectionAndLeadAnchor();
1946 if (sorter != null) {
1947 sortManager = new SortManager(sorter);
1948 }
1949 resizeAndRepaint();
1952 }
1953
1954 /**
1955 * Returns the object responsible for sorting.
1956 *
1957 * @return the object responsible for sorting
1958 * @since 1.6
1959 */
1960 public RowSorter<? extends TableModel> getRowSorter() {
1961 return (sortManager != null) ? sortManager.sorter : null;
1962 }
1963
1964 //
1965 // Selection methods
1966 //
1967 /**
1968 * Sets the table's selection mode to allow only single selections, a single
1969 * contiguous interval, or multiple intervals.
1970 * <P>
1971 * <b>Note:</b>
1972 * {@code JTable} provides all the methods for handling
1973 * column and row selection. When setting states,
1974 * such as {@code setSelectionMode}, it not only
1975 * updates the mode for the row selection model but also sets similar
1976 * values in the selection model of the {@code columnModel}.
1977 * If you want to have the row and column selection models operating
1978 * in different modes, set them both directly.
1979 * <p>
1980 * Both the row and column selection models for {@code JTable}
1981 * default to using a {@code DefaultListSelectionModel}
1982 * so that {@code JTable} works the same way as the
1983 * {@code JList}. See the {@code setSelectionMode} method
1984 * in {@code JList} for details about the modes.
1985 *
1986 * @param selectionMode the mode used by the row and column selection models
1987 * @see JList#setSelectionMode
1988 * @beaninfo
1989 * description: The selection mode used by the row and column selection models.
1990 * enum: SINGLE_SELECTION ListSelectionModel.SINGLE_SELECTION
1991 * SINGLE_INTERVAL_SELECTION ListSelectionModel.SINGLE_INTERVAL_SELECTION
1992 * MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
1993 */
1994 public void setSelectionMode(int selectionMode) {
1995 clearSelection();
1996 getSelectionModel().setSelectionMode(selectionMode);
1997 getColumnModel().getSelectionModel().setSelectionMode(selectionMode);
1998 }
1999
2000 /**
2001 * Sets whether the rows in this model can be selected.
2002 *
2003 * @param rowSelectionAllowed true if this model will allow row selection
2004 * @see #getRowSelectionAllowed
2042 if (old != columnSelectionAllowed) {
2043 repaint();
2044 }
2045 firePropertyChange("columnSelectionAllowed", old, columnSelectionAllowed);
2046 }
2047
2048 /**
2049 * Returns true if columns can be selected.
2050 *
2051 * @return true if columns can be selected, otherwise false
2052 * @see #setColumnSelectionAllowed
2053 */
2054 public boolean getColumnSelectionAllowed() {
2055 return columnModel.getColumnSelectionAllowed();
2056 }
2057
2058 /**
2059 * Sets whether this table allows both a column selection and a
2060 * row selection to exist simultaneously. When set,
2061 * the table treats the intersection of the row and column selection
2062 * models as the selected cells. Override {@code isCellSelected} to
2063 * change this default behavior. This method is equivalent to setting
2064 * both the {@code rowSelectionAllowed} property and
2065 * {@code columnSelectionAllowed} property of the
2066 * {@code columnModel} to the supplied value.
2067 *
2068 * @param cellSelectionEnabled true if simultaneous row and column
2069 * selection is allowed
2070 * @see #getCellSelectionEnabled
2071 * @see #isCellSelected
2072 * @beaninfo
2073 * bound: true
2074 * attribute: visualUpdate true
2075 * description: Select a rectangular region of cells rather than
2076 * rows or columns.
2077 */
2078 public void setCellSelectionEnabled(boolean cellSelectionEnabled) {
2079 setRowSelectionAllowed(cellSelectionEnabled);
2080 setColumnSelectionAllowed(cellSelectionEnabled);
2081 boolean old = this.cellSelectionEnabled;
2082 this.cellSelectionEnabled = cellSelectionEnabled;
2083 firePropertyChange("cellSelectionEnabled", old, cellSelectionEnabled);
2084 }
2085
2086 /**
2087 * Returns true if both row and column selection models are enabled.
2088 * Equivalent to
2089 * {@code getRowSelectionAllowed() && getColumnSelectionAllowed()}.
2090 *
2091 * @return true if both row and column selection models are enabled
2092 *
2093 * @see #setCellSelectionEnabled
2094 */
2095 public boolean getCellSelectionEnabled() {
2096 return getRowSelectionAllowed() && getColumnSelectionAllowed();
2097 }
2098
2099 /**
2100 * Selects all rows, columns, and cells in the table.
2101 */
2102 public void selectAll() {
2103 // If I'm currently editing, then I should stop editing
2104 if (isEditing()) {
2105 removeEditor();
2106 }
2107 if (getRowCount() > 0 && getColumnCount() > 0) {
2108 int oldLead;
2109 int oldAnchor;
2161 private int getAdjustedIndex(int index, boolean row) {
2162 int compare = row ? getRowCount() : getColumnCount();
2163 return index < compare ? index : -1;
2164 }
2165
2166 private int boundRow(int row) throws IllegalArgumentException {
2167 if (row < 0 || row >= getRowCount()) {
2168 throw new IllegalArgumentException("Row index out of range");
2169 }
2170 return row;
2171 }
2172
2173 private int boundColumn(int col) {
2174 if (col< 0 || col >= getColumnCount()) {
2175 throw new IllegalArgumentException("Column index out of range");
2176 }
2177 return col;
2178 }
2179
2180 /**
2181 * Selects the rows from {@code index0} to {@code index1},
2182 * inclusive.
2183 *
2184 * @exception IllegalArgumentException if {@code index0} or
2185 * {@code index1} lie outside
2186 * [0, {@code getRowCount()}-1]
2187 * @param index0 one end of the interval
2188 * @param index1 the other end of the interval
2189 */
2190 public void setRowSelectionInterval(int index0, int index1) {
2191 selectionModel.setSelectionInterval(boundRow(index0), boundRow(index1));
2192 }
2193
2194 /**
2195 * Selects the columns from {@code index0} to {@code index1},
2196 * inclusive.
2197 *
2198 * @exception IllegalArgumentException if {@code index0} or
2199 * {@code index1} lie outside
2200 * [0, {@code getColumnCount()}-1]
2201 * @param index0 one end of the interval
2202 * @param index1 the other end of the interval
2203 */
2204 public void setColumnSelectionInterval(int index0, int index1) {
2205 columnModel.getSelectionModel().setSelectionInterval(boundColumn(index0), boundColumn(index1));
2206 }
2207
2208 /**
2209 * Adds the rows from {@code index0} to {@code index1}, inclusive, to
2210 * the current selection.
2211 *
2212 * @exception IllegalArgumentException if {@code index0} or {@code index1}
2213 * lie outside [0, {@code getRowCount()}-1]
2214 * @param index0 one end of the interval
2215 * @param index1 the other end of the interval
2216 */
2217 public void addRowSelectionInterval(int index0, int index1) {
2218 selectionModel.addSelectionInterval(boundRow(index0), boundRow(index1));
2219 }
2220
2221 /**
2222 * Adds the columns from {@code index0} to {@code index1},
2223 * inclusive, to the current selection.
2224 *
2225 * @exception IllegalArgumentException if {@code index0} or
2226 * {@code index1} lie outside
2227 * [0, {@code getColumnCount()}-1]
2228 * @param index0 one end of the interval
2229 * @param index1 the other end of the interval
2230 */
2231 public void addColumnSelectionInterval(int index0, int index1) {
2232 columnModel.getSelectionModel().addSelectionInterval(boundColumn(index0), boundColumn(index1));
2233 }
2234
2235 /**
2236 * Deselects the rows from {@code index0} to {@code index1}, inclusive.
2237 *
2238 * @exception IllegalArgumentException if {@code index0} or
2239 * {@code index1} lie outside
2240 * [0, {@code getRowCount()}-1]
2241 * @param index0 one end of the interval
2242 * @param index1 the other end of the interval
2243 */
2244 public void removeRowSelectionInterval(int index0, int index1) {
2245 selectionModel.removeSelectionInterval(boundRow(index0), boundRow(index1));
2246 }
2247
2248 /**
2249 * Deselects the columns from {@code index0} to {@code index1}, inclusive.
2250 *
2251 * @exception IllegalArgumentException if {@code index0} or
2252 * {@code index1} lie outside
2253 * [0, {@code getColumnCount()}-1]
2254 * @param index0 one end of the interval
2255 * @param index1 the other end of the interval
2256 */
2257 public void removeColumnSelectionInterval(int index0, int index1) {
2258 columnModel.getSelectionModel().removeSelectionInterval(boundColumn(index0), boundColumn(index1));
2259 }
2260
2261 /**
2262 * Returns the index of the first selected row, -1 if no row is selected.
2263 * @return the index of the first selected row
2264 */
2265 public int getSelectedRow() {
2266 return selectionModel.getMinSelectionIndex();
2267 }
2268
2269 /**
2270 * Returns the index of the first selected column,
2271 * -1 if no column is selected.
2272 * @return the index of the first selected column
2273 */
2328 count++;
2329 }
2330 }
2331 return count;
2332 }
2333
2334 /**
2335 * Returns the number of selected columns.
2336 *
2337 * @return the number of selected columns, 0 if no columns are selected
2338 */
2339 public int getSelectedColumnCount() {
2340 return columnModel.getSelectedColumnCount();
2341 }
2342
2343 /**
2344 * Returns true if the specified index is in the valid range of rows,
2345 * and the row at that index is selected.
2346 *
2347 * @param row a row in the row model
2348 * @return true if {@code row} is a valid index and the row at
2349 * that index is selected (where 0 is the first row)
2350 */
2351 public boolean isRowSelected(int row) {
2352 return selectionModel.isSelectedIndex(row);
2353 }
2354
2355 /**
2356 * Returns true if the specified index is in the valid range of columns,
2357 * and the column at that index is selected.
2358 *
2359 * @param column the column in the column model
2360 * @return true if {@code column} is a valid index and the column at
2361 * that index is selected (where 0 is the first column)
2362 */
2363 public boolean isColumnSelected(int column) {
2364 return columnModel.getSelectionModel().isSelectedIndex(column);
2365 }
2366
2367 /**
2368 * Returns true if the specified indices are in the valid range of rows
2369 * and columns and the cell at the specified position is selected.
2370 * @param row the row being queried
2371 * @param column the column being queried
2372 *
2373 * @return true if {@code row} and {@code column} are valid indices
2374 * and the cell at index {@code (row, column)} is selected,
2375 * where the first row and first column are at index 0
2376 */
2377 public boolean isCellSelected(int row, int column) {
2378 if (!getRowSelectionAllowed() && !getColumnSelectionAllowed()) {
2379 return false;
2380 }
2381 return (!getRowSelectionAllowed() || isRowSelected(row)) &&
2382 (!getColumnSelectionAllowed() || isColumnSelected(column));
2383 }
2384
2385 private void changeSelectionModel(ListSelectionModel sm, int index,
2386 boolean toggle, boolean extend, boolean selected,
2387 int anchor, boolean anchorSelected) {
2388 if (extend) {
2389 if (toggle) {
2390 if (anchorSelected) {
2391 sm.addSelectionInterval(anchor, index);
2392 } else {
2393 sm.removeSelectionInterval(anchor, index);
2394 // this is a Windows-only behavior that we want for file lists
2402 sm.setSelectionInterval(anchor, index);
2403 }
2404 }
2405 else {
2406 if (toggle) {
2407 if (selected) {
2408 sm.removeSelectionInterval(index, index);
2409 }
2410 else {
2411 sm.addSelectionInterval(index, index);
2412 }
2413 }
2414 else {
2415 sm.setSelectionInterval(index, index);
2416 }
2417 }
2418 }
2419
2420 /**
2421 * Updates the selection models of the table, depending on the state of the
2422 * two flags: {@code toggle} and {@code extend}. Most changes
2423 * to the selection that are the result of keyboard or mouse events received
2424 * by the UI are channeled through this method so that the behavior may be
2425 * overridden by a subclass. Some UIs may need more functionality than
2426 * this method provides, such as when manipulating the lead for discontiguous
2427 * selection, and may not call into this method for some selection changes.
2428 * <p>
2429 * This implementation uses the following conventions:
2430 * <ul>
2431 * <li> {@code toggle}: <em>false</em>, {@code extend}: <em>false</em>.
2432 * Clear the previous selection and ensure the new cell is selected.
2433 * <li> {@code toggle}: <em>false</em>, {@code extend}: <em>true</em>.
2434 * Extend the previous selection from the anchor to the specified cell,
2435 * clearing all other selections.
2436 * <li> {@code toggle}: <em>true</em>, {@code extend}: <em>false</em>.
2437 * If the specified cell is selected, deselect it. If it is not selected, select it.
2438 * <li> {@code toggle}: <em>true</em>, {@code extend}: <em>true</em>.
2439 * Apply the selection state of the anchor to all cells between it and the
2440 * specified cell.
2441 * </ul>
2442 * @param rowIndex affects the selection at {@code row}
2443 * @param columnIndex affects the selection at {@code column}
2444 * @param toggle see description above
2445 * @param extend if true, extend the current selection
2446 *
2447 * @since 1.3
2448 */
2449 public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
2450 ListSelectionModel rsm = getSelectionModel();
2451 ListSelectionModel csm = getColumnModel().getSelectionModel();
2452
2453 int anchorRow = getAdjustedIndex(rsm.getAnchorSelectionIndex(), true);
2454 int anchorCol = getAdjustedIndex(csm.getAnchorSelectionIndex(), false);
2455
2456 boolean anchorSelected = true;
2457
2458 if (anchorRow == -1) {
2459 if (getRowCount() > 0) {
2460 anchorRow = 0;
2461 }
2462 anchorSelected = false;
2463 }
2481
2482 changeSelectionModel(csm, columnIndex, toggle, extend, selected,
2483 anchorCol, anchorSelected);
2484 changeSelectionModel(rsm, rowIndex, toggle, extend, selected,
2485 anchorRow, anchorSelected);
2486
2487 // Scroll after changing the selection as blit scrolling is immediate,
2488 // so that if we cause the repaint after the scroll we end up painting
2489 // everything!
2490 if (getAutoscrolls()) {
2491 Rectangle cellRect = getCellRect(rowIndex, columnIndex, false);
2492 if (cellRect != null) {
2493 scrollRectToVisible(cellRect);
2494 }
2495 }
2496 }
2497
2498 /**
2499 * Returns the foreground color for selected cells.
2500 *
2501 * @return the {@code Color} object for the foreground property
2502 * @see #setSelectionForeground
2503 * @see #setSelectionBackground
2504 */
2505 public Color getSelectionForeground() {
2506 return selectionForeground;
2507 }
2508
2509 /**
2510 * Sets the foreground color for selected cells. Cell renderers
2511 * can use this color to render text and graphics for selected
2512 * cells.
2513 * <p>
2514 * The default value of this property is defined by the look
2515 * and feel implementation.
2516 * <p>
2517 * This is a <a href="http://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html">JavaBeans</a> bound property.
2518 *
2519 * @param selectionForeground the {@code Color} to use in the foreground
2520 * for selected list items
2521 * @see #getSelectionForeground
2522 * @see #setSelectionBackground
2523 * @see #setForeground
2524 * @see #setBackground
2525 * @see #setFont
2526 * @beaninfo
2527 * bound: true
2528 * description: A default foreground color for selected cells.
2529 */
2530 public void setSelectionForeground(Color selectionForeground) {
2531 Color old = this.selectionForeground;
2532 this.selectionForeground = selectionForeground;
2533 firePropertyChange("selectionForeground", old, selectionForeground);
2534 repaint();
2535 }
2536
2537 /**
2538 * Returns the background color for selected cells.
2539 *
2540 * @return the {@code Color} used for the background of selected list items
2541 * @see #setSelectionBackground
2542 * @see #setSelectionForeground
2543 */
2544 public Color getSelectionBackground() {
2545 return selectionBackground;
2546 }
2547
2548 /**
2549 * Sets the background color for selected cells. Cell renderers
2550 * can use this color to the fill selected cells.
2551 * <p>
2552 * The default value of this property is defined by the look
2553 * and feel implementation.
2554 * <p>
2555 * This is a <a href="http://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html">JavaBeans</a> bound property.
2556 *
2557 * @param selectionBackground the {@code Color} to use for the background
2558 * of selected cells
2559 * @see #getSelectionBackground
2560 * @see #setSelectionForeground
2561 * @see #setForeground
2562 * @see #setBackground
2563 * @see #setFont
2564 * @beaninfo
2565 * bound: true
2566 * description: A default background color for selected cells.
2567 */
2568 public void setSelectionBackground(Color selectionBackground) {
2569 Color old = this.selectionBackground;
2570 this.selectionBackground = selectionBackground;
2571 firePropertyChange("selectionBackground", old, selectionBackground);
2572 repaint();
2573 }
2574
2575 /**
2576 * Returns the {@code TableColumn} object for the column in the table
2577 * whose identifier is equal to {@code identifier}, when compared using
2578 * {@code equals}.
2579 *
2580 * @return the {@code TableColumn} object that matches the identifier
2581 * @exception IllegalArgumentException if {@code identifier} is {@code null} or no {@code TableColumn} has this identifier
2582 *
2583 * @param identifier the identifier object
2584 */
2585 public TableColumn getColumn(Object identifier) {
2586 TableColumnModel cm = getColumnModel();
2587 int columnIndex = cm.getColumnIndex(identifier);
2588 return cm.getColumn(columnIndex);
2589 }
2590
2591 //
2592 // Informally implement the TableModel interface.
2593 //
2594
2595 /**
2596 * Maps the index of the column in the view at
2597 * {@code viewColumnIndex} to the index of the column
2598 * in the table model. Returns the index of the corresponding
2599 * column in the model. If {@code viewColumnIndex}
2600 * is less than zero, returns {@code viewColumnIndex}.
2601 *
2602 * @param viewColumnIndex the index of the column in the view
2603 * @return the index of the corresponding column in the model
2604 *
2605 * @see #convertColumnIndexToView
2606 */
2607 public int convertColumnIndexToModel(int viewColumnIndex) {
2608 return SwingUtilities2.convertColumnIndexToModel(
2609 getColumnModel(), viewColumnIndex);
2610 }
2611
2612 /**
2613 * Maps the index of the column in the table model at
2614 * {@code modelColumnIndex} to the index of the column
2615 * in the view. Returns the index of the
2616 * corresponding column in the view; returns -1 if this column is not
2617 * being displayed. If {@code modelColumnIndex} is less than zero,
2618 * returns {@code modelColumnIndex}.
2619 *
2620 * @param modelColumnIndex the index of the column in the model
2621 * @return the index of the corresponding column in the view
2622 *
2623 * @see #convertColumnIndexToModel
2624 */
2625 public int convertColumnIndexToView(int modelColumnIndex) {
2626 return SwingUtilities2.convertColumnIndexToView(
2627 getColumnModel(), modelColumnIndex);
2628 }
2629
2630 /**
2631 * Maps the index of the row in terms of the
2632 * {@code TableModel} to the view. If the contents of the
2633 * model are not sorted the model and view indices are the same.
2634 *
2635 * @param modelRowIndex the index of the row in terms of the model
2636 * @return the index of the corresponding row in the view, or -1 if
2637 * the row isn't visible
2638 * @throws IndexOutOfBoundsException if sorting is enabled and passed an
2639 * index outside the number of rows of the {@code TableModel}
2640 * @see javax.swing.table.TableRowSorter
2641 * @since 1.6
2642 */
2643 public int convertRowIndexToView(int modelRowIndex) {
2644 RowSorter<?> sorter = getRowSorter();
2645 if (sorter != null) {
2646 return sorter.convertRowIndexToView(modelRowIndex);
2647 }
2648 return modelRowIndex;
2649 }
2650
2651 /**
2652 * Maps the index of the row in terms of the view to the
2653 * underlying {@code TableModel}. If the contents of the
2654 * model are not sorted the model and view indices are the same.
2655 *
2656 * @param viewRowIndex the index of the row in the view
2657 * @return the index of the corresponding row in the model
2658 * @throws IndexOutOfBoundsException if sorting is enabled and passed an
2659 * index outside the range of the {@code JTable} as
2660 * determined by the method {@code getRowCount}
2661 * @see javax.swing.table.TableRowSorter
2662 * @see #getRowCount
2663 * @since 1.6
2664 */
2665 public int convertRowIndexToModel(int viewRowIndex) {
2666 RowSorter<?> sorter = getRowSorter();
2667 if (sorter != null) {
2668 return sorter.convertRowIndexToModel(viewRowIndex);
2669 }
2670 return viewRowIndex;
2671 }
2672
2673 /**
2674 * Returns the number of rows that can be shown in the
2675 * {@code JTable}, given unlimited space. If a
2676 * {@code RowSorter} with a filter has been specified, the
2677 * number of rows returned may differ from that of the underlying
2678 * {@code TableModel}.
2679 *
2680 * @return the number of rows shown in the {@code JTable}
2681 * @see #getColumnCount
2682 */
2683 public int getRowCount() {
2684 RowSorter<?> sorter = getRowSorter();
2685 if (sorter != null) {
2686 return sorter.getViewRowCount();
2687 }
2688 return getModel().getRowCount();
2689 }
2690
2691 /**
2692 * Returns the number of columns in the column model. Note that this may
2693 * be different from the number of columns in the table model.
2694 *
2695 * @return the number of columns in the table
2696 * @see #getRowCount
2697 * @see #removeColumn
2698 */
2699 public int getColumnCount() {
2700 return getColumnModel().getColumnCount();
2701 }
2702
2703 /**
2704 * Returns the name of the column appearing in the view at
2705 * column position {@code column}.
2706 *
2707 * @param column the column in the view being queried
2708 * @return the name of the column at position {@code column}
2709 in the view where the first column is column 0
2710 */
2711 public String getColumnName(int column) {
2712 return getModel().getColumnName(convertColumnIndexToModel(column));
2713 }
2714
2715 /**
2716 * Returns the type of the column appearing in the view at
2717 * column position {@code column}.
2718 *
2719 * @param column the column in the view being queried
2720 * @return the type of the column at position {@code column}
2721 * in the view where the first column is column 0
2722 */
2723 public Class<?> getColumnClass(int column) {
2724 return getModel().getColumnClass(convertColumnIndexToModel(column));
2725 }
2726
2727 /**
2728 * Returns the cell value at {@code row} and {@code column}.
2729 * <p>
2730 * <b>Note</b>: The column is specified in the table view's display
2731 * order, and not in the {@code TableModel}'s column
2732 * order. This is an important distinction because as the
2733 * user rearranges the columns in the table,
2734 * the column at a given index in the view will change.
2735 * Meanwhile the user's actions never affect the model's
2736 * column ordering.
2737 *
2738 * @param row the row whose value is to be queried
2739 * @param column the column whose value is to be queried
2740 * @return the Object at the specified cell
2741 */
2742 public Object getValueAt(int row, int column) {
2743 return getModel().getValueAt(convertRowIndexToModel(row),
2744 convertColumnIndexToModel(column));
2745 }
2746
2747 /**
2748 * Sets the value for the cell in the table model at {@code row}
2749 * and {@code column}.
2750 * <p>
2751 * <b>Note</b>: The column is specified in the table view's display
2752 * order, and not in the {@code TableModel}'s column
2753 * order. This is an important distinction because as the
2754 * user rearranges the columns in the table,
2755 * the column at a given index in the view will change.
2756 * Meanwhile the user's actions never affect the model's
2757 * column ordering.
2758 *
2759 * {@code aValue} is the new value.
2760 *
2761 * @param aValue the new value
2762 * @param row the row of the cell to be changed
2763 * @param column the column of the cell to be changed
2764 * @see #getValueAt
2765 */
2766 public void setValueAt(Object aValue, int row, int column) {
2767 getModel().setValueAt(aValue, convertRowIndexToModel(row),
2768 convertColumnIndexToModel(column));
2769 }
2770
2771 /**
2772 * Returns true if the cell at {@code row} and {@code column}
2773 * is editable. Otherwise, invoking {@code setValueAt} on the cell
2774 * will have no effect.
2775 * <p>
2776 * <b>Note</b>: The column is specified in the table view's display
2777 * order, and not in the {@code TableModel}'s column
2778 * order. This is an important distinction because as the
2779 * user rearranges the columns in the table,
2780 * the column at a given index in the view will change.
2781 * Meanwhile the user's actions never affect the model's
2782 * column ordering.
2783 *
2784 *
2785 * @param row the row whose value is to be queried
2786 * @param column the column whose value is to be queried
2787 * @return true if the cell is editable
2788 * @see #setValueAt
2789 */
2790 public boolean isCellEditable(int row, int column) {
2791 return getModel().isCellEditable(convertRowIndexToModel(row),
2792 convertColumnIndexToModel(column));
2793 }
2794 //
2795 // Adding and removing columns in the view
2796 //
2797
2798 /**
2799 * Appends {@code aColumn} to the end of the array of columns held by
2800 * this {@code JTable}'s column model.
2801 * If the column name of {@code aColumn} is {@code null},
2802 * sets the column name of {@code aColumn} to the name
2803 * returned by {@code getModel().getColumnName()}.
2804 * <p>
2805 * To add a column to this {@code JTable} to display the
2806 * {@code modelColumn}'th column of data in the model with a
2807 * given {@code width}, {@code cellRenderer},
2808 * and {@code cellEditor} you can use:
2809 * <pre>
2810 *
2811 * addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
2812 *
2813 * </pre>
2814 * [Any of the {@code TableColumn} constructors can be used
2815 * instead of this one.]
2816 * The model column number is stored inside the {@code TableColumn}
2817 * and is used during rendering and editing to locate the appropriates
2818 * data values in the model. The model column number does not change
2819 * when columns are reordered in the view.
2820 *
2821 * @param aColumn the {@code TableColumn} to be added
2822 * @see #removeColumn
2823 */
2824 public void addColumn(TableColumn aColumn) {
2825 if (aColumn.getHeaderValue() == null) {
2826 int modelColumn = aColumn.getModelIndex();
2827 String columnName = getModel().getColumnName(modelColumn);
2828 aColumn.setHeaderValue(columnName);
2829 }
2830 getColumnModel().addColumn(aColumn);
2831 }
2832
2833 /**
2834 * Removes {@code aColumn} from this {@code JTable}'s
2835 * array of columns. Note: this method does not remove the column
2836 * of data from the model; it just removes the {@code TableColumn}
2837 * that was responsible for displaying it.
2838 *
2839 * @param aColumn the {@code TableColumn} to be removed
2840 * @see #addColumn
2841 */
2842 public void removeColumn(TableColumn aColumn) {
2843 getColumnModel().removeColumn(aColumn);
2844 }
2845
2846 /**
2847 * Moves the column {@code column} to the position currently
2848 * occupied by the column {@code targetColumn} in the view.
2849 * The old column at {@code targetColumn} is
2850 * shifted left or right to make room.
2851 *
2852 * @param column the index of column to be moved
2853 * @param targetColumn the new index of the column
2854 */
2855 public void moveColumn(int column, int targetColumn) {
2856 getColumnModel().moveColumn(column, targetColumn);
2857 }
2858
2859 //
2860 // Cover methods for various models and helper methods
2861 //
2862
2863 /**
2864 * Returns the index of the column that {@code point} lies in,
2865 * or -1 if the result is not in the range
2866 * [0, {@code getColumnCount()}-1].
2867 *
2868 * @param point the location of interest
2869 * @return the index of the column that {@code point} lies in,
2870 * or -1 if the result is not in the range
2871 * [0, {@code getColumnCount()}-1]
2872 * @see #rowAtPoint
2873 */
2874 public int columnAtPoint(Point point) {
2875 int x = point.x;
2876 if( !getComponentOrientation().isLeftToRight() ) {
2877 x = getWidth() - x - 1;
2878 }
2879 return getColumnModel().getColumnIndexAtX(x);
2880 }
2881
2882 /**
2883 * Returns the index of the row that {@code point} lies in,
2884 * or -1 if the result is not in the range
2885 * [0, {@code getRowCount()}-1].
2886 *
2887 * @param point the location of interest
2888 * @return the index of the row that {@code point} lies in,
2889 * or -1 if the result is not in the range
2890 * [0, {@code getRowCount()}-1]
2891 * @see #columnAtPoint
2892 */
2893 public int rowAtPoint(Point point) {
2894 int y = point.y;
2895 int result = (rowModel == null) ? y/getRowHeight() : rowModel.getIndex(y);
2896 if (result < 0) {
2897 return -1;
2898 }
2899 else if (result >= getRowCount()) {
2900 return -1;
2901 }
2902 else {
2903 return result;
2904 }
2905 }
2906
2907 /**
2908 * Returns a rectangle for the cell that lies at the intersection of
2909 * {@code row} and {@code column}.
2910 * If {@code includeSpacing} is true then the value returned
2911 * has the full height and width of the row and column
2912 * specified. If it is false, the returned rectangle is inset by the
2913 * intercell spacing to return the true bounds of the rendering or
2914 * editing component as it will be set during rendering.
2915 * <p>
2916 * If the column index is valid but the row index is less
2917 * than zero the method returns a rectangle with the
2918 * {@code y} and {@code height} values set appropriately
2919 * and the {@code x} and {@code width} values both set
2920 * to zero. In general, when either the row or column indices indicate a
2921 * cell outside the appropriate range, the method returns a rectangle
2922 * depicting the closest edge of the closest cell that is within
2923 * the table's range. When both row and column indices are out
2924 * of range the returned rectangle covers the closest
2925 * point of the closest cell.
2926 * <p>
2927 * In all cases, calculations that use this method to calculate
2928 * results along one axis will not fail because of anomalies in
2929 * calculations along the other axis. When the cell is not valid
2930 * the {@code includeSpacing} parameter is ignored.
2931 *
2932 * @param row the row index where the desired cell
2933 * is located
2934 * @param column the column index where the desired cell
2935 * is located in the display; this is not
2936 * necessarily the same as the column index
2937 * in the data model for the table; the
2938 * {@link #convertColumnIndexToView(int)}
2939 * method may be used to convert a data
2940 * model column index to a display
2941 * column index
2942 * @param includeSpacing if false, return the true cell bounds -
2943 * computed by subtracting the intercell
2944 * spacing from the height and widths of
2945 * the column and row models
2946 *
2947 * @return the rectangle containing the cell at location
2948 * {@code row},{@code column}
2949 * @see #getIntercellSpacing
2950 */
2951 public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
2952 Rectangle r = new Rectangle();
2953 boolean valid = true;
2954 if (row < 0) {
2955 // y = height = 0;
2956 valid = false;
2957 }
2958 else if (row >= getRowCount()) {
2959 r.y = getHeight();
2960 valid = false;
2961 }
2962 else {
2963 r.height = getRowHeight(row);
2964 r.y = (rowModel == null) ? row * r.height : rowModel.getPosition(row);
2965 }
2966
2967 if (column < 0) {
2968 if( !getComponentOrientation().isLeftToRight() ) {
3001 r.setBounds(r.x + cm/2, r.y + rm/2, r.width - cm, r.height - rm);
3002 }
3003 return r;
3004 }
3005
3006 private int viewIndexForColumn(TableColumn aColumn) {
3007 TableColumnModel cm = getColumnModel();
3008 for (int column = 0; column < cm.getColumnCount(); column++) {
3009 if (cm.getColumn(column) == aColumn) {
3010 return column;
3011 }
3012 }
3013 return -1;
3014 }
3015
3016 /**
3017 * Causes this table to lay out its rows and columns. Overridden so
3018 * that columns can be resized to accommodate a change in the size of
3019 * a containing parent.
3020 * Resizes one or more of the columns in the table
3021 * so that the total width of all of this {@code JTable}'s
3022 * columns is equal to the width of the table.
3023 * <p>
3024 * Before the layout begins the method gets the
3025 * {@code resizingColumn} of the {@code tableHeader}.
3026 * When the method is called as a result of the resizing of an enclosing window,
3027 * the {@code resizingColumn} is {@code null}. This means that resizing
3028 * has taken place "outside" the {@code JTable} and the change -
3029 * or "delta" - should be distributed to all of the columns regardless
3030 * of this {@code JTable}'s automatic resize mode.
3031 * <p>
3032 * If the {@code resizingColumn} is not {@code null}, it is one of
3033 * the columns in the table that has changed size rather than
3034 * the table itself. In this case the auto-resize modes govern
3035 * the way the extra (or deficit) space is distributed
3036 * amongst the available columns.
3037 * <p>
3038 * The modes are:
3039 * <ul>
3040 * <li> AUTO_RESIZE_OFF: Don't automatically adjust the column's
3041 * widths at all. Use a horizontal scrollbar to accommodate the
3042 * columns when their sum exceeds the width of the
3043 * {@code Viewport}. If the {@code JTable} is not
3044 * enclosed in a {@code JScrollPane} this may
3045 * leave parts of the table invisible.
3046 * <li> AUTO_RESIZE_NEXT_COLUMN: Use just the column after the
3047 * resizing column. This results in the "boundary" or divider
3048 * between adjacent cells being independently adjustable.
3049 * <li> AUTO_RESIZE_SUBSEQUENT_COLUMNS: Use all columns after the
3050 * one being adjusted to absorb the changes. This is the
3051 * default behavior.
3052 * <li> AUTO_RESIZE_LAST_COLUMN: Automatically adjust the
3053 * size of the last column only. If the bounds of the last column
3054 * prevent the desired size from being allocated, set the
3055 * width of the last column to the appropriate limit and make
3056 * no further adjustments.
3057 * <li> AUTO_RESIZE_ALL_COLUMNS: Spread the delta amongst all the columns
3058 * in the {@code JTable}, including the one that is being
3059 * adjusted.
3060 * </ul>
3061 * <p>
3062 * <b>Note:</b> When a {@code JTable} makes adjustments
3063 * to the widths of the columns it respects their minimum and
3064 * maximum values absolutely. It is therefore possible that,
3065 * even after this method is called, the total width of the columns
3066 * is still not equal to the width of the table. When this happens
3067 * the {@code JTable} does not put itself
3068 * in AUTO_RESIZE_OFF mode to bring up a scroll bar, or break other
3069 * commitments of its current auto-resize mode -- instead it
3070 * allows its bounds to be set larger (or smaller) than the total of the
3071 * column minimum or maximum, meaning, either that there
3072 * will not be enough room to display all of the columns, or that the
3073 * columns will not fill the {@code JTable}'s bounds.
3074 * These respectively, result in the clipping of some columns
3075 * or an area being painted in the {@code JTable}'s
3076 * background color during painting.
3077 * <p>
3078 * The mechanism for distributing the delta amongst the available
3079 * columns is provided in a private method in the {@code JTable}
3080 * class:
3081 * <pre>
3082 * adjustSizes(long targetSize, final Resizable3 r, boolean inverse)
3083 * </pre>
3084 * an explanation of which is provided in the following section.
3085 * {@code Resizable3} is a private
3086 * interface that allows any data structure containing a collection
3087 * of elements with a size, preferred size, maximum size and minimum size
3088 * to have its elements manipulated by the algorithm.
3089 *
3090 * <H3> Distributing the delta </H3>
3091 *
3092 * <H4> Overview </H4>
3093 * <P>
3094 * Call "DELTA" the difference between the target size and the
3095 * sum of the preferred sizes of the elements in r. The individual
3096 * sizes are calculated by taking the original preferred
3097 * sizes and adding a share of the DELTA - that share being based on
3098 * how far each preferred size is from its limiting bound (minimum or
3099 * maximum).
3100 *
3101 * <H4>Definition</H4>
3102 * <P>
3103 * Call the individual constraints min[i], max[i], and pref[i].
3104 * <p>
3105 * Call their respective sums: MIN, MAX, and PREF.
3121 * If (DELTA > 0) we are in expand mode where:
3122 *
3123 * <PRE>
3124 * DELTA
3125 * delta[i] = ------------ * (max[i] - pref[i])
3126 * (MAX - PREF)
3127 * </PRE>
3128 * <P>
3129 * The overall effect is that the total size moves that same percentage,
3130 * k, towards the total minimum or maximum and that percentage guarantees
3131 * accommodation of the required space, DELTA.
3132 *
3133 * <H4>Details</H4>
3134 * <P>
3135 * Naive evaluation of the formulae presented here would be subject to
3136 * the aggregated rounding errors caused by doing this operation in finite
3137 * precision (using ints). To deal with this, the multiplying factor above,
3138 * is constantly recalculated and this takes account of the rounding
3139 * errors in the previous iterations. The result is an algorithm that
3140 * produces a set of integers whose values exactly sum to the supplied
3141 * {@code targetSize}, and does so by spreading the rounding
3142 * errors evenly over the given elements.
3143 *
3144 * <H4>When the MAX and MIN bounds are hit</H4>
3145 * <P>
3146 * When {@code targetSize} is outside the [MIN, MAX] range,
3147 * the algorithm sets all sizes to their appropriate limiting value
3148 * (maximum or minimum).
3149 *
3150 */
3151 public void doLayout() {
3152 TableColumn resizingColumn = getResizingColumn();
3153 if (resizingColumn == null) {
3154 setWidthsFromPreferredWidths(false);
3155 }
3156 else {
3157 // JTable behaves like a layout manger - but one in which the
3158 // user can come along and dictate how big one of the children
3159 // (columns) is supposed to be.
3160
3161 // A column has been resized and JTable may need to distribute
3162 // any overall delta to other columns, according to the resize mode.
3163 int columnIndex = viewIndexForColumn(resizingColumn);
3164 int delta = getWidth() - getColumnModel().getTotalColumnWidth();
3165 accommodateDelta(columnIndex, delta);
3166 delta = getWidth() - getColumnModel().getTotalColumnWidth();
3184 // Thereafter, during window resizing etc. it has to work off
3185 // the preferred sizes as usual - the idea being that, whatever
3186 // the user does, everything stays in synch and things don't jump
3187 // around.
3188 setWidthsFromPreferredWidths(true);
3189 }
3190
3191 super.doLayout();
3192 }
3193
3194 private TableColumn getResizingColumn() {
3195 return (tableHeader == null) ? null
3196 : tableHeader.getResizingColumn();
3197 }
3198
3199 /**
3200 * Sizes the table columns to fit the available space.
3201 *
3202 * @param lastColumnOnly determines whether to resize last column only
3203 * @deprecated As of Swing version 1.0.3,
3204 * replaced by {@code doLayout()}.
3205 * @see #doLayout
3206 */
3207 @Deprecated
3208 public void sizeColumnsToFit(boolean lastColumnOnly) {
3209 int oldAutoResizeMode = autoResizeMode;
3210 setAutoResizeMode(lastColumnOnly ? AUTO_RESIZE_LAST_COLUMN
3211 : AUTO_RESIZE_ALL_COLUMNS);
3212 sizeColumnsToFit(-1);
3213 setAutoResizeMode(oldAutoResizeMode);
3214 }
3215
3216 /**
3217 * Obsolete as of Java 2 platform v1.4. Please use the
3218 * {@code doLayout()} method instead.
3219 * @param resizingColumn the column whose resizing made this adjustment
3220 * necessary or -1 if there is no such column
3221 * @see #doLayout
3222 */
3223 public void sizeColumnsToFit(int resizingColumn) {
3224 if (resizingColumn == -1) {
3225 setWidthsFromPreferredWidths(false);
3226 }
3227 else {
3228 if (autoResizeMode == AUTO_RESIZE_OFF) {
3229 TableColumn aColumn = getColumnModel().getColumn(resizingColumn);
3230 aColumn.setPreferredWidth(aColumn.getWidth());
3231 }
3232 else {
3233 int delta = getWidth() - getColumnModel().getTotalColumnWidth();
3234 accommodateDelta(resizingColumn, delta);
3235 setWidthsFromPreferredWidths(true);
3236 }
3237 }
3238 }
3374 // In this case, lowerBound == upperBound, for all subsequent terms.
3375 int newSize;
3376 if (totalLowerBound == totalUpperBound) {
3377 newSize = lowerBound;
3378 }
3379 else {
3380 double f = (double)(target - totalLowerBound)/(totalUpperBound - totalLowerBound);
3381 newSize = (int)Math.round(lowerBound+f*(upperBound - lowerBound));
3382 // We'd need to round manually in an all integer version.
3383 // size[i] = (int)(((totalUpperBound - target) * lowerBound +
3384 // (target - totalLowerBound) * upperBound)/(totalUpperBound-totalLowerBound));
3385 }
3386 r.setSizeAt(newSize, i);
3387 target -= newSize;
3388 totalLowerBound -= lowerBound;
3389 totalUpperBound -= upperBound;
3390 }
3391 }
3392
3393 /**
3394 * Overrides {@code JComponent}'s {@code getToolTipText}
3395 * method in order to allow the renderer's tips to be used
3396 * if it has text set.
3397 * <p>
3398 * <b>Note:</b> For {@code JTable} to properly display
3399 * tooltips of its renderers
3400 * {@code JTable} must be a registered component with the
3401 * {@code ToolTipManager}.
3402 * This is done automatically in {@code initializeLocalVars},
3403 * but if at a later point {@code JTable} is told
3404 * {@code setToolTipText(null)} it will unregister the table
3405 * component, and no tips from renderers will display anymore.
3406 *
3407 * @see JComponent#getToolTipText
3408 */
3409 public String getToolTipText(MouseEvent event) {
3410 String tip = null;
3411 Point p = event.getPoint();
3412
3413 // Locate the renderer under the event location
3414 int hitColumnIndex = columnAtPoint(p);
3415 int hitRowIndex = rowAtPoint(p);
3416
3417 if ((hitColumnIndex != -1) && (hitRowIndex != -1)) {
3418 TableCellRenderer renderer = getCellRenderer(hitRowIndex, hitColumnIndex);
3419 Component component = prepareRenderer(renderer, hitRowIndex, hitColumnIndex);
3420
3421 // Now have to see if the component is a JComponent before
3422 // getting the tip
3423 if (component instanceof JComponent) {
3424 // Convert the event to the renderer's coordinate system
3466 public void setSurrendersFocusOnKeystroke(boolean surrendersFocusOnKeystroke) {
3467 this.surrendersFocusOnKeystroke = surrendersFocusOnKeystroke;
3468 }
3469
3470 /**
3471 * Returns true if the editor should get the focus
3472 * when keystrokes cause the editor to be activated
3473 *
3474 * @return true if the editor should get the focus
3475 * when keystrokes cause the editor to be
3476 * activated
3477 *
3478 * @see #setSurrendersFocusOnKeystroke
3479 * @since 1.4
3480 */
3481 public boolean getSurrendersFocusOnKeystroke() {
3482 return surrendersFocusOnKeystroke;
3483 }
3484
3485 /**
3486 * Programmatically starts editing the cell at {@code row} and
3487 * {@code column}, if those indices are in the valid range, and
3488 * the cell at those indices is editable.
3489 * Note that this is a convenience method for
3490 * {@code editCellAt(int, int, null)}.
3491 *
3492 * @param row the row to be edited
3493 * @param column the column to be edited
3494 * @return false if for any reason the cell cannot be edited,
3495 * or if the indices are invalid
3496 */
3497 public boolean editCellAt(int row, int column) {
3498 return editCellAt(row, column, null);
3499 }
3500
3501 /**
3502 * Programmatically starts editing the cell at {@code row} and
3503 * {@code column}, if those indices are in the valid range, and
3504 * the cell at those indices is editable.
3505 * To prevent the {@code JTable} from
3506 * editing a particular table, column or cell value, return false from
3507 * the {@code isCellEditable} method in the {@code TableModel}
3508 * interface.
3509 *
3510 * @param row the row to be edited
3511 * @param column the column to be edited
3512 * @param e event to pass into {@code shouldSelectCell};
3513 * note that as of Java 2 platform v1.2, the call to
3514 * {@code shouldSelectCell} is no longer made
3515 * @return false if for any reason the cell cannot be edited,
3516 * or if the indices are invalid
3517 */
3518 public boolean editCellAt(int row, int column, EventObject e){
3519 if (cellEditor != null && !cellEditor.stopCellEditing()) {
3520 return false;
3521 }
3522
3523 if (row < 0 || row >= getRowCount() ||
3524 column < 0 || column >= getColumnCount()) {
3525 return false;
3526 }
3527
3528 if (!isCellEditable(row, column))
3529 return false;
3530
3531 if (editorRemover == null) {
3532 KeyboardFocusManager fm =
3533 KeyboardFocusManager.getCurrentKeyboardFocusManager();
3534 editorRemover = new CellEditorRemover(fm);
3592
3593 /**
3594 * Returns the index of the row that contains the cell currently
3595 * being edited. If nothing is being edited, returns -1.
3596 *
3597 * @return the index of the row that contains the cell currently
3598 * being edited; returns -1 if nothing being edited
3599 * @see #editingColumn
3600 */
3601 public int getEditingRow() {
3602 return editingRow;
3603 }
3604
3605 //
3606 // Managing TableUI
3607 //
3608
3609 /**
3610 * Returns the L&F object that renders this component.
3611 *
3612 * @return the {@code TableUI} object that renders this component
3613 */
3614 public TableUI getUI() {
3615 return (TableUI)ui;
3616 }
3617
3618 /**
3619 * Sets the L&F object that renders this component and repaints.
3620 *
3621 * @param ui the TableUI L&F object
3622 * @see UIDefaults#getUI
3623 * @beaninfo
3624 * bound: true
3625 * hidden: true
3626 * attribute: visualUpdate true
3627 * description: The UI object that implements the Component's LookAndFeel.
3628 */
3629 public void setUI(TableUI ui) {
3630 if (this.ui != ui) {
3631 super.setUI(ui);
3632 repaint();
3633 }
3634 }
3635
3636 /**
3637 * Notification from the {@code UIManager} that the L&F has changed.
3638 * Replaces the current UI object with the latest version from the
3639 * {@code UIManager}.
3640 *
3641 * @see JComponent#updateUI
3642 */
3643 public void updateUI() {
3644 // Update the UIs of the cell renderers, cell editors and header renderers.
3645 TableColumnModel cm = getColumnModel();
3646 for(int column = 0; column < cm.getColumnCount(); column++) {
3647 TableColumn aColumn = cm.getColumn(column);
3648 SwingUtilities.updateRendererOrEditorUI(aColumn.getCellRenderer());
3649 SwingUtilities.updateRendererOrEditorUI(aColumn.getCellEditor());
3650 SwingUtilities.updateRendererOrEditorUI(aColumn.getHeaderRenderer());
3651 }
3652
3653 // Update the UIs of all the default renderers.
3654 Enumeration<?> defaultRenderers = defaultRenderersByColumnClass.elements();
3655 while (defaultRenderers.hasMoreElements()) {
3656 SwingUtilities.updateRendererOrEditorUI(defaultRenderers.nextElement());
3657 }
3658
3659 // Update the UIs of all the default editors.
3812 }
3813 }
3814
3815 /**
3816 * Returns the {@code ListSelectionModel} that is used to maintain row
3817 * selection state.
3818 *
3819 * @return the object that provides row selection state, {@code null} if row
3820 * selection is not allowed
3821 * @see #setSelectionModel
3822 */
3823 public ListSelectionModel getSelectionModel() {
3824 return selectionModel;
3825 }
3826
3827 //
3828 // RowSorterListener
3829 //
3830
3831 /**
3832 * {@code RowSorterListener} notification that the
3833 * {@code RowSorter} has changed in some way.
3834 *
3835 * @param e the {@code RowSorterEvent} describing the change
3836 * @throws NullPointerException if {@code e} is {@code null}
3837 * @since 1.6
3838 */
3839 public void sorterChanged(RowSorterEvent e) {
3840 if (e.getType() == RowSorterEvent.Type.SORT_ORDER_CHANGED) {
3841 JTableHeader header = getTableHeader();
3842 if (header != null) {
3843 header.repaint();
3844 }
3845 }
3846 else if (e.getType() == RowSorterEvent.Type.SORTED) {
3847 sorterChanged = true;
3848 if (!ignoreSortChange) {
3849 sortedTableChanged(e, null);
3850 }
3851 }
3852 }
3853
3854
3855 /**
3856 * SortManager provides support for managing the selection and variable
4108 int length;
4109
4110 // True if the event indicates all the contents have changed
4111 boolean allRowsChanged;
4112
4113 ModelChange(TableModelEvent e) {
4114 startModelIndex = Math.max(0, e.getFirstRow());
4115 endModelIndex = e.getLastRow();
4116 modelRowCount = getModel().getRowCount();
4117 if (endModelIndex < 0) {
4118 endModelIndex = Math.max(0, modelRowCount - 1);
4119 }
4120 length = endModelIndex - startModelIndex + 1;
4121 type = e.getType();
4122 event = e;
4123 allRowsChanged = (e.getLastRow() == Integer.MAX_VALUE);
4124 }
4125 }
4126
4127 /**
4128 * Invoked when {@code sorterChanged} is invoked, or
4129 * when {@code tableChanged} is invoked and sorting is enabled.
4130 */
4131 private void sortedTableChanged(RowSorterEvent sortedEvent,
4132 TableModelEvent e) {
4133 int editingModelIndex = -1;
4134 ModelChange change = (e != null) ? new ModelChange(e) : null;
4135
4136 if ((change == null || !change.allRowsChanged) &&
4137 this.editingRow != -1) {
4138 editingModelIndex = convertRowIndexToModel(sortedEvent,
4139 this.editingRow);
4140 }
4141
4142 sortManager.prepareForChange(sortedEvent, change);
4143
4144 if (e != null) {
4145 if (change.type == TableModelEvent.UPDATE) {
4146 repaintSortedRows(change);
4147 }
4148 notifySorter(change);
4149 if (change.type != TableModelEvent.UPDATE) {
4365 private int convertRowIndexToModel(RowSorterEvent e, int viewIndex) {
4366 if (e != null) {
4367 if (e.getPreviousRowCount() == 0) {
4368 return viewIndex;
4369 }
4370 // range checking handled by RowSorterEvent
4371 return e.convertPreviousRowIndexToModel(viewIndex);
4372 }
4373 // Make sure the viewIndex is valid
4374 if (viewIndex < 0 || viewIndex >= getRowCount()) {
4375 return -1;
4376 }
4377 return convertRowIndexToModel(viewIndex);
4378 }
4379
4380 //
4381 // Implementing TableModelListener interface
4382 //
4383
4384 /**
4385 * Invoked when this table's {@code TableModel} generates
4386 * a {@code TableModelEvent}.
4387 * The {@code TableModelEvent} should be constructed in the
4388 * coordinate system of the model; the appropriate mapping to the
4389 * view coordinate system is performed by this {@code JTable}
4390 * when it receives the event.
4391 * <p>
4392 * Application code will not use these methods explicitly, they
4393 * are used internally by {@code JTable}.
4394 * <p>
4395 * Note that as of 1.3, this method clears the selection, if any.
4396 */
4397 public void tableChanged(TableModelEvent e) {
4398 if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
4399 // The whole thing changed
4400 clearSelectionAndLeadAnchor();
4401
4402 rowModel = null;
4403
4404 if (sortManager != null) {
4405 try {
4406 ignoreSortChange = true;
4407 sortManager.sorter.modelStructureChanged();
4408 } finally {
4409 ignoreSortChange = false;
4410 }
4411 sortManager.allChanged();
4412 }
4413
4624 * @see TableColumnModelListener
4625 */
4626 public void columnMarginChanged(ChangeEvent e) {
4627 if (isEditing() && !getCellEditor().stopCellEditing()) {
4628 getCellEditor().cancelCellEditing();
4629 }
4630 TableColumn resizingColumn = getResizingColumn();
4631 // Need to do this here, before the parent's
4632 // layout manager calls getPreferredSize().
4633 if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF) {
4634 resizingColumn.setPreferredWidth(resizingColumn.getWidth());
4635 }
4636 resizeAndRepaint();
4637 }
4638
4639 private int limit(int i, int a, int b) {
4640 return Math.min(b, Math.max(i, a));
4641 }
4642
4643 /**
4644 * Invoked when the selection model of the {@code TableColumnModel}
4645 * is changed.
4646 * <p>
4647 * Application code will not use these methods explicitly, they
4648 * are used internally by JTable.
4649 *
4650 * @param e the event received
4651 * @see TableColumnModelListener
4652 */
4653 public void columnSelectionChanged(ListSelectionEvent e) {
4654 boolean isAdjusting = e.getValueIsAdjusting();
4655 if (columnSelectionAdjusting && !isAdjusting) {
4656 // The assumption is that when the model is no longer adjusting
4657 // we will have already gotten all the changes, and therefore
4658 // don't need to do an additional paint.
4659 columnSelectionAdjusting = false;
4660 return;
4661 }
4662 columnSelectionAdjusting = isAdjusting;
4663 // The getCellRect() call will fail unless there is at least one row.
4664 if (getRowCount() <= 0 || getColumnCount() <= 0) {
4764 * Invoked when editing is canceled. The editor object is discarded
4765 * and the cell is rendered once again.
4766 * <p>
4767 * Application code will not use these methods explicitly, they
4768 * are used internally by JTable.
4769 *
4770 * @param e the event received
4771 * @see CellEditorListener
4772 */
4773 public void editingCanceled(ChangeEvent e) {
4774 removeEditor();
4775 }
4776
4777 //
4778 // Implementing the Scrollable interface
4779 //
4780
4781 /**
4782 * Sets the preferred size of the viewport for this table.
4783 *
4784 * @param size a {@code Dimension} object specifying the {@code preferredSize} of a
4785 * {@code JViewport} whose view is this table
4786 * @see Scrollable#getPreferredScrollableViewportSize
4787 * @beaninfo
4788 * description: The preferred size of the viewport.
4789 */
4790 public void setPreferredScrollableViewportSize(Dimension size) {
4791 preferredViewportSize = size;
4792 }
4793
4794 /**
4795 * Returns the preferred size of the viewport for this table.
4796 *
4797 * @return a {@code Dimension} object containing the {@code preferredSize} of the {@code JViewport}
4798 * which displays this table
4799 * @see Scrollable#getPreferredScrollableViewportSize
4800 */
4801 public Dimension getPreferredScrollableViewportSize() {
4802 return preferredViewportSize;
4803 }
4804
4805 /**
4806 * Returns the scroll increment (in pixels) that completely exposes one new
4807 * row or column (depending on the orientation).
4808 * <p>
4809 * This method is called each time the user requests a unit scroll.
4810 *
4811 * @param visibleRect the view area visible within the viewport
4812 * @param orientation either {@code SwingConstants.VERTICAL}
4813 * or {@code SwingConstants.HORIZONTAL}
4814 * @param direction less than zero to scroll up/left,
4815 * greater than zero for down/right
4816 * @return the "unit" increment for scrolling in the specified direction
4817 * @see Scrollable#getScrollableUnitIncrement
4818 */
4819 public int getScrollableUnitIncrement(Rectangle visibleRect,
4820 int orientation,
4821 int direction) {
4822 int leadingRow;
4823 int leadingCol;
4824 Rectangle leadingCellRect;
4825
4826 int leadingVisibleEdge;
4827 int leadingCellEdge;
4828 int leadingCellSize;
4829
4830 leadingRow = getLeadingRow(visibleRect);
4831 leadingCol = getLeadingCol(visibleRect);
4832 if (orientation == SwingConstants.VERTICAL && leadingRow < 0) {
4833 // Couldn't find leading row - return some default value
4888 else { // Case #2: hide leading cell
4889 return leadingCellSize;
4890 }
4891 }
4892 else { // Leading cell is partially hidden
4893 // Compute visible, hidden portions
4894 int hiddenAmt = Math.abs(leadingVisibleEdge - leadingCellEdge);
4895 int visibleAmt = leadingCellSize - hiddenAmt;
4896
4897 if (direction > 0) {
4898 // Case #3: hide showing portion of leading cell
4899 return visibleAmt;
4900 }
4901 else { // Case #4: reveal hidden portion of leading cell
4902 return hiddenAmt;
4903 }
4904 }
4905 }
4906
4907 /**
4908 * Returns {@code visibleRect.height} or
4909 * {@code visibleRect.width},
4910 * depending on this table's orientation. Note that as of Swing 1.1.1
4911 * (Java 2 v 1.2.2) the value
4912 * returned will ensure that the viewport is cleanly aligned on
4913 * a row boundary.
4914 *
4915 * @return {@code visibleRect.height} or
4916 * {@code visibleRect.width}
4917 * per the orientation
4918 * @see Scrollable#getScrollableBlockIncrement
4919 */
4920 public int getScrollableBlockIncrement(Rectangle visibleRect,
4921 int orientation, int direction) {
4922
4923 if (getRowCount() == 0) {
4924 // Short-circuit empty table model
4925 if (SwingConstants.VERTICAL == orientation) {
4926 int rh = getRowHeight();
4927 return (rh > 0) ? Math.max(rh, (visibleRect.height / rh) * rh) :
4928 visibleRect.height;
4929 }
4930 else {
4931 return visibleRect.width;
4932 }
4933 }
4934 // Shortcut for vertical scrolling of a table w/ uniform row height
4935 if (null == rowModel && SwingConstants.VERTICAL == orientation) {
4936 int row = rowAtPoint(visibleRect.getLocation());
5196 }
5197
5198 /*
5199 * Returns the trailing edge ("end") of the given Rectangle.
5200 * For VERTICAL, this is the bottom, for left-to-right, the right side, and
5201 * for right-to-left, the left side.
5202 */
5203 private int trailingEdge(Rectangle rect, int orientation) {
5204 if (orientation == SwingConstants.VERTICAL) {
5205 return rect.y + rect.height;
5206 }
5207 else if (getComponentOrientation().isLeftToRight()) {
5208 return rect.x + rect.width;
5209 }
5210 else { // Horizontal, right-to-left
5211 return rect.x;
5212 }
5213 }
5214
5215 /**
5216 * Returns false if {@code autoResizeMode} is set to
5217 * {@code AUTO_RESIZE_OFF}, which indicates that the
5218 * width of the viewport does not determine the width
5219 * of the table. Otherwise returns true.
5220 *
5221 * @return false if {@code autoResizeMode} is set
5222 * to {@code AUTO_RESIZE_OFF}, otherwise returns true
5223 * @see Scrollable#getScrollableTracksViewportWidth
5224 */
5225 public boolean getScrollableTracksViewportWidth() {
5226 return !(autoResizeMode == AUTO_RESIZE_OFF);
5227 }
5228
5229 /**
5230 * Returns {@code false} to indicate that the height of the viewport does
5231 * not determine the height of the table, unless
5232 * {@code getFillsViewportHeight} is {@code true} and the preferred height
5233 * of the table is smaller than the viewport's height.
5234 *
5235 * @return {@code false} unless {@code getFillsViewportHeight} is
5236 * {@code true} and the table needs to be stretched to fill
5237 * the viewport
5238 * @see Scrollable#getScrollableTracksViewportHeight
5239 * @see #setFillsViewportHeight
5240 * @see #getFillsViewportHeight
5241 */
5242 public boolean getScrollableTracksViewportHeight() {
5572 setAutoResizeMode(AUTO_RESIZE_SUBSEQUENT_COLUMNS);
5573 setRowHeight(16);
5574 isRowHeightSet = false;
5575 setRowMargin(1);
5576 setRowSelectionAllowed(true);
5577 setCellEditor(null);
5578 setEditingColumn(-1);
5579 setEditingRow(-1);
5580 setSurrendersFocusOnKeystroke(false);
5581 setPreferredScrollableViewportSize(new Dimension(450, 400));
5582
5583 // I'm registered to do tool tips so we can draw tips for the renderers
5584 ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
5585 toolTipManager.registerComponent(this);
5586
5587 setAutoscrolls(true);
5588 }
5589
5590 /**
5591 * Returns the default table model object, which is
5592 * a {@code DefaultTableModel}. A subclass can override this
5593 * method to return a different table model object.
5594 *
5595 * @return the default table model object
5596 * @see javax.swing.table.DefaultTableModel
5597 */
5598 protected TableModel createDefaultDataModel() {
5599 return new DefaultTableModel();
5600 }
5601
5602 /**
5603 * Returns the default column model object, which is
5604 * a {@code DefaultTableColumnModel}. A subclass can override this
5605 * method to return a different column model object.
5606 *
5607 * @return the default column model object
5608 * @see javax.swing.table.DefaultTableColumnModel
5609 */
5610 protected TableColumnModel createDefaultColumnModel() {
5611 return new DefaultTableColumnModel();
5612 }
5613
5614 /**
5615 * Returns the default selection model object, which is
5616 * a {@code DefaultListSelectionModel}. A subclass can override this
5617 * method to return a different selection model object.
5618 *
5619 * @return the default selection model object
5620 * @see javax.swing.DefaultListSelectionModel
5621 */
5622 protected ListSelectionModel createDefaultSelectionModel() {
5623 return new DefaultListSelectionModel();
5624 }
5625
5626 /**
5627 * Returns the default table header object, which is
5628 * a {@code JTableHeader}. A subclass can override this
5629 * method to return a different table header object.
5630 *
5631 * @return the default table header object
5632 * @see javax.swing.table.JTableHeader
5633 */
5634 protected JTableHeader createDefaultTableHeader() {
5635 return new JTableHeader(columnModel);
5636 }
5637
5638 /**
5639 * Equivalent to {@code revalidate} followed by {@code repaint}.
5640 */
5641 protected void resizeAndRepaint() {
5642 revalidate();
5643 repaint();
5644 }
5645
5646 /**
5647 * Returns the active cell editor, which is {@code null} if the table
5648 * is not currently editing.
5649 *
5650 * @return the {@code TableCellEditor} that does the editing,
5651 * or {@code null} if the table is not currently editing.
5652 * @see #cellEditor
5653 * @see #getCellEditor(int, int)
5654 */
5655 public TableCellEditor getCellEditor() {
5656 return cellEditor;
5657 }
5658
5659 /**
5660 * Sets the active cell editor.
5661 *
5662 * @param anEditor the active cell editor
5663 * @see #cellEditor
5664 * @beaninfo
5665 * bound: true
5666 * description: The table's active cell editor.
5667 */
5668 public void setCellEditor(TableCellEditor anEditor) {
5669 TableCellEditor oldEditor = cellEditor;
5670 cellEditor = anEditor;
5671 firePropertyChange("tableCellEditor", oldEditor, anEditor);
5672 }
5673
5674 /**
5675 * Sets the {@code editingColumn} variable.
5676 * @param aColumn the column of the cell to be edited
5677 *
5678 * @see #editingColumn
5679 */
5680 public void setEditingColumn(int aColumn) {
5681 editingColumn = aColumn;
5682 }
5683
5684 /**
5685 * Sets the {@code editingRow} variable.
5686 * @param aRow the row of the cell to be edited
5687 *
5688 * @see #editingRow
5689 */
5690 public void setEditingRow(int aRow) {
5691 editingRow = aRow;
5692 }
5693
5694 /**
5695 * Returns an appropriate renderer for the cell specified by this row and
5696 * column. If the {@code TableColumn} for this column has a non-null
5697 * renderer, returns that. If not, finds the class of the data in
5698 * this column (using {@code getColumnClass})
5699 * and returns the default renderer for this type of data.
5700 * <p>
5701 * <b>Note:</b>
5702 * Throughout the table package, the internal implementations always
5703 * use this method to provide renderers so that this default behavior
5704 * can be safely overridden by a subclass.
5705 *
5706 * @param row the row of the cell to render, where 0 is the first row
5707 * @param column the column of the cell to render,
5708 * where 0 is the first column
5709 * @return the assigned renderer; if {@code null}
5710 * returns the default renderer
5711 * for this type of object
5712 * @see javax.swing.table.DefaultTableCellRenderer
5713 * @see javax.swing.table.TableColumn#setCellRenderer
5714 * @see #setDefaultRenderer
5715 */
5716 public TableCellRenderer getCellRenderer(int row, int column) {
5717 TableColumn tableColumn = getColumnModel().getColumn(column);
5718 TableCellRenderer renderer = tableColumn.getCellRenderer();
5719 if (renderer == null) {
5720 renderer = getDefaultRenderer(getColumnClass(column));
5721 }
5722 return renderer;
5723 }
5724
5725 /**
5726 * Prepares the renderer by querying the data model for the
5727 * value and selection state
5728 * of the cell at {@code row}, {@code column}.
5729 * Returns the component (may be a {@code Component}
5730 * or a {@code JComponent}) under the event location.
5731 * <p>
5732 * During a printing operation, this method will configure the
5733 * renderer without indicating selection or focus, to prevent
5734 * them from appearing in the printed output. To do other
5735 * customizations based on whether or not the table is being
5736 * printed, you can check the value of
5737 * {@link javax.swing.JComponent#isPaintingForPrint()}, either here
5738 * or within custom renderers.
5739 * <p>
5740 * <b>Note:</b>
5741 * Throughout the table package, the internal implementations always
5742 * use this method to prepare renderers so that this default behavior
5743 * can be safely overridden by a subclass.
5744 *
5745 * @param renderer the {@code TableCellRenderer} to prepare
5746 * @param row the row of the cell to render, where 0 is the first row
5747 * @param column the column of the cell to render,
5748 * where 0 is the first column
5749 * @return the {@code Component} under the event location
5750 */
5751 public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
5752 Object value = getValueAt(row, column);
5753
5754 boolean isSelected = false;
5755 boolean hasFocus = false;
5756
5757 // Only indicate the selection and focused cell if not printing
5758 if (!isPaintingForPrint()) {
5759 isSelected = isCellSelected(row, column);
5760
5761 boolean rowIsLead =
5762 (selectionModel.getLeadSelectionIndex() == row);
5763 boolean colIsLead =
5764 (columnModel.getSelectionModel().getLeadSelectionIndex() == column);
5765
5766 hasFocus = (rowIsLead && colIsLead) && isFocusOwner();
5767 }
5768
5769 return renderer.getTableCellRendererComponent(this, value,
5770 isSelected, hasFocus,
5771 row, column);
5772 }
5773
5774 /**
5775 * Returns an appropriate editor for the cell specified by
5776 * {@code row} and {@code column}. If the
5777 * {@code TableColumn} for this column has a non-null editor,
5778 * returns that. If not, finds the class of the data in this
5779 * column (using {@code getColumnClass})
5780 * and returns the default editor for this type of data.
5781 * <p>
5782 * <b>Note:</b>
5783 * Throughout the table package, the internal implementations always
5784 * use this method to provide editors so that this default behavior
5785 * can be safely overridden by a subclass.
5786 *
5787 * @param row the row of the cell to edit, where 0 is the first row
5788 * @param column the column of the cell to edit,
5789 * where 0 is the first column
5790 * @return the editor for this cell;
5791 * if {@code null} return the default editor for
5792 * this type of cell
5793 * @see DefaultCellEditor
5794 */
5795 public TableCellEditor getCellEditor(int row, int column) {
5796 TableColumn tableColumn = getColumnModel().getColumn(column);
5797 TableCellEditor editor = tableColumn.getCellEditor();
5798 if (editor == null) {
5799 editor = getDefaultEditor(getColumnClass(column));
5800 }
5801 return editor;
5802 }
5803
5804
5805 /**
5806 * Prepares the editor by querying the data model for the value and
5807 * selection state of the cell at {@code row}, {@code column}.
5808 * <p>
5809 * <b>Note:</b>
5810 * Throughout the table package, the internal implementations always
5811 * use this method to prepare editors so that this default behavior
5812 * can be safely overridden by a subclass.
5813 *
5814 * @param editor the {@code TableCellEditor} to set up
5815 * @param row the row of the cell to edit,
5816 * where 0 is the first row
5817 * @param column the column of the cell to edit,
5818 * where 0 is the first column
5819 * @return the {@code Component} being edited
5820 */
5821 @SuppressWarnings("deprecation")
5822 public Component prepareEditor(TableCellEditor editor, int row, int column) {
5823 Object value = getValueAt(row, column);
5824 boolean isSelected = isCellSelected(row, column);
5825 Component comp = editor.getTableCellEditorComponent(this, value, isSelected,
5826 row, column);
5827 if (comp instanceof JComponent) {
5828 JComponent jComp = (JComponent)comp;
5829 if (jComp.getNextFocusableComponent() == null) {
5830 jComp.setNextFocusableComponent(this);
5831 }
5832 }
5833 return comp;
5834 }
5835
5836 /**
5837 * Discards the editor object and frees the real estate it used for
5838 * cell rendering.
5839 */
5972 }
5973 }
5974
5975 /* Called from the JComponent's EnableSerializationFocusListener to
5976 * do any Swing-specific pre-serialization configuration.
5977 */
5978 void compWriteObjectNotify() {
5979 super.compWriteObjectNotify();
5980 // If ToolTipText != null, then the tooltip has already been
5981 // unregistered by JComponent.compWriteObjectNotify()
5982 if (getToolTipText() == null) {
5983 ToolTipManager.sharedInstance().unregisterComponent(this);
5984 }
5985 }
5986
5987 /**
5988 * Returns a string representation of this table. This method
5989 * is intended to be used only for debugging purposes, and the
5990 * content and format of the returned string may vary between
5991 * implementations. The returned string may be empty but may not
5992 * be {@code null}.
5993 *
5994 * @return a string representation of this table
5995 */
5996 protected String paramString() {
5997 String gridColorString = (gridColor != null ?
5998 gridColor.toString() : "");
5999 String showHorizontalLinesString = (showHorizontalLines ?
6000 "true" : "false");
6001 String showVerticalLinesString = (showVerticalLines ?
6002 "true" : "false");
6003 String autoResizeModeString;
6004 if (autoResizeMode == AUTO_RESIZE_OFF) {
6005 autoResizeModeString = "AUTO_RESIZE_OFF";
6006 } else if (autoResizeMode == AUTO_RESIZE_NEXT_COLUMN) {
6007 autoResizeModeString = "AUTO_RESIZE_NEXT_COLUMN";
6008 } else if (autoResizeMode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) {
6009 autoResizeModeString = "AUTO_RESIZE_SUBSEQUENT_COLUMNS";
6010 } else if (autoResizeMode == AUTO_RESIZE_LAST_COLUMN) {
6011 autoResizeModeString = "AUTO_RESIZE_LAST_COLUMN";
6012 } else if (autoResizeMode == AUTO_RESIZE_ALL_COLUMNS) {
6069 } else if ((c instanceof Window) ||
6070 (c instanceof Applet && c.getParent() == null)) {
6071 if (c == SwingUtilities.getRoot(JTable.this)) {
6072 if (!getCellEditor().stopCellEditing()) {
6073 getCellEditor().cancelCellEditing();
6074 }
6075 }
6076 break;
6077 }
6078 c = c.getParent();
6079 }
6080 }
6081 }
6082
6083 /////////////////
6084 // Printing Support
6085 /////////////////
6086
6087 /**
6088 * A convenience method that displays a printing dialog, and then prints
6089 * this {@code JTable} in mode {@code PrintMode.FIT_WIDTH},
6090 * with no header or footer text. A modal progress dialog, with an abort
6091 * option, will be shown for the duration of printing.
6092 * <p>
6093 * Note: In headless mode, no dialogs are shown and printing
6094 * occurs on the default printer.
6095 *
6096 * @return true, unless printing is cancelled by the user
6097 * @throws SecurityException if this thread is not allowed to
6098 * initiate a print job request
6099 * @throws PrinterException if an error in the print system causes the job
6100 * to be aborted
6101 * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6102 * boolean, PrintRequestAttributeSet, boolean, PrintService)
6103 * @see #getPrintable
6104 *
6105 * @since 1.5
6106 */
6107 public boolean print() throws PrinterException {
6108
6109 return print(PrintMode.FIT_WIDTH);
6110 }
6111
6112 /**
6113 * A convenience method that displays a printing dialog, and then prints
6114 * this {@code JTable} in the given printing mode,
6115 * with no header or footer text. A modal progress dialog, with an abort
6116 * option, will be shown for the duration of printing.
6117 * <p>
6118 * Note: In headless mode, no dialogs are shown and printing
6119 * occurs on the default printer.
6120 *
6121 * @param printMode the printing mode that the printable should use
6122 * @return true, unless printing is cancelled by the user
6123 * @throws SecurityException if this thread is not allowed to
6124 * initiate a print job request
6125 * @throws PrinterException if an error in the print system causes the job
6126 * to be aborted
6127 * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6128 * boolean, PrintRequestAttributeSet, boolean, PrintService)
6129 * @see #getPrintable
6130 *
6131 * @since 1.5
6132 */
6133 public boolean print(PrintMode printMode) throws PrinterException {
6134
6135 return print(printMode, null, null);
6136 }
6137
6138 /**
6139 * A convenience method that displays a printing dialog, and then prints
6140 * this {@code JTable} in the given printing mode,
6141 * with the specified header and footer text. A modal progress dialog,
6142 * with an abort option, will be shown for the duration of printing.
6143 * <p>
6144 * Note: In headless mode, no dialogs are shown and printing
6145 * occurs on the default printer.
6146 *
6147 * @param printMode the printing mode that the printable should use
6148 * @param headerFormat a {@code MessageFormat} specifying the text
6149 * to be used in printing a header,
6150 * or null for none
6151 * @param footerFormat a {@code MessageFormat} specifying the text
6152 * to be used in printing a footer,
6153 * or null for none
6154 * @return true, unless printing is cancelled by the user
6155 * @throws SecurityException if this thread is not allowed to
6156 * initiate a print job request
6157 * @throws PrinterException if an error in the print system causes the job
6158 * to be aborted
6159 * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6160 * boolean, PrintRequestAttributeSet, boolean, PrintService)
6161 * @see #getPrintable
6162 *
6163 * @since 1.5
6164 */
6165 public boolean print(PrintMode printMode,
6166 MessageFormat headerFormat,
6167 MessageFormat footerFormat) throws PrinterException {
6168
6169 boolean showDialogs = !GraphicsEnvironment.isHeadless();
6170 return print(printMode, headerFormat, footerFormat,
6171 showDialogs, null, showDialogs);
6172 }
6173
6174 /**
6175 * Prints this table, as specified by the fully featured
6176 * {@link #print(JTable.PrintMode, MessageFormat, MessageFormat,
6177 * boolean, PrintRequestAttributeSet, boolean, PrintService) print}
6178 * method, with the default printer specified as the print service.
6179 *
6180 * @param printMode the printing mode that the printable should use
6181 * @param headerFormat a {@code MessageFormat} specifying the text
6182 * to be used in printing a header,
6183 * or {@code null} for none
6184 * @param footerFormat a {@code MessageFormat} specifying the text
6185 * to be used in printing a footer,
6186 * or {@code null} for none
6187 * @param showPrintDialog whether or not to display a print dialog
6188 * @param attr a {@code PrintRequestAttributeSet}
6189 * specifying any printing attributes,
6190 * or {@code null} for none
6191 * @param interactive whether or not to print in an interactive mode
6192 * @return true, unless printing is cancelled by the user
6193 * @throws HeadlessException if the method is asked to show a printing
6194 * dialog or run interactively, and
6195 * {@code GraphicsEnvironment.isHeadless}
6196 * returns {@code true}
6197 * @throws SecurityException if this thread is not allowed to
6198 * initiate a print job request
6199 * @throws PrinterException if an error in the print system causes the job
6200 * to be aborted
6201 * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6202 * boolean, PrintRequestAttributeSet, boolean, PrintService)
6203 * @see #getPrintable
6204 *
6205 * @since 1.5
6206 */
6207 public boolean print(PrintMode printMode,
6208 MessageFormat headerFormat,
6209 MessageFormat footerFormat,
6210 boolean showPrintDialog,
6211 PrintRequestAttributeSet attr,
6212 boolean interactive) throws PrinterException,
6213 HeadlessException {
6214
6215 return print(printMode,
6216 headerFormat,
6217 footerFormat,
6218 showPrintDialog,
6219 attr,
6220 interactive,
6221 null);
6222 }
6223
6224 /**
6225 * Prints this {@code JTable}. Takes steps that the majority of
6226 * developers would take in order to print a {@code JTable}.
6227 * In short, it prepares the table, calls {@code getPrintable} to
6228 * fetch an appropriate {@code Printable}, and then sends it to the
6229 * printer.
6230 * <p>
6231 * A {@code boolean} parameter allows you to specify whether or not
6232 * a printing dialog is displayed to the user. When it is, the user may
6233 * use the dialog to change the destination printer or printing attributes,
6234 * or even to cancel the print. Another two parameters allow for a
6235 * {@code PrintService} and printing attributes to be specified.
6236 * These parameters can be used either to provide initial values for the
6237 * print dialog, or to specify values when the dialog is not shown.
6238 * <p>
6239 * A second {@code boolean} parameter allows you to specify whether
6240 * or not to perform printing in an interactive mode. If {@code true},
6241 * a modal progress dialog, with an abort option, is displayed for the
6242 * duration of printing . This dialog also prevents any user action which
6243 * may affect the table. However, it can not prevent the table from being
6244 * modified by code (for example, another thread that posts updates using
6245 * {@code SwingUtilities.invokeLater}). It is therefore the
6246 * responsibility of the developer to ensure that no other code modifies
6247 * the table in any way during printing (invalid modifications include
6248 * changes in: size, renderers, or underlying data). Printing behavior is
6249 * undefined when the table is changed during printing.
6250 * <p>
6251 * If {@code false} is specified for this parameter, no dialog will
6252 * be displayed and printing will begin immediately on the event-dispatch
6253 * thread. This blocks any other events, including repaints, from being
6254 * processed until printing is complete. Although this effectively prevents
6255 * the table from being changed, it doesn't provide a good user experience.
6256 * For this reason, specifying {@code false} is only recommended when
6257 * printing from an application with no visible GUI.
6258 * <p>
6259 * Note: Attempting to show the printing dialog or run interactively, while
6260 * in headless mode, will result in a {@code HeadlessException}.
6261 * <p>
6262 * Before fetching the printable, this method will gracefully terminate
6263 * editing, if necessary, to prevent an editor from showing in the printed
6264 * result. Additionally, {@code JTable} will prepare its renderers
6265 * during printing such that selection and focus are not indicated.
6266 * As far as customizing further how the table looks in the printout,
6267 * developers can provide custom renderers or paint code that conditionalize
6268 * on the value of {@link javax.swing.JComponent#isPaintingForPrint()}.
6269 * <p>
6270 * See {@link #getPrintable} for more description on how the table is
6271 * printed.
6272 *
6273 * @param printMode the printing mode that the printable should use
6274 * @param headerFormat a {@code MessageFormat} specifying the text
6275 * to be used in printing a header,
6276 * or {@code null} for none
6277 * @param footerFormat a {@code MessageFormat} specifying the text
6278 * to be used in printing a footer,
6279 * or {@code null} for none
6280 * @param showPrintDialog whether or not to display a print dialog
6281 * @param attr a {@code PrintRequestAttributeSet}
6282 * specifying any printing attributes,
6283 * or {@code null} for none
6284 * @param interactive whether or not to print in an interactive mode
6285 * @param service the destination {@code PrintService},
6286 * or {@code null} to use the default printer
6287 * @return true, unless printing is cancelled by the user
6288 * @throws HeadlessException if the method is asked to show a printing
6289 * dialog or run interactively, and
6290 * {@code GraphicsEnvironment.isHeadless}
6291 * returns {@code true}
6292 * @throws SecurityException if a security manager exists and its
6293 * {@link java.lang.SecurityManager#checkPrintJobAccess}
6294 * method disallows this thread from creating a print job request
6295 * @throws PrinterException if an error in the print system causes the job
6296 * to be aborted
6297 * @see #getPrintable
6298 * @see java.awt.GraphicsEnvironment#isHeadless
6299 *
6300 * @since 1.6
6301 */
6302 public boolean print(PrintMode printMode,
6303 MessageFormat headerFormat,
6304 MessageFormat footerFormat,
6305 boolean showPrintDialog,
6306 PrintRequestAttributeSet attr,
6307 boolean interactive,
6308 PrintService service) throws PrinterException,
6309 HeadlessException {
6310
6311 // complain early if an invalid parameter is specified for headless mode
6419 // a subclass of PrinterException meaning the job was aborted,
6420 // in this case, by the user
6421 if (pe instanceof PrinterAbortException) {
6422 return false;
6423 } else if (pe instanceof PrinterException) {
6424 throw (PrinterException)pe;
6425 } else if (pe instanceof RuntimeException) {
6426 throw (RuntimeException)pe;
6427 } else if (pe instanceof Error) {
6428 throw (Error)pe;
6429 }
6430
6431 // can not happen
6432 throw new AssertionError(pe);
6433 }
6434
6435 return true;
6436 }
6437
6438 /**
6439 * Return a {@code Printable} for use in printing this JTable.
6440 * <p>
6441 * This method is meant for those wishing to customize the default
6442 * {@code Printable} implementation used by {@code JTable}'s
6443 * {@code print} methods. Developers wanting simply to print the table
6444 * should use one of those methods directly.
6445 * <p>
6446 * The {@code Printable} can be requested in one of two printing modes.
6447 * In both modes, it spreads table rows naturally in sequence across
6448 * multiple pages, fitting as many rows as possible per page.
6449 * {@code PrintMode.NORMAL} specifies that the table be
6450 * printed at its current size. In this mode, there may be a need to spread
6451 * columns across pages in a similar manner to that of the rows. When the
6452 * need arises, columns are distributed in an order consistent with the
6453 * table's {@code ComponentOrientation}.
6454 * {@code PrintMode.FIT_WIDTH} specifies that the output be
6455 * scaled smaller, if necessary, to fit the table's entire width
6456 * (and thereby all columns) on each page. Width and height are scaled
6457 * equally, maintaining the aspect ratio of the output.
6458 * <p>
6459 * The {@code Printable} heads the portion of table on each page
6460 * with the appropriate section from the table's {@code JTableHeader},
6461 * if it has one.
6462 * <p>
6463 * Header and footer text can be added to the output by providing
6464 * {@code MessageFormat} arguments. The printing code requests
6465 * Strings from the formats, providing a single item which may be included
6466 * in the formatted string: an {@code Integer} representing the current
6467 * page number.
6468 * <p>
6469 * You are encouraged to read the documentation for
6470 * {@code MessageFormat} as some characters, such as single-quote,
6471 * are special and need to be escaped.
6472 * <p>
6473 * Here's an example of creating a {@code MessageFormat} that can be
6474 * used to print "Duke's Table: Page - " and the current page number:
6475 *
6476 * <pre>
6477 * // notice the escaping of the single quote
6478 * // notice how the page number is included with "{0}"
6479 * MessageFormat format = new MessageFormat("Duke''s Table: Page - {0}");
6480 * </pre>
6481 * <p>
6482 * The {@code Printable} constrains what it draws to the printable
6483 * area of each page that it prints. Under certain circumstances, it may
6484 * find it impossible to fit all of a page's content into that area. In
6485 * these cases the output may be clipped, but the implementation
6486 * makes an effort to do something reasonable. Here are a few situations
6487 * where this is known to occur, and how they may be handled by this
6488 * particular implementation:
6489 * <ul>
6490 * <li>In any mode, when the header or footer text is too wide to fit
6491 * completely in the printable area -- print as much of the text as
6492 * possible starting from the beginning, as determined by the table's
6493 * {@code ComponentOrientation}.
6494 * <li>In any mode, when a row is too tall to fit in the
6495 * printable area -- print the upper-most portion of the row
6496 * and paint no lower border on the table.
6497 * <li>In {@code PrintMode.NORMAL} when a column
6498 * is too wide to fit in the printable area -- print the center
6499 * portion of the column and leave the left and right borders
6500 * off the table.
6501 * </ul>
6502 * <p>
6503 * It is entirely valid for this {@code Printable} to be wrapped
6504 * inside another in order to create complex reports and documents. You may
6505 * even request that different pages be rendered into different sized
6506 * printable areas. The implementation must be prepared to handle this
6507 * (possibly by doing its layout calculations on the fly). However,
6508 * providing different heights to each page will likely not work well
6509 * with {@code PrintMode.NORMAL} when it has to spread columns
6510 * across pages.
6511 * <p>
6512 * As far as customizing how the table looks in the printed result,
6513 * {@code JTable} itself will take care of hiding the selection
6514 * and focus during printing. For additional customizations, your
6515 * renderers or painting code can customize the look based on the value
6516 * of {@link javax.swing.JComponent#isPaintingForPrint()}
6517 * <p>
6518 * Also, <i>before</i> calling this method you may wish to <i>first</i>
6519 * modify the state of the table, such as to cancel cell editing or
6520 * have the user size the table appropriately. However, you must not
6521 * modify the state of the table <i>after</i> this {@code Printable}
6522 * has been fetched (invalid modifications include changes in size or
6523 * underlying data). The behavior of the returned {@code Printable}
6524 * is undefined once the table has been changed.
6525 *
6526 * @param printMode the printing mode that the printable should use
6527 * @param headerFormat a {@code MessageFormat} specifying the text to
6528 * be used in printing a header, or null for none
6529 * @param footerFormat a {@code MessageFormat} specifying the text to
6530 * be used in printing a footer, or null for none
6531 * @return a {@code Printable} for printing this JTable
6532 * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6533 * boolean, PrintRequestAttributeSet, boolean)
6534 * @see Printable
6535 * @see PrinterJob
6536 *
6537 * @since 1.5
6538 */
6539 public Printable getPrintable(PrintMode printMode,
6540 MessageFormat headerFormat,
6541 MessageFormat footerFormat) {
6542
6543 return new TablePrintable(this, printMode, headerFormat, footerFormat);
6544 }
6545
6546
6547 /**
6548 * A {@code Printable} implementation that wraps another
6549 * {@code Printable}, making it safe for printing on another thread.
6550 */
6551 private class ThreadSafePrintable implements Printable {
6552
6553 /** The delegate {@code Printable}. */
6554 private Printable printDelegate;
6555
6556 /**
6557 * To communicate any return value when delegating.
6558 */
6559 private int retVal;
6560
6561 /**
6562 * To communicate any {@code Throwable} when delegating.
6563 */
6564 private Throwable retThrowable;
6565
6566 /**
6567 * Construct a {@code ThreadSafePrintable} around the given
6568 * delegate.
6569 *
6570 * @param printDelegate the {@code Printable} to delegate to
6571 */
6572 public ThreadSafePrintable(Printable printDelegate) {
6573 this.printDelegate = printDelegate;
6574 }
6575
6576 /**
6577 * Prints the specified page into the given {@link Graphics}
6578 * context, in the specified format.
6579 * <p>
6580 * Regardless of what thread this method is called on, all calls into
6581 * the delegate will be done on the event-dispatch thread.
6582 *
6583 * @param graphics the context into which the page is drawn
6584 * @param pageFormat the size and orientation of the page being drawn
6585 * @param pageIndex the zero based index of the page to be drawn
6586 * @return PAGE_EXISTS if the page is rendered successfully, or
6587 * NO_SUCH_PAGE if a non-existent page index is specified
6588 * @throws PrinterException if an error causes printing to be aborted
6589 */
6590 public int print(final Graphics graphics,
6652 * For tables, the AccessibleContext takes the form of an
6653 * AccessibleJTable.
6654 * A new AccessibleJTable instance is created if necessary.
6655 *
6656 * @return an AccessibleJTable that serves as the
6657 * AccessibleContext of this JTable
6658 */
6659 public AccessibleContext getAccessibleContext() {
6660 if (accessibleContext == null) {
6661 accessibleContext = new AccessibleJTable();
6662 }
6663 return accessibleContext;
6664 }
6665
6666 //
6667 // *** should also implement AccessibleSelection?
6668 // *** and what's up with keyboard navigation/manipulation?
6669 //
6670 /**
6671 * This class implements accessibility support for the
6672 * {@code JTable} class. It provides an implementation of the
6673 * Java Accessibility API appropriate to table user-interface elements.
6674 * <p>
6675 * <strong>Warning:</strong>
6676 * Serialized objects of this class will not be compatible with
6677 * future Swing releases. The current serialization support is
6678 * appropriate for short term storage or RMI between applications running
6679 * the same version of Swing. As of 1.4, support for long term storage
6680 * of all JavaBeans™
6681 * has been added to the {@code java.beans} package.
6682 * Please see {@link java.beans.XMLEncoder}.
6683 */
6684 @SuppressWarnings("serial") // Same-version serialization only
6685 protected class AccessibleJTable extends AccessibleJComponent
6686 implements AccessibleSelection, ListSelectionListener, TableModelListener,
6687 TableColumnModelListener, CellEditorListener, PropertyChangeListener,
6688 AccessibleExtendedTable {
6689
6690 int previousFocusedRow;
6691 int previousFocusedCol;
6692
6693 /**
6694 * AccessibleJTable constructor
6695 *
6696 * @since 1.5
6697 */
6698 protected AccessibleJTable() {
6699 super();
6700 JTable.this.addPropertyChangeListener(this);
6701 JTable.this.getSelectionModel().addListSelectionListener(this);
7102 * AccessibleSelection interface on behalf of itself.
7103 *
7104 * @return this object
7105 */
7106 public AccessibleSelection getAccessibleSelection() {
7107 return this;
7108 }
7109
7110 /**
7111 * Gets the role of this object.
7112 *
7113 * @return an instance of AccessibleRole describing the role of the
7114 * object
7115 * @see AccessibleRole
7116 */
7117 public AccessibleRole getAccessibleRole() {
7118 return AccessibleRole.TABLE;
7119 }
7120
7121 /**
7122 * Returns the {@code Accessible} child, if one exists,
7123 * contained at the local coordinate {@code Point}.
7124 *
7125 * @param p the point defining the top-left corner of the
7126 * {@code Accessible}, given in the coordinate space
7127 * of the object's parent
7128 * @return the {@code Accessible}, if it exists,
7129 * at the specified location; else {@code null}
7130 */
7131 public Accessible getAccessibleAt(Point p) {
7132 int column = columnAtPoint(p);
7133 int row = rowAtPoint(p);
7134
7135 if ((column != -1) && (row != -1)) {
7136 TableColumn aColumn = getColumnModel().getColumn(column);
7137 TableCellRenderer renderer = aColumn.getCellRenderer();
7138 if (renderer == null) {
7139 Class<?> columnClass = getColumnClass(column);
7140 renderer = getDefaultRenderer(columnClass);
7141 }
7142 Component component = renderer.getTableCellRendererComponent(
7143 JTable.this, null, false, false,
7144 row, column);
7145 return new AccessibleJTableCell(JTable.this, row, column,
7146 getAccessibleIndexAt(row, column));
7147 }
7148 return null;
7149 }
7150
7151 /**
7152 * Returns the number of accessible children in the object. If all
7153 * of the children of this object implement {@code Accessible},
7154 * then this method should return the number of children of this object.
7155 *
7156 * @return the number of accessible children in the object
7157 */
7158 public int getAccessibleChildrenCount() {
7159 return (JTable.this.getColumnCount() * JTable.this.getRowCount());
7160 }
7161
7162 /**
7163 * Returns the nth {@code Accessible} child of the object.
7164 *
7165 * @param i zero-based index of child
7166 * @return the nth Accessible child of the object
7167 */
7168 public Accessible getAccessibleChild(int i) {
7169 if (i < 0 || i >= getAccessibleChildrenCount()) {
7170 return null;
7171 } else {
7172 // children increase across, and then down, for tables
7173 // (arbitrary decision)
7174 int column = getAccessibleColumnAtIndex(i);
7175 int row = getAccessibleRowAtIndex(i);
7176
7177 TableColumn aColumn = getColumnModel().getColumn(column);
7178 TableCellRenderer renderer = aColumn.getCellRenderer();
7179 if (renderer == null) {
7180 Class<?> columnClass = getColumnClass(column);
7181 renderer = getDefaultRenderer(columnClass);
7182 }
7183 Component component = renderer.getTableCellRendererComponent(
7184 JTable.this, null, false, false,
7185 row, column);
7186 return new AccessibleJTableCell(JTable.this, row, column,
7187 getAccessibleIndexAt(row, column));
7188 }
7189 }
7190
7191 // AccessibleSelection support
7192
7193 /**
7194 * Returns the number of {@code Accessible} children
7195 * currently selected.
7196 * If no children are selected, the return value will be 0.
7197 *
7198 * @return the number of items currently selected
7199 */
7200 public int getAccessibleSelectionCount() {
7201 int rowsSel = JTable.this.getSelectedRowCount();
7202 int colsSel = JTable.this.getSelectedColumnCount();
7203
7204 if (JTable.this.cellSelectionEnabled) { // a contiguous block
7205 return rowsSel * colsSel;
7206
7207 } else {
7208 // a column swath and a row swath, with a shared block
7209 if (JTable.this.getRowSelectionAllowed() &&
7210 JTable.this.getColumnSelectionAllowed()) {
7211 return rowsSel * JTable.this.getColumnCount() +
7212 colsSel * JTable.this.getRowCount() -
7213 rowsSel * colsSel;
7214
7215 // just one or more rows in selection
7216 } else if (JTable.this.getRowSelectionAllowed()) {
7217 return rowsSel * JTable.this.getColumnCount();
7218
7219 // just one or more rows in selection
7220 } else if (JTable.this.getColumnSelectionAllowed()) {
7221 return colsSel * JTable.this.getRowCount();
7222
7223 } else {
7224 return 0; // JTable doesn't allow selections
7225 }
7226 }
7227 }
7228
7229 /**
7230 * Returns an {@code Accessible} representing the
7231 * specified selected child in the object. If there
7232 * isn't a selection, or there are fewer children selected
7233 * than the integer passed in, the return
7234 * value will be {@code null}.
7235 * <p>Note that the index represents the i-th selected child, which
7236 * is different from the i-th child.
7237 *
7238 * @param i the zero-based index of selected children
7239 * @return the i-th selected child
7240 * @see #getAccessibleSelectionCount
7241 */
7242 public Accessible getAccessibleSelection(int i) {
7243 if (i < 0 || i > getAccessibleSelectionCount()) {
7244 return null;
7245 }
7246
7247 int rowsSel = JTable.this.getSelectedRowCount();
7248 int colsSel = JTable.this.getSelectedColumnCount();
7249 int rowIndicies[] = getSelectedRows();
7250 int colIndicies[] = getSelectedColumns();
7251 int ttlCols = JTable.this.getColumnCount();
7252 int ttlRows = JTable.this.getRowCount();
7253 int r;
7254 int c;
7344 // one or more rows selected
7345 } else if (JTable.this.getRowSelectionAllowed()) {
7346 c = i % ttlCols;
7347 r = rowIndicies[i / ttlCols];
7348 return getAccessibleChild((r * ttlCols) + c);
7349
7350 // one or more columns selected
7351 } else if (JTable.this.getColumnSelectionAllowed()) {
7352 c = colIndicies[i % colsSel];
7353 r = i / colsSel;
7354 return getAccessibleChild((r * ttlCols) + c);
7355 }
7356 }
7357 return null;
7358 }
7359
7360 /**
7361 * Determines if the current child of this object is selected.
7362 *
7363 * @param i the zero-based index of the child in this
7364 * {@code Accessible} object
7365 * @return true if the current child of this object is selected
7366 * @see AccessibleContext#getAccessibleChild
7367 */
7368 public boolean isAccessibleChildSelected(int i) {
7369 int column = getAccessibleColumnAtIndex(i);
7370 int row = getAccessibleRowAtIndex(i);
7371 return JTable.this.isCellSelected(row, column);
7372 }
7373
7374 /**
7375 * Adds the specified {@code Accessible} child of the
7376 * object to the object's selection. If the object supports
7377 * multiple selections, the specified child is added to
7378 * any existing selection, otherwise
7379 * it replaces any existing selection in the object. If the
7380 * specified child is already selected, this method has no effect.
7381 * <p>
7382 * This method only works on {@code JTable}s which have
7383 * individual cell selection enabled.
7384 *
7385 * @param i the zero-based index of the child
7386 * @see AccessibleContext#getAccessibleChild
7387 */
7388 public void addAccessibleSelection(int i) {
7389 // TIGER - 4495286
7390 int column = getAccessibleColumnAtIndex(i);
7391 int row = getAccessibleRowAtIndex(i);
7392 JTable.this.changeSelection(row, column, true, false);
7393 }
7394
7395 /**
7396 * Removes the specified child of the object from the object's
7397 * selection. If the specified item isn't currently selected, this
7398 * method has no effect.
7399 * <p>
7400 * This method only works on {@code JTables} which have
7401 * individual cell selection enabled.
7402 *
7403 * @param i the zero-based index of the child
7404 * @see AccessibleContext#getAccessibleChild
7405 */
7406 public void removeAccessibleSelection(int i) {
7407 if (JTable.this.cellSelectionEnabled) {
7408 int column = getAccessibleColumnAtIndex(i);
7409 int row = getAccessibleRowAtIndex(i);
7410 JTable.this.removeRowSelectionInterval(row, row);
7411 JTable.this.removeColumnSelectionInterval(column, column);
7412 }
7413 }
7414
7415 /**
7416 * Clears the selection in the object, so that no children in the
7417 * object are selected.
7418 */
7419 public void clearAccessibleSelection() {
7420 JTable.this.clearSelection();
7421 }
7422
7423 /**
7424 * Causes every child of the object to be selected, but only
7425 * if the {@code JTable} supports multiple selections,
7426 * and if individual cell selection is enabled.
7427 */
7428 public void selectAllAccessibleSelection() {
7429 if (JTable.this.cellSelectionEnabled) {
7430 JTable.this.selectAll();
7431 }
7432 }
7433
7434 // begin AccessibleExtendedTable implementation -------------
7435
7436 /**
7437 * Returns the row number of an index in the table.
7438 *
7439 * @param index the zero-based index in the table
7440 * @return the zero-based row of the table if one exists;
7441 * otherwise -1.
7442 * @since 1.4
7443 */
7444 public int getAccessibleRow(int index) {
7445 return getAccessibleRowAtIndex(index);
7463 * @param r zero-based row of the table
7464 * @param c zero-based column of the table
7465 * @return the zero-based index in the table if one exists;
7466 * otherwise -1.
7467 * @since 1.4
7468 */
7469 public int getAccessibleIndex(int r, int c) {
7470 return getAccessibleIndexAt(r, c);
7471 }
7472
7473 // end of AccessibleExtendedTable implementation ------------
7474
7475 // start of AccessibleTable implementation ------------------
7476
7477 private Accessible caption;
7478 private Accessible summary;
7479 private Accessible [] rowDescription;
7480 private Accessible [] columnDescription;
7481
7482 /**
7483 * Gets the {@code AccessibleTable} associated with this
7484 * object. In the implementation of the Java Accessibility
7485 * API for this class, return this object, which is responsible
7486 * for implementing the {@code AccessibleTables} interface
7487 * on behalf of itself.
7488 *
7489 * @return this object
7490 * @since 1.3
7491 */
7492 public AccessibleTable getAccessibleTable() {
7493 return this;
7494 }
7495
7496 /**
7497 * Returns the caption for the table.
7498 *
7499 * @return the caption for the table
7500 * @since 1.3
7501 */
7502 public Accessible getAccessibleCaption() {
7503 return this.caption;
7504 }
7505
7506 /**
7541
7542 /*
7543 * Returns the total number of rows in this table.
7544 *
7545 * @return the total number of rows in this table
7546 */
7547 public int getAccessibleRowCount() {
7548 return JTable.this.getRowCount();
7549 }
7550
7551 /*
7552 * Returns the total number of columns in the table.
7553 *
7554 * @return the total number of columns in the table
7555 */
7556 public int getAccessibleColumnCount() {
7557 return JTable.this.getColumnCount();
7558 }
7559
7560 /*
7561 * Returns the {@code Accessible} at a specified row
7562 * and column in the table.
7563 *
7564 * @param r zero-based row of the table
7565 * @param c zero-based column of the table
7566 * @return the {@code Accessible} at the specified row and column
7567 * in the table
7568 */
7569 public Accessible getAccessibleAt(int r, int c) {
7570 return getAccessibleChild((r * getAccessibleColumnCount()) + c);
7571 }
7572
7573 /**
7574 * Returns the number of rows occupied by the {@code Accessible}
7575 * at a specified row and column in the table.
7576 *
7577 * @return the number of rows occupied by the {@code Accessible}
7578 * at a specified row and column in the table
7579 * @since 1.3
7580 */
7581 public int getAccessibleRowExtentAt(int r, int c) {
7582 return 1;
7583 }
7584
7585 /**
7586 * Returns the number of columns occupied by the
7587 * {@code Accessible} at a given (row, column).
7588 *
7589 * @return the number of columns occupied by the {@code Accessible}
7590 * at a specified row and column in the table
7591 * @since 1.3
7592 */
7593 public int getAccessibleColumnExtentAt(int r, int c) {
7594 return 1;
7595 }
7596
7597 /**
7598 * Returns the row headers as an {@code AccessibleTable}.
7599 *
7600 * @return an {@code AccessibleTable} representing the row
7601 * headers
7602 * @since 1.3
7603 */
7604 public AccessibleTable getAccessibleRowHeader() {
7605 // row headers are not supported
7606 return null;
7607 }
7608
7609 /**
7610 * Sets the row headers as an {@code AccessibleTable}.
7611 *
7612 * @param a an {@code AccessibleTable} representing the row
7613 * headers
7614 * @since 1.3
7615 */
7616 public void setAccessibleRowHeader(AccessibleTable a) {
7617 // row headers are not supported
7618 }
7619
7620 /**
7621 * Returns the column headers as an {@code AccessibleTable}.
7622 *
7623 * @return an {@code AccessibleTable} representing the column
7624 * headers, or {@code null} if the table header is
7625 * {@code null}
7626 * @since 1.3
7627 */
7628 public AccessibleTable getAccessibleColumnHeader() {
7629 JTableHeader header = JTable.this.getTableHeader();
7630 return header == null ? null : new AccessibleTableHeader(header);
7631 }
7632
7633 /*
7634 * Private class representing a table column header
7635 */
7636 private class AccessibleTableHeader implements AccessibleTable {
7637 private JTableHeader header;
7638 private TableColumnModel headerModel;
7639
7640 AccessibleTableHeader(JTableHeader header) {
7641 this.header = header;
7642 this.headerModel = header.getColumnModel();
7643 }
7644
7645 /**
7840 * Returns the selected rows in a table.
7841 *
7842 * @return an array of selected rows where each element is a
7843 * zero-based row of the table
7844 * @since 1.3
7845 */
7846 public int [] getSelectedAccessibleRows() { return new int[0]; }
7847
7848 /**
7849 * Returns the selected columns in a table.
7850 *
7851 * @return an array of selected columns where each element is a
7852 * zero-based column of the table
7853 * @since 1.3
7854 */
7855 public int [] getSelectedAccessibleColumns() { return new int[0]; }
7856 }
7857
7858
7859 /**
7860 * Sets the column headers as an {@code AccessibleTable}.
7861 *
7862 * @param a an {@code AccessibleTable} representing the
7863 * column headers
7864 * @since 1.3
7865 */
7866 public void setAccessibleColumnHeader(AccessibleTable a) {
7867 // XXX not implemented
7868 }
7869
7870 /**
7871 * Returns the description of the specified row in the table.
7872 *
7873 * @param r zero-based row of the table
7874 * @return the description of the row
7875 * @since 1.3
7876 */
7877 public Accessible getAccessibleRowDescription(int r) {
7878 if (r < 0 || r >= getAccessibleRowCount()) {
7879 throw new IllegalArgumentException(Integer.toString(r));
7880 }
7881 if (rowDescription == null) {
7882 return null;
8043 */
8044 public int getAccessibleIndexAt(int r, int c) {
8045 return ((r * getAccessibleColumnCount()) + c);
8046 }
8047
8048 // end of AccessibleTable implementation --------------------
8049
8050 /**
8051 * The class provides an implementation of the Java Accessibility
8052 * API appropriate to table cells.
8053 */
8054 protected class AccessibleJTableCell extends AccessibleContext
8055 implements Accessible, AccessibleComponent {
8056
8057 private JTable parent;
8058 private int row;
8059 private int column;
8060 private int index;
8061
8062 /**
8063 * Constructs an {@code AccessibleJTableHeaderEntry}.
8064 *
8065 * @param t a {@code JTable}
8066 * @param r an {@code int} specifying a row
8067 * @param c an {@code int} specifying a column
8068 * @param i an {@code int} specifying the index to this cell
8069 * @since 1.4
8070 */
8071 public AccessibleJTableCell(JTable t, int r, int c, int i) {
8072 parent = t;
8073 row = r;
8074 column = c;
8075 index = i;
8076 this.setAccessibleParent(parent);
8077 }
8078
8079 /**
8080 * Gets the {@code AccessibleContext} associated with this
8081 * component. In the implementation of the Java Accessibility
8082 * API for this class, return this object, which is its own
8083 * {@code AccessibleContext}.
8084 *
8085 * @return this object
8086 */
8087 public AccessibleContext getAccessibleContext() {
8088 return this;
8089 }
8090
8091 /**
8092 * Gets the AccessibleContext for the table cell renderer.
8093 *
8094 * @return the {@code AccessibleContext} for the table
8095 * cell renderer if one exists;
8096 * otherwise, returns {@code null}.
8097 * @since 1.6
8098 */
8099 protected AccessibleContext getCurrentAccessibleContext() {
8100 TableColumn aColumn = getColumnModel().getColumn(column);
8101 TableCellRenderer renderer = aColumn.getCellRenderer();
8102 if (renderer == null) {
8103 Class<?> columnClass = getColumnClass(column);
8104 renderer = getDefaultRenderer(columnClass);
8105 }
8106 Component component = renderer.getTableCellRendererComponent(
8107 JTable.this, getValueAt(row, column),
8108 false, false, row, column);
8109 if (component instanceof Accessible) {
8110 return component.getAccessibleContext();
8111 } else {
8112 return null;
8113 }
8114 }
8115
8116 /**
8117 * Gets the table cell renderer component.
8118 *
8119 * @return the table cell renderer component if one exists;
8120 * otherwise, returns {@code null}.
8121 * @since 1.6
8122 */
8123 protected Component getCurrentComponent() {
8124 TableColumn aColumn = getColumnModel().getColumn(column);
8125 TableCellRenderer renderer = aColumn.getCellRenderer();
8126 if (renderer == null) {
8127 Class<?> columnClass = getColumnClass(column);
8128 renderer = getDefaultRenderer(columnClass);
8129 }
8130 return renderer.getTableCellRendererComponent(
8131 JTable.this, null, false, false,
8132 row, column);
8133 }
8134
8135 // AccessibleContext methods
8136
8137 /**
8138 * Gets the accessible name of this object.
8139 *
8140 * @return the localized name of the object; {@code null}
8141 * if this object does not have a name
8142 */
8143 public String getAccessibleName() {
8144 AccessibleContext ac = getCurrentAccessibleContext();
8145 if (ac != null) {
8146 String name = ac.getAccessibleName();
8147 if ((name != null) && (name != "")) {
8148 // return the cell renderer's AccessibleName
8149 return name;
8150 }
8151 }
8152 if ((accessibleName != null) && (accessibleName != "")) {
8153 return accessibleName;
8154 } else {
8155 // fall back to the client property
8156 return (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
8157 }
8158 }
8159
8160 /**
8161 * Sets the localized accessible name of this object.
8162 *
8163 * @param s the new localized name of the object
8164 */
8165 public void setAccessibleName(String s) {
8166 AccessibleContext ac = getCurrentAccessibleContext();
8167 if (ac != null) {
8168 ac.setAccessibleName(s);
8169 } else {
8170 super.setAccessibleName(s);
8171 }
8172 }
8173
8174 //
8175 // *** should check toolTip text for desc. (needs MouseEvent)
8176 //
8177 /**
8178 * Gets the accessible description of this object.
8179 *
8180 * @return the localized description of the object;
8181 * {@code null} if this object does not have
8182 * a description
8183 */
8184 public String getAccessibleDescription() {
8185 AccessibleContext ac = getCurrentAccessibleContext();
8186 if (ac != null) {
8187 return ac.getAccessibleDescription();
8188 } else {
8189 return super.getAccessibleDescription();
8190 }
8191 }
8192
8193 /**
8194 * Sets the accessible description of this object.
8195 *
8196 * @param s the new localized description of the object
8197 */
8198 public void setAccessibleDescription(String s) {
8199 AccessibleContext ac = getCurrentAccessibleContext();
8200 if (ac != null) {
8201 ac.setAccessibleDescription(s);
8202 } else {
8203 super.setAccessibleDescription(s);
8204 }
8205 }
8206
8207 /**
8208 * Gets the role of this object.
8209 *
8210 * @return an instance of {@code AccessibleRole}
8211 * describing the role of the object
8212 * @see AccessibleRole
8213 */
8214 public AccessibleRole getAccessibleRole() {
8215 AccessibleContext ac = getCurrentAccessibleContext();
8216 if (ac != null) {
8217 return ac.getAccessibleRole();
8218 } else {
8219 return AccessibleRole.UNKNOWN;
8220 }
8221 }
8222
8223 /**
8224 * Gets the state set of this object.
8225 *
8226 * @return an instance of {@code AccessibleStateSet}
8227 * containing the current state set of the object
8228 * @see AccessibleState
8229 */
8230 public AccessibleStateSet getAccessibleStateSet() {
8231 AccessibleContext ac = getCurrentAccessibleContext();
8232 AccessibleStateSet as = null;
8233
8234 if (ac != null) {
8235 as = ac.getAccessibleStateSet();
8236 }
8237 if (as == null) {
8238 as = new AccessibleStateSet();
8239 }
8240 Rectangle rjt = JTable.this.getVisibleRect();
8241 Rectangle rcell = JTable.this.getCellRect(row, column, false);
8242 if (rjt.intersects(rcell)) {
8243 as.add(AccessibleState.SHOWING);
8244 } else {
8245 if (as.contains(AccessibleState.SHOWING)) {
8246 as.remove(AccessibleState.SHOWING);
8247 }
8248 }
8249 if (parent.isCellSelected(row, column)) {
8250 as.add(AccessibleState.SELECTED);
8251 } else if (as.contains(AccessibleState.SELECTED)) {
8252 as.remove(AccessibleState.SELECTED);
8253 }
8254 if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
8255 as.add(AccessibleState.ACTIVE);
8256 }
8257 as.add(AccessibleState.TRANSIENT);
8258 return as;
8259 }
8260
8261 /**
8262 * Gets the {@code Accessible} parent of this object.
8263 *
8264 * @return the Accessible parent of this object;
8265 * {@code null} if this object does not
8266 * have an {@code Accessible} parent
8267 */
8268 public Accessible getAccessibleParent() {
8269 return parent;
8270 }
8271
8272 /**
8273 * Gets the index of this object in its accessible parent.
8274 *
8275 * @return the index of this object in its parent; -1 if this
8276 * object does not have an accessible parent
8277 * @see #getAccessibleParent
8278 */
8279 public int getAccessibleIndexInParent() {
8280 return index;
8281 }
8282
8283 /**
8284 * Returns the number of accessible children in the object.
8285 *
8286 * @return the number of accessible children in the object
8287 */
8288 public int getAccessibleChildrenCount() {
8289 AccessibleContext ac = getCurrentAccessibleContext();
8290 if (ac != null) {
8291 return ac.getAccessibleChildrenCount();
8292 } else {
8293 return 0;
8294 }
8295 }
8296
8297 /**
8298 * Returns the specified {@code Accessible} child of the
8299 * object.
8300 *
8301 * @param i zero-based index of child
8302 * @return the {@code Accessible} child of the object
8303 */
8304 public Accessible getAccessibleChild(int i) {
8305 AccessibleContext ac = getCurrentAccessibleContext();
8306 if (ac != null) {
8307 Accessible accessibleChild = ac.getAccessibleChild(i);
8308 ac.setAccessibleParent(this);
8309 return accessibleChild;
8310 } else {
8311 return null;
8312 }
8313 }
8314
8315 /**
8316 * Gets the locale of the component. If the component
8317 * does not have a locale, then the locale of its parent
8318 * is returned.
8319 *
8320 * @return this component's locale; if this component does
8321 * not have a locale, the locale of its parent is returned
8322 * @exception IllegalComponentStateException if the
8323 * {@code Component} does not have its own locale
8324 * and has not yet been added to a containment hierarchy
8325 * such that the locale can be determined from the
8326 * containing parent
8327 * @see #setLocale
8328 */
8329 public Locale getLocale() {
8330 AccessibleContext ac = getCurrentAccessibleContext();
8331 if (ac != null) {
8332 return ac.getLocale();
8333 } else {
8334 return null;
8335 }
8336 }
8337
8338 /**
8339 * Adds a {@code PropertyChangeListener} to the listener list.
8340 * The listener is registered for all properties.
8341 *
8342 * @param l the {@code PropertyChangeListener}
8343 * to be added
8344 */
8345 public void addPropertyChangeListener(PropertyChangeListener l) {
8346 AccessibleContext ac = getCurrentAccessibleContext();
8347 if (ac != null) {
8348 ac.addPropertyChangeListener(l);
8349 } else {
8350 super.addPropertyChangeListener(l);
8351 }
8352 }
8353
8354 /**
8355 * Removes a {@code PropertyChangeListener} from the
8356 * listener list. This removes a {@code PropertyChangeListener}
8357 * that was registered for all properties.
8358 *
8359 * @param l the {@code PropertyChangeListener}
8360 * to be removed
8361 */
8362 public void removePropertyChangeListener(PropertyChangeListener l) {
8363 AccessibleContext ac = getCurrentAccessibleContext();
8364 if (ac != null) {
8365 ac.removePropertyChangeListener(l);
8366 } else {
8367 super.removePropertyChangeListener(l);
8368 }
8369 }
8370
8371 /**
8372 * Gets the {@code AccessibleAction} associated with this
8373 * object if one exists. Otherwise returns {@code null}.
8374 *
8375 * @return the {@code AccessibleAction}, or {@code null}
8376 */
8377 public AccessibleAction getAccessibleAction() {
8378 return getCurrentAccessibleContext().getAccessibleAction();
8379 }
8380
8381 /**
8382 * Gets the {@code AccessibleComponent} associated with
8383 * this object if one exists. Otherwise returns {@code null}.
8384 *
8385 * @return the {@code AccessibleComponent}, or
8386 * {@code null}
8387 */
8388 public AccessibleComponent getAccessibleComponent() {
8389 return this; // to override getBounds()
8390 }
8391
8392 /**
8393 * Gets the {@code AccessibleSelection} associated with
8394 * this object if one exists. Otherwise returns {@code null}.
8395 *
8396 * @return the {@code AccessibleSelection}, or
8397 * {@code null}
8398 */
8399 public AccessibleSelection getAccessibleSelection() {
8400 return getCurrentAccessibleContext().getAccessibleSelection();
8401 }
8402
8403 /**
8404 * Gets the {@code AccessibleText} associated with this
8405 * object if one exists. Otherwise returns {@code null}.
8406 *
8407 * @return the {@code AccessibleText}, or {@code null}
8408 */
8409 public AccessibleText getAccessibleText() {
8410 return getCurrentAccessibleContext().getAccessibleText();
8411 }
8412
8413 /**
8414 * Gets the {@code AccessibleValue} associated with
8415 * this object if one exists. Otherwise returns {@code null}.
8416 *
8417 * @return the {@code AccessibleValue}, or {@code null}
8418 */
8419 public AccessibleValue getAccessibleValue() {
8420 return getCurrentAccessibleContext().getAccessibleValue();
8421 }
8422
8423
8424 // AccessibleComponent methods
8425
8426 /**
8427 * Gets the background color of this object.
8428 *
8429 * @return the background color, if supported, of the object;
8430 * otherwise, {@code null}
8431 */
8432 public Color getBackground() {
8433 AccessibleContext ac = getCurrentAccessibleContext();
8434 if (ac instanceof AccessibleComponent) {
8435 return ((AccessibleComponent) ac).getBackground();
8436 } else {
8437 Component c = getCurrentComponent();
8438 if (c != null) {
8439 return c.getBackground();
8440 } else {
8441 return null;
8442 }
8443 }
8444 }
8445
8446 /**
8447 * Sets the background color of this object.
8448 *
8449 * @param c the new {@code Color} for the background
8450 */
8451 public void setBackground(Color c) {
8452 AccessibleContext ac = getCurrentAccessibleContext();
8453 if (ac instanceof AccessibleComponent) {
8454 ((AccessibleComponent) ac).setBackground(c);
8455 } else {
8456 Component cp = getCurrentComponent();
8457 if (cp != null) {
8458 cp.setBackground(c);
8459 }
8460 }
8461 }
8462
8463 /**
8464 * Gets the foreground color of this object.
8465 *
8466 * @return the foreground color, if supported, of the object;
8467 * otherwise, {@code null}
8468 */
8469 public Color getForeground() {
8470 AccessibleContext ac = getCurrentAccessibleContext();
8471 if (ac instanceof AccessibleComponent) {
8472 return ((AccessibleComponent) ac).getForeground();
8473 } else {
8474 Component c = getCurrentComponent();
8475 if (c != null) {
8476 return c.getForeground();
8477 } else {
8478 return null;
8479 }
8480 }
8481 }
8482
8483 /**
8484 * Sets the foreground color of this object.
8485 *
8486 * @param c the new {@code Color} for the foreground
8487 */
8488 public void setForeground(Color c) {
8489 AccessibleContext ac = getCurrentAccessibleContext();
8490 if (ac instanceof AccessibleComponent) {
8491 ((AccessibleComponent) ac).setForeground(c);
8492 } else {
8493 Component cp = getCurrentComponent();
8494 if (cp != null) {
8495 cp.setForeground(c);
8496 }
8497 }
8498 }
8499
8500 /**
8501 * Gets the {@code Cursor} of this object.
8502 *
8503 * @return the {@code Cursor}, if supported,
8504 * of the object; otherwise, {@code null}
8505 */
8506 public Cursor getCursor() {
8507 AccessibleContext ac = getCurrentAccessibleContext();
8508 if (ac instanceof AccessibleComponent) {
8509 return ((AccessibleComponent) ac).getCursor();
8510 } else {
8511 Component c = getCurrentComponent();
8512 if (c != null) {
8513 return c.getCursor();
8514 } else {
8515 Accessible ap = getAccessibleParent();
8516 if (ap instanceof AccessibleComponent) {
8517 return ((AccessibleComponent) ap).getCursor();
8518 } else {
8519 return null;
8520 }
8521 }
8522 }
8523 }
8524
8525 /**
8526 * Sets the {@code Cursor} of this object.
8527 *
8528 * @param c the new {@code Cursor} for the object
8529 */
8530 public void setCursor(Cursor c) {
8531 AccessibleContext ac = getCurrentAccessibleContext();
8532 if (ac instanceof AccessibleComponent) {
8533 ((AccessibleComponent) ac).setCursor(c);
8534 } else {
8535 Component cp = getCurrentComponent();
8536 if (cp != null) {
8537 cp.setCursor(c);
8538 }
8539 }
8540 }
8541
8542 /**
8543 * Gets the {@code Font} of this object.
8544 *
8545 * @return the {@code Font},if supported,
8546 * for the object; otherwise, {@code null}
8547 */
8548 public Font getFont() {
8549 AccessibleContext ac = getCurrentAccessibleContext();
8550 if (ac instanceof AccessibleComponent) {
8551 return ((AccessibleComponent) ac).getFont();
8552 } else {
8553 Component c = getCurrentComponent();
8554 if (c != null) {
8555 return c.getFont();
8556 } else {
8557 return null;
8558 }
8559 }
8560 }
8561
8562 /**
8563 * Sets the {@code Font} of this object.
8564 *
8565 * @param f the new {@code Font} for the object
8566 */
8567 public void setFont(Font f) {
8568 AccessibleContext ac = getCurrentAccessibleContext();
8569 if (ac instanceof AccessibleComponent) {
8570 ((AccessibleComponent) ac).setFont(f);
8571 } else {
8572 Component c = getCurrentComponent();
8573 if (c != null) {
8574 c.setFont(f);
8575 }
8576 }
8577 }
8578
8579 /**
8580 * Gets the {@code FontMetrics} of this object.
8581 *
8582 * @param f the {@code Font}
8583 * @return the {@code FontMetrics} object, if supported;
8584 * otherwise {@code null}
8585 * @see #getFont
8586 */
8587 public FontMetrics getFontMetrics(Font f) {
8588 AccessibleContext ac = getCurrentAccessibleContext();
8589 if (ac instanceof AccessibleComponent) {
8590 return ((AccessibleComponent) ac).getFontMetrics(f);
8591 } else {
8592 Component c = getCurrentComponent();
8593 if (c != null) {
8594 return c.getFontMetrics(f);
8595 } else {
8596 return null;
8597 }
8598 }
8599 }
8600
8601 /**
8602 * Determines if the object is enabled.
8603 *
8604 * @return true if object is enabled; otherwise, false
8622 *
8623 * @param b if true, enables this object; otherwise, disables it
8624 */
8625 public void setEnabled(boolean b) {
8626 AccessibleContext ac = getCurrentAccessibleContext();
8627 if (ac instanceof AccessibleComponent) {
8628 ((AccessibleComponent) ac).setEnabled(b);
8629 } else {
8630 Component c = getCurrentComponent();
8631 if (c != null) {
8632 c.setEnabled(b);
8633 }
8634 }
8635 }
8636
8637 /**
8638 * Determines if this object is visible. Note: this means that the
8639 * object intends to be visible; however, it may not in fact be
8640 * showing on the screen because one of the objects that this object
8641 * is contained by is not visible. To determine if an object is
8642 * showing on the screen, use {@code isShowing}.
8643 *
8644 * @return true if object is visible; otherwise, false
8645 */
8646 public boolean isVisible() {
8647 AccessibleContext ac = getCurrentAccessibleContext();
8648 if (ac instanceof AccessibleComponent) {
8649 return ((AccessibleComponent) ac).isVisible();
8650 } else {
8651 Component c = getCurrentComponent();
8652 if (c != null) {
8653 return c.isVisible();
8654 } else {
8655 return false;
8656 }
8657 }
8658 }
8659
8660 /**
8661 * Sets the visible state of the object.
8662 *
8693 // returns false when the cell on the screen
8694 // if no parent
8695 return isVisible();
8696 }
8697 } else {
8698 Component c = getCurrentComponent();
8699 if (c != null) {
8700 return c.isShowing();
8701 } else {
8702 return false;
8703 }
8704 }
8705 }
8706
8707 /**
8708 * Checks whether the specified point is within this
8709 * object's bounds, where the point's x and y coordinates
8710 * are defined to be relative to the coordinate system of
8711 * the object.
8712 *
8713 * @param p the {@code Point} relative to the
8714 * coordinate system of the object
8715 * @return true if object contains {@code Point};
8716 * otherwise false
8717 */
8718 public boolean contains(Point p) {
8719 AccessibleContext ac = getCurrentAccessibleContext();
8720 if (ac instanceof AccessibleComponent) {
8721 Rectangle r = ((AccessibleComponent) ac).getBounds();
8722 return r.contains(p);
8723 } else {
8724 Component c = getCurrentComponent();
8725 if (c != null) {
8726 Rectangle r = c.getBounds();
8727 return r.contains(p);
8728 } else {
8729 return getBounds().contains(p);
8730 }
8731 }
8732 }
8733
8734 /**
8735 * Returns the location of the object on the screen.
8736 *
8737 * @return location of object on screen -- can be
8738 * {@code null} if this object is not on the screen
8739 */
8740 public Point getLocationOnScreen() {
8741 if (parent != null && parent.isShowing()) {
8742 Point parentLocation = parent.getLocationOnScreen();
8743 Point componentLocation = getLocation();
8744 componentLocation.translate(parentLocation.x, parentLocation.y);
8745 return componentLocation;
8746 } else {
8747 return null;
8748 }
8749 }
8750
8751 /**
8752 * Gets the location of the object relative to the parent
8753 * in the form of a point specifying the object's
8754 * top-left corner in the screen's coordinate space.
8755 *
8756 * @return an instance of {@code Point} representing
8757 * the top-left corner of the object's bounds in the
8758 * coordinate space of the screen; {@code null} if
8759 * this object or its parent are not on the screen
8760 */
8761 public Point getLocation() {
8762 if (parent != null) {
8763 Rectangle r = parent.getCellRect(row, column, false);
8764 if (r != null) {
8765 return r.getLocation();
8766 }
8767 }
8768 return null;
8769 }
8770
8771 /**
8772 * Sets the location of the object relative to the parent.
8773 */
8774 public void setLocation(Point p) {
8775 // if ((parent != null) && (parent.contains(p))) {
8776 // ensureIndexIsVisible(indexInParent);
8777 // }
8778 }
8878 }
8879 }
8880 }
8881
8882 } // inner class AccessibleJTableCell
8883
8884 // Begin AccessibleJTableHeader ========== // TIGER - 4715503
8885
8886 /**
8887 * This class implements accessibility for JTable header cells.
8888 */
8889 private class AccessibleJTableHeaderCell extends AccessibleContext
8890 implements Accessible, AccessibleComponent {
8891
8892 private int row;
8893 private int column;
8894 private JTableHeader parent;
8895 private Component rendererComponent;
8896
8897 /**
8898 * Constructs an {@code AccessibleJTableHeaderEntry} instance.
8899 *
8900 * @param row header cell row index
8901 * @param column header cell column index
8902 * @param parent header cell parent
8903 * @param rendererComponent component that renders the header cell
8904 */
8905 public AccessibleJTableHeaderCell(int row, int column,
8906 JTableHeader parent,
8907 Component rendererComponent) {
8908 this.row = row;
8909 this.column = column;
8910 this.parent = parent;
8911 this.rendererComponent = rendererComponent;
8912 this.setAccessibleParent(parent);
8913 }
8914
8915 /**
8916 * Gets the {@code AccessibleContext} associated with this
8917 * component. In the implementation of the Java Accessibility
8918 * API for this class, return this object, which is its own
8919 * {@code AccessibleContext}.
8920 *
8921 * @return this object
8922 */
8923 public AccessibleContext getAccessibleContext() {
8924 return this;
8925 }
8926
8927 /*
8928 * Returns the AccessibleContext for the header cell
8929 * renderer.
8930 */
8931 private AccessibleContext getCurrentAccessibleContext() {
8932 return rendererComponent.getAccessibleContext();
8933 }
8934
8935 /*
8936 * Returns the component that renders the header cell.
8937 */
8938 private Component getCurrentComponent() {
8939 return rendererComponent;
8940 }
8941
8942 // AccessibleContext methods ==========
8943
8944 /**
8945 * Gets the accessible name of this object.
8946 *
8947 * @return the localized name of the object; {@code null}
8948 * if this object does not have a name
8949 */
8950 public String getAccessibleName() {
8951 AccessibleContext ac = getCurrentAccessibleContext();
8952 if (ac != null) {
8953 String name = ac.getAccessibleName();
8954 if ((name != null) && (name != "")) {
8955 return ac.getAccessibleName();
8956 }
8957 }
8958 if ((accessibleName != null) && (accessibleName != "")) {
8959 return accessibleName;
8960 } else {
8961 return null;
8962 }
8963 }
8964
8965 /**
8966 * Sets the localized accessible name of this object.
8967 *
8968 * @param s the new localized name of the object
8969 */
8970 public void setAccessibleName(String s) {
8971 AccessibleContext ac = getCurrentAccessibleContext();
8972 if (ac != null) {
8973 ac.setAccessibleName(s);
8974 } else {
8975 super.setAccessibleName(s);
8976 }
8977 }
8978
8979 /**
8980 * Gets the accessible description of this object.
8981 *
8982 * @return the localized description of the object;
8983 * {@code null} if this object does not have
8984 * a description
8985 */
8986 public String getAccessibleDescription() {
8987 AccessibleContext ac = getCurrentAccessibleContext();
8988 if (ac != null) {
8989 return ac.getAccessibleDescription();
8990 } else {
8991 return super.getAccessibleDescription();
8992 }
8993 }
8994
8995 /**
8996 * Sets the accessible description of this object.
8997 *
8998 * @param s the new localized description of the object
8999 */
9000 public void setAccessibleDescription(String s) {
9001 AccessibleContext ac = getCurrentAccessibleContext();
9002 if (ac != null) {
9003 ac.setAccessibleDescription(s);
9004 } else {
9005 super.setAccessibleDescription(s);
9006 }
9007 }
9008
9009 /**
9010 * Gets the role of this object.
9011 *
9012 * @return an instance of {@code AccessibleRole}
9013 * describing the role of the object
9014 * @see AccessibleRole
9015 */
9016 public AccessibleRole getAccessibleRole() {
9017 AccessibleContext ac = getCurrentAccessibleContext();
9018 if (ac != null) {
9019 return ac.getAccessibleRole();
9020 } else {
9021 return AccessibleRole.UNKNOWN;
9022 }
9023 }
9024
9025 /**
9026 * Gets the state set of this object.
9027 *
9028 * @return an instance of {@code AccessibleStateSet}
9029 * containing the current state set of the object
9030 * @see AccessibleState
9031 */
9032 public AccessibleStateSet getAccessibleStateSet() {
9033 AccessibleContext ac = getCurrentAccessibleContext();
9034 AccessibleStateSet as = null;
9035
9036 if (ac != null) {
9037 as = ac.getAccessibleStateSet();
9038 }
9039 if (as == null) {
9040 as = new AccessibleStateSet();
9041 }
9042 Rectangle rjt = JTable.this.getVisibleRect();
9043 Rectangle rcell = JTable.this.getCellRect(row, column, false);
9044 if (rjt.intersects(rcell)) {
9045 as.add(AccessibleState.SHOWING);
9046 } else {
9047 if (as.contains(AccessibleState.SHOWING)) {
9048 as.remove(AccessibleState.SHOWING);
9049 }
9050 }
9051 if (JTable.this.isCellSelected(row, column)) {
9052 as.add(AccessibleState.SELECTED);
9053 } else if (as.contains(AccessibleState.SELECTED)) {
9054 as.remove(AccessibleState.SELECTED);
9055 }
9056 if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
9057 as.add(AccessibleState.ACTIVE);
9058 }
9059 as.add(AccessibleState.TRANSIENT);
9060 return as;
9061 }
9062
9063 /**
9064 * Gets the {@code Accessible} parent of this object.
9065 *
9066 * @return the Accessible parent of this object;
9067 * {@code null} if this object does not
9068 * have an {@code Accessible} parent
9069 */
9070 public Accessible getAccessibleParent() {
9071 return parent;
9072 }
9073
9074 /**
9075 * Gets the index of this object in its accessible parent.
9076 *
9077 * @return the index of this object in its parent; -1 if this
9078 * object does not have an accessible parent
9079 * @see #getAccessibleParent
9080 */
9081 public int getAccessibleIndexInParent() {
9082 return column;
9083 }
9084
9085 /**
9086 * Returns the number of accessible children in the object.
9087 *
9088 * @return the number of accessible children in the object
9089 */
9090 public int getAccessibleChildrenCount() {
9091 AccessibleContext ac = getCurrentAccessibleContext();
9092 if (ac != null) {
9093 return ac.getAccessibleChildrenCount();
9094 } else {
9095 return 0;
9096 }
9097 }
9098
9099 /**
9100 * Returns the specified {@code Accessible} child of the
9101 * object.
9102 *
9103 * @param i zero-based index of child
9104 * @return the {@code Accessible} child of the object
9105 */
9106 public Accessible getAccessibleChild(int i) {
9107 AccessibleContext ac = getCurrentAccessibleContext();
9108 if (ac != null) {
9109 Accessible accessibleChild = ac.getAccessibleChild(i);
9110 ac.setAccessibleParent(this);
9111 return accessibleChild;
9112 } else {
9113 return null;
9114 }
9115 }
9116
9117 /**
9118 * Gets the locale of the component. If the component
9119 * does not have a locale, then the locale of its parent
9120 * is returned.
9121 *
9122 * @return this component's locale; if this component does
9123 * not have a locale, the locale of its parent is returned
9124 * @exception IllegalComponentStateException if the
9125 * {@code Component} does not have its own locale
9126 * and has not yet been added to a containment hierarchy
9127 * such that the locale can be determined from the
9128 * containing parent
9129 * @see #setLocale
9130 */
9131 public Locale getLocale() {
9132 AccessibleContext ac = getCurrentAccessibleContext();
9133 if (ac != null) {
9134 return ac.getLocale();
9135 } else {
9136 return null;
9137 }
9138 }
9139
9140 /**
9141 * Adds a {@code PropertyChangeListener} to the listener list.
9142 * The listener is registered for all properties.
9143 *
9144 * @param l the {@code PropertyChangeListener}
9145 * to be added
9146 */
9147 public void addPropertyChangeListener(PropertyChangeListener l) {
9148 AccessibleContext ac = getCurrentAccessibleContext();
9149 if (ac != null) {
9150 ac.addPropertyChangeListener(l);
9151 } else {
9152 super.addPropertyChangeListener(l);
9153 }
9154 }
9155
9156 /**
9157 * Removes a {@code PropertyChangeListener} from the
9158 * listener list. This removes a {@code PropertyChangeListener}
9159 * that was registered for all properties.
9160 *
9161 * @param l the {@code PropertyChangeListener}
9162 * to be removed
9163 */
9164 public void removePropertyChangeListener(PropertyChangeListener l) {
9165 AccessibleContext ac = getCurrentAccessibleContext();
9166 if (ac != null) {
9167 ac.removePropertyChangeListener(l);
9168 } else {
9169 super.removePropertyChangeListener(l);
9170 }
9171 }
9172
9173 /**
9174 * Gets the {@code AccessibleAction} associated with this
9175 * object if one exists. Otherwise returns {@code null}.
9176 *
9177 * @return the {@code AccessibleAction}, or {@code null}
9178 */
9179 public AccessibleAction getAccessibleAction() {
9180 return getCurrentAccessibleContext().getAccessibleAction();
9181 }
9182
9183 /**
9184 * Gets the {@code AccessibleComponent} associated with
9185 * this object if one exists. Otherwise returns {@code null}.
9186 *
9187 * @return the {@code AccessibleComponent}, or
9188 * {@code null}
9189 */
9190 public AccessibleComponent getAccessibleComponent() {
9191 return this; // to override getBounds()
9192 }
9193
9194 /**
9195 * Gets the {@code AccessibleSelection} associated with
9196 * this object if one exists. Otherwise returns {@code null}.
9197 *
9198 * @return the {@code AccessibleSelection}, or
9199 * {@code null}
9200 */
9201 public AccessibleSelection getAccessibleSelection() {
9202 return getCurrentAccessibleContext().getAccessibleSelection();
9203 }
9204
9205 /**
9206 * Gets the {@code AccessibleText} associated with this
9207 * object if one exists. Otherwise returns {@code null}.
9208 *
9209 * @return the {@code AccessibleText}, or {@code null}
9210 */
9211 public AccessibleText getAccessibleText() {
9212 return getCurrentAccessibleContext().getAccessibleText();
9213 }
9214
9215 /**
9216 * Gets the {@code AccessibleValue} associated with
9217 * this object if one exists. Otherwise returns {@code null}.
9218 *
9219 * @return the {@code AccessibleValue}, or {@code null}
9220 */
9221 public AccessibleValue getAccessibleValue() {
9222 return getCurrentAccessibleContext().getAccessibleValue();
9223 }
9224
9225
9226 // AccessibleComponent methods ==========
9227
9228 /**
9229 * Gets the background color of this object.
9230 *
9231 * @return the background color, if supported, of the object;
9232 * otherwise, {@code null}
9233 */
9234 public Color getBackground() {
9235 AccessibleContext ac = getCurrentAccessibleContext();
9236 if (ac instanceof AccessibleComponent) {
9237 return ((AccessibleComponent) ac).getBackground();
9238 } else {
9239 Component c = getCurrentComponent();
9240 if (c != null) {
9241 return c.getBackground();
9242 } else {
9243 return null;
9244 }
9245 }
9246 }
9247
9248 /**
9249 * Sets the background color of this object.
9250 *
9251 * @param c the new {@code Color} for the background
9252 */
9253 public void setBackground(Color c) {
9254 AccessibleContext ac = getCurrentAccessibleContext();
9255 if (ac instanceof AccessibleComponent) {
9256 ((AccessibleComponent) ac).setBackground(c);
9257 } else {
9258 Component cp = getCurrentComponent();
9259 if (cp != null) {
9260 cp.setBackground(c);
9261 }
9262 }
9263 }
9264
9265 /**
9266 * Gets the foreground color of this object.
9267 *
9268 * @return the foreground color, if supported, of the object;
9269 * otherwise, {@code null}
9270 */
9271 public Color getForeground() {
9272 AccessibleContext ac = getCurrentAccessibleContext();
9273 if (ac instanceof AccessibleComponent) {
9274 return ((AccessibleComponent) ac).getForeground();
9275 } else {
9276 Component c = getCurrentComponent();
9277 if (c != null) {
9278 return c.getForeground();
9279 } else {
9280 return null;
9281 }
9282 }
9283 }
9284
9285 /**
9286 * Sets the foreground color of this object.
9287 *
9288 * @param c the new {@code Color} for the foreground
9289 */
9290 public void setForeground(Color c) {
9291 AccessibleContext ac = getCurrentAccessibleContext();
9292 if (ac instanceof AccessibleComponent) {
9293 ((AccessibleComponent) ac).setForeground(c);
9294 } else {
9295 Component cp = getCurrentComponent();
9296 if (cp != null) {
9297 cp.setForeground(c);
9298 }
9299 }
9300 }
9301
9302 /**
9303 * Gets the {@code Cursor} of this object.
9304 *
9305 * @return the {@code Cursor}, if supported,
9306 * of the object; otherwise, {@code null}
9307 */
9308 public Cursor getCursor() {
9309 AccessibleContext ac = getCurrentAccessibleContext();
9310 if (ac instanceof AccessibleComponent) {
9311 return ((AccessibleComponent) ac).getCursor();
9312 } else {
9313 Component c = getCurrentComponent();
9314 if (c != null) {
9315 return c.getCursor();
9316 } else {
9317 Accessible ap = getAccessibleParent();
9318 if (ap instanceof AccessibleComponent) {
9319 return ((AccessibleComponent) ap).getCursor();
9320 } else {
9321 return null;
9322 }
9323 }
9324 }
9325 }
9326
9327 /**
9328 * Sets the {@code Cursor} of this object.
9329 *
9330 * @param c the new {@code Cursor} for the object
9331 */
9332 public void setCursor(Cursor c) {
9333 AccessibleContext ac = getCurrentAccessibleContext();
9334 if (ac instanceof AccessibleComponent) {
9335 ((AccessibleComponent) ac).setCursor(c);
9336 } else {
9337 Component cp = getCurrentComponent();
9338 if (cp != null) {
9339 cp.setCursor(c);
9340 }
9341 }
9342 }
9343
9344 /**
9345 * Gets the {@code Font} of this object.
9346 *
9347 * @return the {@code Font},if supported,
9348 * for the object; otherwise, {@code null}
9349 */
9350 public Font getFont() {
9351 AccessibleContext ac = getCurrentAccessibleContext();
9352 if (ac instanceof AccessibleComponent) {
9353 return ((AccessibleComponent) ac).getFont();
9354 } else {
9355 Component c = getCurrentComponent();
9356 if (c != null) {
9357 return c.getFont();
9358 } else {
9359 return null;
9360 }
9361 }
9362 }
9363
9364 /**
9365 * Sets the {@code Font} of this object.
9366 *
9367 * @param f the new {@code Font} for the object
9368 */
9369 public void setFont(Font f) {
9370 AccessibleContext ac = getCurrentAccessibleContext();
9371 if (ac instanceof AccessibleComponent) {
9372 ((AccessibleComponent) ac).setFont(f);
9373 } else {
9374 Component c = getCurrentComponent();
9375 if (c != null) {
9376 c.setFont(f);
9377 }
9378 }
9379 }
9380
9381 /**
9382 * Gets the {@code FontMetrics} of this object.
9383 *
9384 * @param f the {@code Font}
9385 * @return the {@code FontMetrics} object, if supported;
9386 * otherwise {@code null}
9387 * @see #getFont
9388 */
9389 public FontMetrics getFontMetrics(Font f) {
9390 AccessibleContext ac = getCurrentAccessibleContext();
9391 if (ac instanceof AccessibleComponent) {
9392 return ((AccessibleComponent) ac).getFontMetrics(f);
9393 } else {
9394 Component c = getCurrentComponent();
9395 if (c != null) {
9396 return c.getFontMetrics(f);
9397 } else {
9398 return null;
9399 }
9400 }
9401 }
9402
9403 /**
9404 * Determines if the object is enabled.
9405 *
9406 * @return true if object is enabled; otherwise, false
9424 *
9425 * @param b if true, enables this object; otherwise, disables it
9426 */
9427 public void setEnabled(boolean b) {
9428 AccessibleContext ac = getCurrentAccessibleContext();
9429 if (ac instanceof AccessibleComponent) {
9430 ((AccessibleComponent) ac).setEnabled(b);
9431 } else {
9432 Component c = getCurrentComponent();
9433 if (c != null) {
9434 c.setEnabled(b);
9435 }
9436 }
9437 }
9438
9439 /**
9440 * Determines if this object is visible. Note: this means that the
9441 * object intends to be visible; however, it may not in fact be
9442 * showing on the screen because one of the objects that this object
9443 * is contained by is not visible. To determine if an object is
9444 * showing on the screen, use {@code isShowing}.
9445 *
9446 * @return true if object is visible; otherwise, false
9447 */
9448 public boolean isVisible() {
9449 AccessibleContext ac = getCurrentAccessibleContext();
9450 if (ac instanceof AccessibleComponent) {
9451 return ((AccessibleComponent) ac).isVisible();
9452 } else {
9453 Component c = getCurrentComponent();
9454 if (c != null) {
9455 return c.isVisible();
9456 } else {
9457 return false;
9458 }
9459 }
9460 }
9461
9462 /**
9463 * Sets the visible state of the object.
9464 *
9495 // returns false when the cell on the screen
9496 // if no parent
9497 return isVisible();
9498 }
9499 } else {
9500 Component c = getCurrentComponent();
9501 if (c != null) {
9502 return c.isShowing();
9503 } else {
9504 return false;
9505 }
9506 }
9507 }
9508
9509 /**
9510 * Checks whether the specified point is within this
9511 * object's bounds, where the point's x and y coordinates
9512 * are defined to be relative to the coordinate system of
9513 * the object.
9514 *
9515 * @param p the {@code Point} relative to the
9516 * coordinate system of the object
9517 * @return true if object contains {@code Point};
9518 * otherwise false
9519 */
9520 public boolean contains(Point p) {
9521 AccessibleContext ac = getCurrentAccessibleContext();
9522 if (ac instanceof AccessibleComponent) {
9523 Rectangle r = ((AccessibleComponent) ac).getBounds();
9524 return r.contains(p);
9525 } else {
9526 Component c = getCurrentComponent();
9527 if (c != null) {
9528 Rectangle r = c.getBounds();
9529 return r.contains(p);
9530 } else {
9531 return getBounds().contains(p);
9532 }
9533 }
9534 }
9535
9536 /**
9537 * Returns the location of the object on the screen.
9538 *
9539 * @return location of object on screen -- can be
9540 * {@code null} if this object is not on the screen
9541 */
9542 public Point getLocationOnScreen() {
9543 if (parent != null && parent.isShowing()) {
9544 Point parentLocation = parent.getLocationOnScreen();
9545 Point componentLocation = getLocation();
9546 componentLocation.translate(parentLocation.x, parentLocation.y);
9547 return componentLocation;
9548 } else {
9549 return null;
9550 }
9551 }
9552
9553 /**
9554 * Gets the location of the object relative to the parent
9555 * in the form of a point specifying the object's
9556 * top-left corner in the screen's coordinate space.
9557 *
9558 * @return an instance of {@code Point} representing
9559 * the top-left corner of the object's bounds in the
9560 * coordinate space of the screen; {@code null} if
9561 * this object or its parent are not on the screen
9562 */
9563 public Point getLocation() {
9564 if (parent != null) {
9565 Rectangle r = parent.getHeaderRect(column);
9566 if (r != null) {
9567 return r.getLocation();
9568 }
9569 }
9570 return null;
9571 }
9572
9573 /**
9574 * Sets the location of the object relative to the parent.
9575 * @param p the new position for the top-left corner
9576 * @see #getLocation
9577 */
9578 public void setLocation(Point p) {
9579 }
9580
|