1 /*
2  * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package javax.swing;
26 
27 import java.util.*;
28 
29 import java.applet.Applet;
30 import java.awt.*;
31 import java.awt.event.*;
32 import java.awt.print.*;
33 
34 import java.beans.JavaBean;
35 import java.beans.BeanProperty;
36 import java.beans.PropertyChangeEvent;
37 import java.beans.PropertyChangeListener;
38 
39 import java.io.ObjectOutputStream;
40 import java.io.ObjectInputStream;
41 import java.io.IOException;
42 import java.io.InvalidObjectException;
43 
44 import javax.accessibility.*;
45 
46 import javax.swing.event.*;
47 import javax.swing.plaf.*;
48 import javax.swing.table.*;
49 import javax.swing.border.*;
50 
51 import java.text.NumberFormat;
52 import java.text.DateFormat;
53 import java.text.MessageFormat;
54 import java.util.List;
55 
56 import javax.print.attribute.*;
57 import javax.print.PrintService;
58 
59 import sun.awt.AWTAccessor;
60 import sun.awt.AWTAccessor.MouseEventAccessor;
61 import sun.reflect.misc.ReflectUtil;
62 
63 import sun.swing.SwingUtilities2;
64 import sun.swing.SwingUtilities2.Section;
65 import static sun.swing.SwingUtilities2.Section.*;
66 import sun.swing.PrintingStatus;
67 
68 /**
69  * The <code>JTable</code> is used to display and edit regular two-dimensional tables
70  * of cells.
71  * See <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/table.html">How to Use Tables</a>
72  * in <em>The Java Tutorial</em>
73  * for task-oriented documentation and examples of using <code>JTable</code>.
74  *
75  * <p>
76  * The <code>JTable</code> has many
77  * facilities that make it possible to customize its rendering and editing
78  * but provides defaults for these features so that simple tables can be
79  * set up easily.  For example, to set up a table with 10 rows and 10
80  * columns of numbers:
81  *
82  * <pre>
83  *      TableModel dataModel = new AbstractTableModel() {
84  *          public int getColumnCount() { return 10; }
85  *          public int getRowCount() { return 10;}
86  *          public Object getValueAt(int row, int col) { return Integer.valueOf(row*col); }
87  *      };
88  *      JTable table = new JTable(dataModel);
89  *      JScrollPane scrollpane = new JScrollPane(table);
90  * </pre>
91  * <p>
92  * {@code JTable}s are typically placed inside of a {@code JScrollPane}.  By
93  * default, a {@code JTable} will adjust its width such that
94  * a horizontal scrollbar is unnecessary.  To allow for a horizontal scrollbar,
95  * invoke {@link #setAutoResizeMode} with {@code AUTO_RESIZE_OFF}.
96  * Note that if you wish to use a <code>JTable</code> in a standalone
97  * view (outside of a <code>JScrollPane</code>) and want the header
98  * displayed, you can get it using {@link #getTableHeader} and
99  * display it separately.
100  * <p>
101  * To enable sorting and filtering of rows, use a
102  * {@code RowSorter}.
103  * You can set up a row sorter in either of two ways:
104  * <ul>
105  *   <li>Directly set the {@code RowSorter}. For example:
106  *        {@code table.setRowSorter(new TableRowSorter(model))}.
107  *   <li>Set the {@code autoCreateRowSorter}
108  *       property to {@code true}, so that the {@code JTable}
109  *       creates a {@code RowSorter} for
110  *       you. For example: {@code setAutoCreateRowSorter(true)}.
111  * </ul>
112  * <p>
113  * When designing applications that use the <code>JTable</code> it is worth paying
114  * close attention to the data structures that will represent the table's data.
115  * The <code>DefaultTableModel</code> is a model implementation that
116  * uses a <code>Vector</code> of <code>Vector</code>s of <code>Object</code>s to
117  * store the cell values. As well as copying the data from an
118  * application into the <code>DefaultTableModel</code>,
119  * it is also possible to wrap the data in the methods of the
120  * <code>TableModel</code> interface so that the data can be passed to the
121  * <code>JTable</code> directly, as in the example above. This often results
122  * in more efficient applications because the model is free to choose the
123  * internal representation that best suits the data.
124  * A good rule of thumb for deciding whether to use the <code>AbstractTableModel</code>
125  * or the <code>DefaultTableModel</code> is to use the <code>AbstractTableModel</code>
126  * as the base class for creating subclasses and the <code>DefaultTableModel</code>
127  * when subclassing is not required.
128  * <p>
129  * The "TableExample" directory in the demo area of the source distribution
130  * gives a number of complete examples of <code>JTable</code> usage,
131  * covering how the <code>JTable</code> can be used to provide an
132  * editable view of data taken from a database and how to modify
133  * the columns in the display to use specialized renderers and editors.
134  * <p>
135  * The <code>JTable</code> uses integers exclusively to refer to both the rows and the columns
136  * of the model that it displays. The <code>JTable</code> simply takes a tabular range of cells
137  * and uses <code>getValueAt(int, int)</code> to retrieve the
138  * values from the model during painting.  It is important to remember that
139  * the column and row indexes returned by various <code>JTable</code> methods
140  * are in terms of the <code>JTable</code> (the view) and are not
141  * necessarily the same indexes used by the model.
142  * <p>
143  * By default, columns may be rearranged in the <code>JTable</code> so that the
144  * view's columns appear in a different order to the columns in the model.
145  * This does not affect the implementation of the model at all: when the
146  * columns are reordered, the <code>JTable</code> maintains the new order of the columns
147  * internally and converts its column indices before querying the model.
148  * <p>
149  * So, when writing a <code>TableModel</code>, it is not necessary to listen for column
150  * reordering events as the model will be queried in its own coordinate
151  * system regardless of what is happening in the view.
152  * In the examples area there is a demonstration of a sorting algorithm making
153  * use of exactly this technique to interpose yet another coordinate system
154  * where the order of the rows is changed, rather than the order of the columns.
155  * <p>
156  * Similarly when using the sorting and filtering functionality
157  * provided by <code>RowSorter</code> the underlying
158  * <code>TableModel</code> does not need to know how to do sorting,
159  * rather <code>RowSorter</code> will handle it.  Coordinate
160  * conversions will be necessary when using the row based methods of
161  * <code>JTable</code> with the underlying <code>TableModel</code>.
162  * All of <code>JTable</code>s row based methods are in terms of the
163  * <code>RowSorter</code>, which is not necessarily the same as that
164  * of the underlying <code>TableModel</code>.  For example, the
165  * selection is always in terms of <code>JTable</code> so that when
166  * using <code>RowSorter</code> you will need to convert using
167  * <code>convertRowIndexToView</code> or
168  * <code>convertRowIndexToModel</code>.  The following shows how to
169  * convert coordinates from <code>JTable</code> to that of the
170  * underlying model:
171  * <pre>
172  *   int[] selection = table.getSelectedRows();
173  *   for (int i = 0; i &lt; selection.length; i++) {
174  *     selection[i] = table.convertRowIndexToModel(selection[i]);
175  *   }
176  *   // selection is now in terms of the underlying TableModel
177  * </pre>
178  * <p>
179  * By default if sorting is enabled <code>JTable</code> will persist the
180  * selection and variable row heights in terms of the model on
181  * sorting.  For example if row 0, in terms of the underlying model,
182  * is currently selected, after the sort row 0, in terms of the
183  * underlying model will be selected.  Visually the selection may
184  * change, but in terms of the underlying model it will remain the
185  * same.  The one exception to that is if the model index is no longer
186  * visible or was removed.  For example, if row 0 in terms of model
187  * was filtered out the selection will be empty after the sort.
188  * <p>
189  * J2SE 5 adds methods to <code>JTable</code> to provide convenient access to some
190  * common printing needs. Simple new {@link #print()} methods allow for quick
191  * and easy addition of printing support to your application. In addition, a new
192  * {@link #getPrintable} method is available for more advanced printing needs.
193  * <p>
194  * As for all <code>JComponent</code> classes, you can use
195  * {@link InputMap} and {@link ActionMap} to associate an
196  * {@link Action} object with a {@link KeyStroke} and execute the
197  * action under specified conditions.
198  * <p>
199  * <strong>Warning:</strong> Swing is not thread safe. For more
200  * information see <a
201  * href="package-summary.html#threading">Swing's Threading
202  * Policy</a>.
203  * <p>
204  * <strong>Warning:</strong>
205  * Serialized objects of this class will not be compatible with
206  * future Swing releases. The current serialization support is
207  * appropriate for short term storage or RMI between applications running
208  * the same version of Swing.  As of 1.4, support for long term storage
209  * of all JavaBeans&trade;
210  * has been added to the <code>java.beans</code> package.
211  * Please see {@link java.beans.XMLEncoder}.
212  *
213  * @author Philip Milne
214  * @author Shannon Hickey (printing support)
215  * @see javax.swing.table.DefaultTableModel
216  * @see javax.swing.table.TableRowSorter
217  * @since 1.2
218  */
219 /* The first versions of the JTable, contained in Swing-0.1 through
220  * Swing-0.4, were written by Alan Chung.
221  */
222 @JavaBean(defaultProperty = "UI", description = "A component which displays data in a two dimensional grid.")
223 @SwingContainer(false)
224 @SuppressWarnings("serial") // Same-version serialization only
225 public class JTable extends JComponent implements TableModelListener, Scrollable,
226     TableColumnModelListener, ListSelectionListener, CellEditorListener,
227     Accessible, RowSorterListener
228 {
229 //
230 // Static Constants
231 //
232 
233     /**
234      * @see #getUIClassID
235      * @see #readObject
236      */
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;
394     private PropertyChangeListener editorRemover = null;
395     /**
396      * The last value of getValueIsAdjusting from the column selection models
397      * columnSelectionChanged notification. Used to test if a repaint is
398      * needed.
399      */
400     private boolean columnSelectionAdjusting;
401     /**
402      * The last value of getValueIsAdjusting from the row selection models
403      * valueChanged notification. Used to test if a repaint is needed.
404      */
405     private boolean rowSelectionAdjusting;
406 
407     /**
408      * To communicate errors between threads during printing.
409      */
410     private Throwable printError;
411 
412     /**
413      * True when setRowHeight(int) has been invoked.
414      */
415     private boolean isRowHeightSet;
416 
417     /**
418      * If true, on a sort the selection is reset.
419      */
420     private boolean updateSelectionOnSort;
421 
422     /**
423      * Information used in sorting.
424      */
425     private transient SortManager sortManager;
426 
427     /**
428      * If true, when sorterChanged is invoked it's value is ignored.
429      */
430     private boolean ignoreSortChange;
431 
432     /**
433      * Whether or not sorterChanged has been invoked.
434      */
435     private boolean sorterChanged;
436 
437     /**
438      * If true, any time the model changes a new RowSorter is set.
439      */
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      * Flag to indicate UI update is in progress
461      */
462     private transient boolean updateInProgress;
463 
464     /**
465      * A subclass of <code>TransferHandler.DropLocation</code> representing
466      * a drop location for a <code>JTable</code>.
467      *
468      * @see #getDropLocation
469      * @since 1.6
470      */
471     public static final class DropLocation extends TransferHandler.DropLocation {
472         private final int row;
473         private final int col;
474         private final boolean isInsertRow;
475         private final boolean isInsertCol;
476 
DropLocation(Point p, int row, int col, boolean isInsertRow, boolean isInsertCol)477         private DropLocation(Point p, int row, int col,
478                              boolean isInsertRow, boolean isInsertCol) {
479 
480             super(p);
481             this.row = row;
482             this.col = col;
483             this.isInsertRow = isInsertRow;
484             this.isInsertCol = isInsertCol;
485         }
486 
487         /**
488          * Returns the row index where a dropped item should be placed in the
489          * table. Interpretation of the value depends on the return of
490          * <code>isInsertRow()</code>. If that method returns
491          * <code>true</code> this value indicates the index where a new
492          * row should be inserted. Otherwise, it represents the value
493          * of an existing row on which the data was dropped. This index is
494          * in terms of the view.
495          * <p>
496          * <code>-1</code> indicates that the drop occurred over empty space,
497          * and no row could be calculated.
498          *
499          * @return the drop row
500          */
getRow()501         public int getRow() {
502             return row;
503         }
504 
505         /**
506          * Returns the column index where a dropped item should be placed in the
507          * table. Interpretation of the value depends on the return of
508          * <code>isInsertColumn()</code>. If that method returns
509          * <code>true</code> this value indicates the index where a new
510          * column should be inserted. Otherwise, it represents the value
511          * of an existing column on which the data was dropped. This index is
512          * in terms of the view.
513          * <p>
514          * <code>-1</code> indicates that the drop occurred over empty space,
515          * and no column could be calculated.
516          *
517          * @return the drop row
518          */
getColumn()519         public int getColumn() {
520             return col;
521         }
522 
523         /**
524          * Returns whether or not this location represents an insert
525          * of a row.
526          *
527          * @return whether or not this is an insert row
528          */
isInsertRow()529         public boolean isInsertRow() {
530             return isInsertRow;
531         }
532 
533         /**
534          * Returns whether or not this location represents an insert
535          * of a column.
536          *
537          * @return whether or not this is an insert column
538          */
isInsertColumn()539         public boolean isInsertColumn() {
540             return isInsertCol;
541         }
542 
543         /**
544          * Returns a string representation of this drop location.
545          * This method is intended to be used for debugging purposes,
546          * and the content and format of the returned string may vary
547          * between implementations.
548          *
549          * @return a string representation of this drop location
550          */
toString()551         public String toString() {
552             return getClass().getName()
553                    + "[dropPoint=" + getDropPoint() + ","
554                    + "row=" + row + ","
555                    + "column=" + col + ","
556                    + "insertRow=" + isInsertRow + ","
557                    + "insertColumn=" + isInsertCol + "]";
558         }
559     }
560 
561 //
562 // Constructors
563 //
564 
565     /**
566      * Constructs a default <code>JTable</code> that is initialized with a default
567      * data model, a default column model, and a default selection
568      * model.
569      *
570      * @see #createDefaultDataModel
571      * @see #createDefaultColumnModel
572      * @see #createDefaultSelectionModel
573      */
JTable()574     public JTable() {
575         this(null, null, null);
576     }
577 
578     /**
579      * Constructs a <code>JTable</code> that is initialized with
580      * <code>dm</code> as the data model, a default column model,
581      * and a default selection model.
582      *
583      * @param dm        the data model for the table
584      * @see #createDefaultColumnModel
585      * @see #createDefaultSelectionModel
586      */
JTable(TableModel dm)587     public JTable(TableModel dm) {
588         this(dm, null, null);
589     }
590 
591     /**
592      * Constructs a <code>JTable</code> that is initialized with
593      * <code>dm</code> as the data model, <code>cm</code>
594      * as the column model, and a default selection model.
595      *
596      * @param dm        the data model for the table
597      * @param cm        the column model for the table
598      * @see #createDefaultSelectionModel
599      */
JTable(TableModel dm, TableColumnModel cm)600     public JTable(TableModel dm, TableColumnModel cm) {
601         this(dm, cm, null);
602     }
603 
604     /**
605      * Constructs a <code>JTable</code> that is initialized with
606      * <code>dm</code> as the data model, <code>cm</code> as the
607      * column model, and <code>sm</code> as the selection model.
608      * If any of the parameters are <code>null</code> this method
609      * will initialize the table with the corresponding default model.
610      * The <code>autoCreateColumnsFromModel</code> flag is set to false
611      * if <code>cm</code> is non-null, otherwise it is set to true
612      * and the column model is populated with suitable
613      * <code>TableColumns</code> for the columns in <code>dm</code>.
614      *
615      * @param dm        the data model for the table
616      * @param cm        the column model for the table
617      * @param sm        the row selection model for the table
618      * @see #createDefaultDataModel
619      * @see #createDefaultColumnModel
620      * @see #createDefaultSelectionModel
621      */
JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm)622     public JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
623         super();
624         setLayout(null);
625 
626         setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
627                            JComponent.getManagingFocusForwardTraversalKeys());
628         setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
629                            JComponent.getManagingFocusBackwardTraversalKeys());
630         if (cm == null) {
631             cm = createDefaultColumnModel();
632             autoCreateColumnsFromModel = true;
633         }
634         setColumnModel(cm);
635 
636         if (sm == null) {
637             sm = createDefaultSelectionModel();
638         }
639         setSelectionModel(sm);
640 
641     // Set the model last, that way if the autoCreatColumnsFromModel has
642     // been set above, we will automatically populate an empty columnModel
643     // with suitable columns for the new model.
644         if (dm == null) {
645             dm = createDefaultDataModel();
646         }
647         setModel(dm);
648 
649         initializeLocalVars();
650         updateUI();
651     }
652 
653     /**
654      * Constructs a <code>JTable</code> with <code>numRows</code>
655      * and <code>numColumns</code> of empty cells using
656      * <code>DefaultTableModel</code>.  The columns will have
657      * names of the form "A", "B", "C", etc.
658      *
659      * @param numRows           the number of rows the table holds
660      * @param numColumns        the number of columns the table holds
661      * @see javax.swing.table.DefaultTableModel
662      */
JTable(int numRows, int numColumns)663     public JTable(int numRows, int numColumns) {
664         this(new DefaultTableModel(numRows, numColumns));
665     }
666 
667     /**
668      * Constructs a <code>JTable</code> to display the values in the
669      * <code>Vector</code> of <code>Vectors</code>, <code>rowData</code>,
670      * with column names, <code>columnNames</code>.  The
671      * <code>Vectors</code> contained in <code>rowData</code>
672      * should contain the values for that row. In other words,
673      * the value of the cell at row 1, column 5 can be obtained
674      * with the following code:
675      *
676      * <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
677      *
678      * @param rowData           the data for the new table
679      * @param columnNames       names of each column
680      */
681     @SuppressWarnings("rawtypes")
JTable(Vector<? extends Vector> rowData, Vector<?> columnNames)682     public JTable(Vector<? extends Vector> rowData, Vector<?> columnNames) {
683         this(new DefaultTableModel(rowData, columnNames));
684     }
685 
686     /**
687      * Constructs a <code>JTable</code> to display the values in the two dimensional array,
688      * <code>rowData</code>, with column names, <code>columnNames</code>.
689      * <code>rowData</code> is an array of rows, so the value of the cell at row 1,
690      * column 5 can be obtained with the following code:
691      *
692      * <pre> rowData[1][5]; </pre>
693      * <p>
694      * All rows must be of the same length as <code>columnNames</code>.
695      *
696      * @param rowData           the data for the new table
697      * @param columnNames       names of each column
698      */
JTable(final Object[][] rowData, final Object[] columnNames)699     public JTable(final Object[][] rowData, final Object[] columnNames) {
700         this(new AbstractTableModel() {
701             public String getColumnName(int column) { return columnNames[column].toString(); }
702             public int getRowCount() { return rowData.length; }
703             public int getColumnCount() { return columnNames.length; }
704             public Object getValueAt(int row, int col) { return rowData[row][col]; }
705             public boolean isCellEditable(int row, int column) { return true; }
706             public void setValueAt(Object value, int row, int col) {
707                 rowData[row][col] = value;
708                 fireTableCellUpdated(row, col);
709             }
710         });
711     }
712 
713     /**
714      * Calls the <code>configureEnclosingScrollPane</code> method.
715      *
716      * @see #configureEnclosingScrollPane
717      */
addNotify()718     public void addNotify() {
719         super.addNotify();
720         configureEnclosingScrollPane();
721     }
722 
723     /**
724      * If this <code>JTable</code> is the <code>viewportView</code> of an enclosing <code>JScrollPane</code>
725      * (the usual situation), configure this <code>ScrollPane</code> by, amongst other things,
726      * installing the table's <code>tableHeader</code> as the <code>columnHeaderView</code> of the scroll pane.
727      * When a <code>JTable</code> is added to a <code>JScrollPane</code> in the usual way,
728      * using <code>new JScrollPane(myTable)</code>, <code>addNotify</code> is
729      * called in the <code>JTable</code> (when the table is added to the viewport).
730      * <code>JTable</code>'s <code>addNotify</code> method in turn calls this method,
731      * which is protected so that this default installation procedure can
732      * be overridden by a subclass.
733      *
734      * @see #addNotify
735      */
configureEnclosingScrollPane()736     protected void configureEnclosingScrollPane() {
737         Container parent = SwingUtilities.getUnwrappedParent(this);
738         if (parent instanceof JViewport) {
739             JViewport port = (JViewport) parent;
740             Container gp = port.getParent();
741             if (gp instanceof JScrollPane) {
742                 JScrollPane scrollPane = (JScrollPane)gp;
743                 // Make certain we are the viewPort's view and not, for
744                 // example, the rowHeaderView of the scrollPane -
745                 // an implementor of fixed columns might do this.
746                 JViewport viewport = scrollPane.getViewport();
747                 if (viewport == null ||
748                         SwingUtilities.getUnwrappedView(viewport) != this) {
749                     return;
750                 }
751                 scrollPane.setColumnHeaderView(getTableHeader());
752                 // configure the scrollpane for any LAF dependent settings
753                 configureEnclosingScrollPaneUI();
754             }
755         }
756     }
757 
758     /**
759      * This is a sub-part of configureEnclosingScrollPane() that configures
760      * anything on the scrollpane that may change when the look and feel
761      * changes. It needed to be split out from configureEnclosingScrollPane() so
762      * that it can be called from updateUI() when the LAF changes without
763      * causing the regression found in bug 6687962. This was because updateUI()
764      * is called from the constructor which then caused
765      * configureEnclosingScrollPane() to be called by the constructor which
766      * changes its contract for any subclass that overrides it. So by splitting
767      * it out in this way configureEnclosingScrollPaneUI() can be called both
768      * from configureEnclosingScrollPane() and updateUI() in a safe manor.
769      */
configureEnclosingScrollPaneUI()770     private void configureEnclosingScrollPaneUI() {
771         Container parent = SwingUtilities.getUnwrappedParent(this);
772         if (parent instanceof JViewport) {
773             JViewport port = (JViewport) parent;
774             Container gp = port.getParent();
775             if (gp instanceof JScrollPane) {
776                 JScrollPane scrollPane = (JScrollPane)gp;
777                 // Make certain we are the viewPort's view and not, for
778                 // example, the rowHeaderView of the scrollPane -
779                 // an implementor of fixed columns might do this.
780                 JViewport viewport = scrollPane.getViewport();
781                 if (viewport == null ||
782                         SwingUtilities.getUnwrappedView(viewport) != this) {
783                     return;
784                 }
785                 //  scrollPane.getViewport().setBackingStoreEnabled(true);
786                 Border border = scrollPane.getBorder();
787                 if (border == null || border instanceof UIResource) {
788                     Border scrollPaneBorder =
789                         UIManager.getBorder("Table.scrollPaneBorder");
790                     if (scrollPaneBorder != null) {
791                         scrollPane.setBorder(scrollPaneBorder);
792                     }
793                 }
794                 // add JScrollBar corner component if available from LAF and not already set by the user
795                 Component corner =
796                         scrollPane.getCorner(JScrollPane.UPPER_TRAILING_CORNER);
797                 if (corner == null || corner instanceof UIResource){
798                     corner = null;
799                     try {
800                         corner = (Component) UIManager.get(
801                                 "Table.scrollPaneCornerComponent");
802                     } catch (Exception e) {
803                         // just ignore and don't set corner
804                     }
805                     scrollPane.setCorner(JScrollPane.UPPER_TRAILING_CORNER,
806                             corner);
807                 }
808             }
809         }
810     }
811 
812     /**
813      * Calls the <code>unconfigureEnclosingScrollPane</code> method.
814      *
815      * @see #unconfigureEnclosingScrollPane
816      */
removeNotify()817     public void removeNotify() {
818         KeyboardFocusManager.getCurrentKeyboardFocusManager().
819             removePropertyChangeListener("permanentFocusOwner", editorRemover);
820         editorRemover = null;
821         unconfigureEnclosingScrollPane();
822         super.removeNotify();
823     }
824 
825     /**
826      * Reverses the effect of <code>configureEnclosingScrollPane</code>
827      * by replacing the <code>columnHeaderView</code> of the enclosing
828      * scroll pane with <code>null</code>. <code>JTable</code>'s
829      * <code>removeNotify</code> method calls
830      * this method, which is protected so that this default uninstallation
831      * procedure can be overridden by a subclass.
832      *
833      * @see #removeNotify
834      * @see #configureEnclosingScrollPane
835      * @since 1.3
836      */
unconfigureEnclosingScrollPane()837     protected void unconfigureEnclosingScrollPane() {
838         Container parent = SwingUtilities.getUnwrappedParent(this);
839         if (parent instanceof JViewport) {
840             JViewport port = (JViewport) parent;
841             Container gp = port.getParent();
842             if (gp instanceof JScrollPane) {
843                 JScrollPane scrollPane = (JScrollPane)gp;
844                 // Make certain we are the viewPort's view and not, for
845                 // example, the rowHeaderView of the scrollPane -
846                 // an implementor of fixed columns might do this.
847                 JViewport viewport = scrollPane.getViewport();
848                 if (viewport == null ||
849                         SwingUtilities.getUnwrappedView(viewport) != this) {
850                     return;
851                 }
852                 scrollPane.setColumnHeaderView(null);
853                 // remove ScrollPane corner if one was added by the LAF
854                 Component corner =
855                         scrollPane.getCorner(JScrollPane.UPPER_TRAILING_CORNER);
856                 if (corner instanceof UIResource){
857                     scrollPane.setCorner(JScrollPane.UPPER_TRAILING_CORNER,
858                             null);
859                 }
860             }
861         }
862     }
863 
setUIProperty(String propertyName, Object value)864     void setUIProperty(String propertyName, Object value) {
865         if (propertyName == "rowHeight") {
866             if (!isRowHeightSet) {
867                 setRowHeight(((Number)value).intValue());
868                 isRowHeightSet = false;
869             }
870             return;
871         }
872         super.setUIProperty(propertyName, value);
873     }
874 
875 //
876 // Static Methods
877 //
878 
879     /**
880      * Equivalent to <code>new JScrollPane(aTable)</code>.
881      *
882      * @param aTable a {@code JTable} to be used for the scroll pane
883      * @return a {@code JScrollPane} created using {@code aTable}
884      * @deprecated As of Swing version 1.0.2,
885      * replaced by <code>new JScrollPane(aTable)</code>.
886      */
887     @Deprecated
createScrollPaneForTable(JTable aTable)888     public static JScrollPane createScrollPaneForTable(JTable aTable) {
889         return new JScrollPane(aTable);
890     }
891 
892 //
893 // Table Attributes
894 //
895 
896     /**
897      * Sets the <code>tableHeader</code> working with this <code>JTable</code> to <code>newHeader</code>.
898      * It is legal to have a <code>null</code> <code>tableHeader</code>.
899      *
900      * @param   tableHeader                       new tableHeader
901      * @see     #getTableHeader
902      */
903     @BeanProperty(description
904             = "The JTableHeader instance which renders the column headers.")
setTableHeader(JTableHeader tableHeader)905     public void setTableHeader(JTableHeader tableHeader) {
906         if (this.tableHeader != tableHeader) {
907             JTableHeader old = this.tableHeader;
908             // Release the old header
909             if (old != null) {
910                 old.setTable(null);
911             }
912             this.tableHeader = tableHeader;
913             if (tableHeader != null) {
914                 tableHeader.setTable(this);
915             }
916             firePropertyChange("tableHeader", old, tableHeader);
917         }
918     }
919 
920     /**
921      * Returns the <code>tableHeader</code> used by this <code>JTable</code>.
922      *
923      * @return  the <code>tableHeader</code> used by this table
924      * @see     #setTableHeader
925      */
getTableHeader()926     public JTableHeader getTableHeader() {
927         return tableHeader;
928     }
929 
930     /**
931      * Sets the height, in pixels, of all cells to <code>rowHeight</code>,
932      * revalidates, and repaints.
933      * The height of the cells will be equal to the row height minus
934      * the row margin.
935      *
936      * @param   rowHeight                       new row height
937      * @exception IllegalArgumentException      if <code>rowHeight</code> is
938      *                                          less than 1
939      * @see     #getRowHeight
940      */
941     @BeanProperty(description
942             = "The height of the specified row.")
setRowHeight(int rowHeight)943     public void setRowHeight(int rowHeight) {
944         if (rowHeight <= 0) {
945             throw new IllegalArgumentException("New row height less than 1");
946         }
947         int old = this.rowHeight;
948         this.rowHeight = rowHeight;
949         rowModel = null;
950         if (sortManager != null) {
951             sortManager.modelRowSizes = null;
952         }
953         isRowHeightSet = true;
954         resizeAndRepaint();
955         firePropertyChange("rowHeight", old, rowHeight);
956     }
957 
958     /**
959      * Returns the height of a table row, in pixels.
960      *
961      * @return  the height in pixels of a table row
962      * @see     #setRowHeight
963      */
getRowHeight()964     public int getRowHeight() {
965         return rowHeight;
966     }
967 
getRowModel()968     private SizeSequence getRowModel() {
969         if (rowModel == null) {
970             rowModel = new SizeSequence(getRowCount(), getRowHeight());
971         }
972         return rowModel;
973     }
974 
975     /**
976      * Sets the height for <code>row</code> to <code>rowHeight</code>,
977      * revalidates, and repaints. The height of the cells in this row
978      * will be equal to the row height minus the row margin.
979      *
980      * @param   row                             the row whose height is being
981                                                 changed
982      * @param   rowHeight                       new row height, in pixels
983      * @exception IllegalArgumentException      if <code>rowHeight</code> is
984      *                                          less than 1
985      * @since 1.3
986      */
987     @BeanProperty(description
988             = "The height in pixels of the cells in <code>row</code>")
setRowHeight(int row, int rowHeight)989     public void setRowHeight(int row, int rowHeight) {
990         if (rowHeight <= 0) {
991             throw new IllegalArgumentException("New row height less than 1");
992         }
993         getRowModel().setSize(row, rowHeight);
994         if (sortManager != null) {
995             sortManager.setViewRowHeight(row, rowHeight);
996         }
997         resizeAndRepaint();
998     }
999 
1000     /**
1001      * Returns the height, in pixels, of the cells in <code>row</code>.
1002      * @param   row              the row whose height is to be returned
1003      * @return the height, in pixels, of the cells in the row
1004      * @since 1.3
1005      */
getRowHeight(int row)1006     public int getRowHeight(int row) {
1007         return (rowModel == null) ? getRowHeight() : rowModel.getSize(row);
1008     }
1009 
1010     /**
1011      * Sets the amount of empty space between cells in adjacent rows.
1012      *
1013      * @param  rowMargin  the number of pixels between cells in a row
1014      * @see     #getRowMargin
1015      */
1016     @BeanProperty(description
1017             = "The amount of space between cells.")
setRowMargin(int rowMargin)1018     public void setRowMargin(int rowMargin) {
1019         int old = this.rowMargin;
1020         this.rowMargin = rowMargin;
1021         resizeAndRepaint();
1022         firePropertyChange("rowMargin", old, rowMargin);
1023     }
1024 
1025     /**
1026      * Gets the amount of empty space, in pixels, between cells. Equivalent to:
1027      * <code>getIntercellSpacing().height</code>.
1028      * @return the number of pixels between cells in a row
1029      *
1030      * @see     #setRowMargin
1031      */
getRowMargin()1032     public int getRowMargin() {
1033         return rowMargin;
1034     }
1035 
1036     /**
1037      * Sets the <code>rowMargin</code> and the <code>columnMargin</code> --
1038      * the height and width of the space between cells -- to
1039      * <code>intercellSpacing</code>.
1040      *
1041      * @param   intercellSpacing        a <code>Dimension</code>
1042      *                                  specifying the new width
1043      *                                  and height between cells
1044      * @see     #getIntercellSpacing
1045      */
1046     @BeanProperty(bound = false, description
1047             = "The spacing between the cells, drawn in the background color of the JTable.")
setIntercellSpacing(Dimension intercellSpacing)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      */
getIntercellSpacing()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      */
1075     @BeanProperty(description
1076             = "The grid color.")
setGridColor(Color gridColor)1077     public void setGridColor(Color gridColor) {
1078         if (gridColor == null) {
1079             throw new IllegalArgumentException("New color is null");
1080         }
1081         Color old = this.gridColor;
1082         this.gridColor = gridColor;
1083         firePropertyChange("gridColor", old, gridColor);
1084         // Redraw
1085         repaint();
1086     }
1087 
1088     /**
1089      * Returns the color used to draw grid lines.
1090      * The default color is look and feel dependent.
1091      *
1092      * @return  the color used to draw grid lines
1093      * @see     #setGridColor
1094      */
getGridColor()1095     public Color getGridColor() {
1096         return gridColor;
1097     }
1098 
1099     /**
1100      *  Sets whether the table draws grid lines around cells.
1101      *  If <code>showGrid</code> is true it does; if it is false it doesn't.
1102      *  There is no <code>getShowGrid</code> method as this state is held
1103      *  in two variables -- <code>showHorizontalLines</code> and <code>showVerticalLines</code> --
1104      *  each of which can be queried independently.
1105      *
1106      * @param   showGrid                 true if table view should draw grid lines
1107      *
1108      * @see     #setShowVerticalLines
1109      * @see     #setShowHorizontalLines
1110      */
1111     @BeanProperty(description
1112             = "The color used to draw the grid lines.")
setShowGrid(boolean showGrid)1113     public void setShowGrid(boolean showGrid) {
1114         setShowHorizontalLines(showGrid);
1115         setShowVerticalLines(showGrid);
1116 
1117         // Redraw
1118         repaint();
1119     }
1120 
1121     /**
1122      *  Sets whether the table draws horizontal lines between cells.
1123      *  If <code>showHorizontalLines</code> is true it does; if it is false it doesn't.
1124      *
1125      * @param   showHorizontalLines      true if table view should draw horizontal lines
1126      * @see     #getShowHorizontalLines
1127      * @see     #setShowGrid
1128      * @see     #setShowVerticalLines
1129      */
1130     @BeanProperty(description
1131             = "Whether horizontal lines should be drawn in between the cells.")
setShowHorizontalLines(boolean showHorizontalLines)1132     public void setShowHorizontalLines(boolean showHorizontalLines) {
1133         boolean old = this.showHorizontalLines;
1134         this.showHorizontalLines = showHorizontalLines;
1135         firePropertyChange("showHorizontalLines", old, showHorizontalLines);
1136 
1137         // Redraw
1138         repaint();
1139     }
1140 
1141     /**
1142      *  Sets whether the table draws vertical lines between cells.
1143      *  If <code>showVerticalLines</code> is true it does; if it is false it doesn't.
1144      *
1145      * @param   showVerticalLines              true if table view should draw vertical lines
1146      * @see     #getShowVerticalLines
1147      * @see     #setShowGrid
1148      * @see     #setShowHorizontalLines
1149      */
1150     @BeanProperty(description
1151             = "Whether vertical lines should be drawn in between the cells.")
setShowVerticalLines(boolean showVerticalLines)1152     public void setShowVerticalLines(boolean showVerticalLines) {
1153         boolean old = this.showVerticalLines;
1154         this.showVerticalLines = showVerticalLines;
1155         firePropertyChange("showVerticalLines", old, showVerticalLines);
1156         // Redraw
1157         repaint();
1158     }
1159 
1160     /**
1161      * Returns true if the table draws horizontal lines between cells, false if it
1162      * doesn't. The default value is look and feel dependent.
1163      *
1164      * @return  true if the table draws horizontal lines between cells, false if it
1165      *          doesn't
1166      * @see     #setShowHorizontalLines
1167      */
getShowHorizontalLines()1168     public boolean getShowHorizontalLines() {
1169         return showHorizontalLines;
1170     }
1171 
1172     /**
1173      * Returns true if the table draws vertical lines between cells, false if it
1174      * doesn't. The default value is look and feel dependent.
1175      *
1176      * @return  true if the table draws vertical lines between cells, false if it
1177      *          doesn't
1178      * @see     #setShowVerticalLines
1179      */
getShowVerticalLines()1180     public boolean getShowVerticalLines() {
1181         return showVerticalLines;
1182     }
1183 
1184     /**
1185      * Sets the table's auto resize mode when the table is resized.  For further
1186      * information on how the different resize modes work, see
1187      * {@link #doLayout}.
1188      *
1189      * @param   mode One of 5 legal values:
1190      *                   AUTO_RESIZE_OFF,
1191      *                   AUTO_RESIZE_NEXT_COLUMN,
1192      *                   AUTO_RESIZE_SUBSEQUENT_COLUMNS,
1193      *                   AUTO_RESIZE_LAST_COLUMN,
1194      *                   AUTO_RESIZE_ALL_COLUMNS
1195      *
1196      * @see     #getAutoResizeMode
1197      * @see     #doLayout
1198      */
1199     @BeanProperty(enumerationValues = {
1200             "JTable.AUTO_RESIZE_OFF",
1201             "JTable.AUTO_RESIZE_NEXT_COLUMN",
1202             "JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS",
1203             "JTable.AUTO_RESIZE_LAST_COLUMN",
1204             "JTable.AUTO_RESIZE_ALL_COLUMNS"}, description
1205             = "Whether the columns should adjust themselves automatically.")
setAutoResizeMode(int mode)1206     public void setAutoResizeMode(int mode) {
1207         if (isValidAutoResizeMode(mode)) {
1208             int old = autoResizeMode;
1209             autoResizeMode = mode;
1210             resizeAndRepaint();
1211             if (tableHeader != null) {
1212                 tableHeader.resizeAndRepaint();
1213             }
1214             firePropertyChange("autoResizeMode", old, autoResizeMode);
1215         }
1216     }
1217 
isValidAutoResizeMode(int mode)1218     private static boolean isValidAutoResizeMode(int mode) {
1219         return (mode == AUTO_RESIZE_OFF)
1220                 || (mode == AUTO_RESIZE_NEXT_COLUMN)
1221                 || (mode == AUTO_RESIZE_SUBSEQUENT_COLUMNS)
1222                 || (mode == AUTO_RESIZE_LAST_COLUMN)
1223                 || (mode == AUTO_RESIZE_ALL_COLUMNS);
1224     }
1225 
1226     /**
1227      * Returns the auto resize mode of the table.  The default mode
1228      * is AUTO_RESIZE_SUBSEQUENT_COLUMNS.
1229      *
1230      * @return  the autoResizeMode of the table
1231      *
1232      * @see     #setAutoResizeMode
1233      * @see     #doLayout
1234      */
getAutoResizeMode()1235     public int getAutoResizeMode() {
1236         return autoResizeMode;
1237     }
1238 
1239     /**
1240      * Sets this table's <code>autoCreateColumnsFromModel</code> flag.
1241      * This method calls <code>createDefaultColumnsFromModel</code> if
1242      * <code>autoCreateColumnsFromModel</code> changes from false to true.
1243      *
1244      * @param   autoCreateColumnsFromModel   true if <code>JTable</code> should automatically create columns
1245      * @see     #getAutoCreateColumnsFromModel
1246      * @see     #createDefaultColumnsFromModel
1247      */
1248     @BeanProperty(description
1249             = "Automatically populates the columnModel when a new TableModel is submitted.")
setAutoCreateColumnsFromModel(boolean autoCreateColumnsFromModel)1250     public void setAutoCreateColumnsFromModel(boolean autoCreateColumnsFromModel) {
1251         if (this.autoCreateColumnsFromModel != autoCreateColumnsFromModel) {
1252             boolean old = this.autoCreateColumnsFromModel;
1253             this.autoCreateColumnsFromModel = autoCreateColumnsFromModel;
1254             if (autoCreateColumnsFromModel) {
1255                 createDefaultColumnsFromModel();
1256             }
1257             firePropertyChange("autoCreateColumnsFromModel", old, autoCreateColumnsFromModel);
1258         }
1259     }
1260 
1261     /**
1262      * Determines whether the table will create default columns from the model.
1263      * If true, <code>setModel</code> will clear any existing columns and
1264      * create new columns from the new model.  Also, if the event in
1265      * the <code>tableChanged</code> notification specifies that the
1266      * entire table changed, then the columns will be rebuilt.
1267      * The default is true.
1268      *
1269      * @return  the autoCreateColumnsFromModel of the table
1270      * @see     #setAutoCreateColumnsFromModel
1271      * @see     #createDefaultColumnsFromModel
1272      */
getAutoCreateColumnsFromModel()1273     public boolean getAutoCreateColumnsFromModel() {
1274         return autoCreateColumnsFromModel;
1275     }
1276 
1277     /**
1278      * Creates default columns for the table from
1279      * the data model using the <code>getColumnCount</code> method
1280      * defined in the <code>TableModel</code> interface.
1281      * <p>
1282      * Clears any existing columns before creating the
1283      * new columns based on information from the model.
1284      *
1285      * @see     #getAutoCreateColumnsFromModel
1286      */
createDefaultColumnsFromModel()1287     public void createDefaultColumnsFromModel() {
1288         TableModel m = getModel();
1289         if (m != null) {
1290             // Remove any current columns
1291             TableColumnModel cm = getColumnModel();
1292             while (cm.getColumnCount() > 0) {
1293                 cm.removeColumn(cm.getColumn(0));
1294             }
1295 
1296             // Create new columns from the data model info
1297             for (int i = 0; i < m.getColumnCount(); i++) {
1298                 TableColumn newColumn = new TableColumn(i);
1299                 addColumn(newColumn);
1300             }
1301         }
1302     }
1303 
1304     /**
1305      * Sets a default cell renderer to be used if no renderer has been set in
1306      * a <code>TableColumn</code>. If renderer is <code>null</code>,
1307      * removes the default renderer for this column class.
1308      *
1309      * @param  columnClass     set the default cell renderer for this columnClass
1310      * @param  renderer        default cell renderer to be used for this
1311      *                         columnClass
1312      * @see     #getDefaultRenderer
1313      * @see     #setDefaultEditor
1314      */
setDefaultRenderer(Class<?> columnClass, TableCellRenderer renderer)1315     public void setDefaultRenderer(Class<?> columnClass, TableCellRenderer renderer) {
1316         if (renderer != null) {
1317             defaultRenderersByColumnClass.put(columnClass, renderer);
1318         }
1319         else {
1320             defaultRenderersByColumnClass.remove(columnClass);
1321         }
1322     }
1323 
1324     /**
1325      * Returns the cell renderer to be used when no renderer has been set in
1326      * a <code>TableColumn</code>. During the rendering of cells the renderer is fetched from
1327      * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
1328      * there is no entry for this <code>columnClass</code> the method returns
1329      * the entry for the most specific superclass. The <code>JTable</code> installs entries
1330      * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
1331      * or replaced.
1332      *
1333      * @param   columnClass   return the default cell renderer
1334      *                        for this columnClass
1335      * @return  the renderer for this columnClass
1336      * @see     #setDefaultRenderer
1337      * @see     #getColumnClass
1338      */
getDefaultRenderer(Class<?> columnClass)1339     public TableCellRenderer getDefaultRenderer(Class<?> columnClass) {
1340         if (columnClass == null) {
1341             return null;
1342         }
1343         else {
1344             Object renderer = defaultRenderersByColumnClass.get(columnClass);
1345             if (renderer != null) {
1346                 return (TableCellRenderer)renderer;
1347             }
1348             else {
1349                 Class<?> c = columnClass.getSuperclass();
1350                 if (c == null && columnClass != Object.class) {
1351                     c = Object.class;
1352                 }
1353                 return getDefaultRenderer(c);
1354             }
1355         }
1356     }
1357 
1358     /**
1359      * Sets a default cell editor to be used if no editor has been set in
1360      * a <code>TableColumn</code>. If no editing is required in a table, or a
1361      * particular column in a table, uses the <code>isCellEditable</code>
1362      * method in the <code>TableModel</code> interface to ensure that this
1363      * <code>JTable</code> will not start an editor in these columns.
1364      * If editor is <code>null</code>, removes the default editor for this
1365      * column class.
1366      *
1367      * @param  columnClass  set the default cell editor for this columnClass
1368      * @param  editor   default cell editor to be used for this columnClass
1369      * @see     TableModel#isCellEditable
1370      * @see     #getDefaultEditor
1371      * @see     #setDefaultRenderer
1372      */
setDefaultEditor(Class<?> columnClass, TableCellEditor editor)1373     public void setDefaultEditor(Class<?> columnClass, TableCellEditor editor) {
1374         if (editor != null) {
1375             defaultEditorsByColumnClass.put(columnClass, editor);
1376         }
1377         else {
1378             defaultEditorsByColumnClass.remove(columnClass);
1379         }
1380     }
1381 
1382     /**
1383      * Returns the editor to be used when no editor has been set in
1384      * a <code>TableColumn</code>. During the editing of cells the editor is fetched from
1385      * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
1386      * there is no entry for this <code>columnClass</code> the method returns
1387      * the entry for the most specific superclass. The <code>JTable</code> installs entries
1388      * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
1389      * or replaced.
1390      *
1391      * @param   columnClass  return the default cell editor for this columnClass
1392      * @return the default cell editor to be used for this columnClass
1393      * @see     #setDefaultEditor
1394      * @see     #getColumnClass
1395      */
getDefaultEditor(Class<?> columnClass)1396     public TableCellEditor getDefaultEditor(Class<?> columnClass) {
1397         if (columnClass == null) {
1398             return null;
1399         }
1400         else {
1401             Object editor = defaultEditorsByColumnClass.get(columnClass);
1402             if (editor != null) {
1403                 return (TableCellEditor)editor;
1404             }
1405             else {
1406                 return getDefaultEditor(columnClass.getSuperclass());
1407             }
1408         }
1409     }
1410 
1411     /**
1412      * Turns on or off automatic drag handling. In order to enable automatic
1413      * drag handling, this property should be set to {@code true}, and the
1414      * table's {@code TransferHandler} needs to be {@code non-null}.
1415      * The default value of the {@code dragEnabled} property is {@code false}.
1416      * <p>
1417      * The job of honoring this property, and recognizing a user drag gesture,
1418      * lies with the look and feel implementation, and in particular, the table's
1419      * {@code TableUI}. When automatic drag handling is enabled, most look and
1420      * feels (including those that subclass {@code BasicLookAndFeel}) begin a
1421      * drag and drop operation whenever the user presses the mouse button over
1422      * an item (in single selection mode) or a selection (in other selection
1423      * modes) and then moves the mouse a few pixels. Setting this property to
1424      * {@code true} can therefore have a subtle effect on how selections behave.
1425      * <p>
1426      * If a look and feel is used that ignores this property, you can still
1427      * begin a drag and drop operation by calling {@code exportAsDrag} on the
1428      * table's {@code TransferHandler}.
1429      *
1430      * @param b whether or not to enable automatic drag handling
1431      * @exception HeadlessException if
1432      *            <code>b</code> is <code>true</code> and
1433      *            <code>GraphicsEnvironment.isHeadless()</code>
1434      *            returns <code>true</code>
1435      * @see java.awt.GraphicsEnvironment#isHeadless
1436      * @see #getDragEnabled
1437      * @see #setTransferHandler
1438      * @see TransferHandler
1439      * @since 1.4
1440      */
1441     @BeanProperty(bound = false, description
1442             = "determines whether automatic drag handling is enabled")
setDragEnabled(boolean b)1443     public void setDragEnabled(boolean b) {
1444         checkDragEnabled(b);
1445         dragEnabled = b;
1446     }
1447 
checkDragEnabled(boolean b)1448     private void checkDragEnabled(boolean b) {
1449         if (b && GraphicsEnvironment.isHeadless()) {
1450             throw new HeadlessException();
1451         }
1452     }
1453 
1454     /**
1455      * Returns whether or not automatic drag handling is enabled.
1456      *
1457      * @return the value of the {@code dragEnabled} property
1458      * @see #setDragEnabled
1459      * @since 1.4
1460      */
getDragEnabled()1461     public boolean getDragEnabled() {
1462         return dragEnabled;
1463     }
1464 
1465     /**
1466      * Sets the drop mode for this component. For backward compatibility,
1467      * the default for this property is <code>DropMode.USE_SELECTION</code>.
1468      * Usage of one of the other modes is recommended, however, for an
1469      * improved user experience. <code>DropMode.ON</code>, for instance,
1470      * offers similar behavior of showing items as selected, but does so without
1471      * affecting the actual selection in the table.
1472      * <p>
1473      * <code>JTable</code> supports the following drop modes:
1474      * <ul>
1475      *    <li><code>DropMode.USE_SELECTION</code></li>
1476      *    <li><code>DropMode.ON</code></li>
1477      *    <li><code>DropMode.INSERT</code></li>
1478      *    <li><code>DropMode.INSERT_ROWS</code></li>
1479      *    <li><code>DropMode.INSERT_COLS</code></li>
1480      *    <li><code>DropMode.ON_OR_INSERT</code></li>
1481      *    <li><code>DropMode.ON_OR_INSERT_ROWS</code></li>
1482      *    <li><code>DropMode.ON_OR_INSERT_COLS</code></li>
1483      * </ul>
1484      * <p>
1485      * The drop mode is only meaningful if this component has a
1486      * <code>TransferHandler</code> that accepts drops.
1487      *
1488      * @param dropMode the drop mode to use
1489      * @throws IllegalArgumentException if the drop mode is unsupported
1490      *         or <code>null</code>
1491      * @see #getDropMode
1492      * @see #getDropLocation
1493      * @see #setTransferHandler
1494      * @see TransferHandler
1495      * @since 1.6
1496      */
setDropMode(DropMode dropMode)1497     public final void setDropMode(DropMode dropMode) {
1498         checkDropMode(dropMode);
1499         this.dropMode = dropMode;
1500     }
1501 
checkDropMode(DropMode dropMode)1502     private static void checkDropMode(DropMode dropMode) {
1503         if (dropMode != null) {
1504             switch (dropMode) {
1505                 case USE_SELECTION:
1506                 case ON:
1507                 case INSERT:
1508                 case INSERT_ROWS:
1509                 case INSERT_COLS:
1510                 case ON_OR_INSERT:
1511                 case ON_OR_INSERT_ROWS:
1512                 case ON_OR_INSERT_COLS:
1513                     return;
1514             }
1515         }
1516         throw new IllegalArgumentException(dropMode
1517                 + ": Unsupported drop mode for table");
1518     }
1519     /**
1520      * Returns the drop mode for this component.
1521      *
1522      * @return the drop mode for this component
1523      * @see #setDropMode
1524      * @since 1.6
1525      */
getDropMode()1526     public final DropMode getDropMode() {
1527         return dropMode;
1528     }
1529 
1530     /**
1531      * Calculates a drop location in this component, representing where a
1532      * drop at the given point should insert data.
1533      *
1534      * @param p the point to calculate a drop location for
1535      * @return the drop location, or <code>null</code>
1536      */
dropLocationForPoint(Point p)1537     DropLocation dropLocationForPoint(Point p) {
1538         DropLocation location = null;
1539 
1540         int row = rowAtPoint(p);
1541         int col = columnAtPoint(p);
1542         boolean outside = Boolean.TRUE == getClientProperty("Table.isFileList")
1543                           && SwingUtilities2.pointOutsidePrefSize(this, row, col, p);
1544 
1545         Rectangle rect = getCellRect(row, col, true);
1546         Section xSection, ySection;
1547         boolean between = false;
1548         boolean ltr = getComponentOrientation().isLeftToRight();
1549 
1550         switch(dropMode) {
1551             case USE_SELECTION:
1552             case ON:
1553                 if (row == -1 || col == -1 || outside) {
1554                     location = new DropLocation(p, -1, -1, false, false);
1555                 } else {
1556                     location = new DropLocation(p, row, col, false, false);
1557                 }
1558                 break;
1559             case INSERT:
1560                 if (row == -1 && col == -1) {
1561                     location = new DropLocation(p, 0, 0, true, true);
1562                     break;
1563                 }
1564 
1565                 xSection = SwingUtilities2.liesInHorizontal(rect, p, ltr, true);
1566 
1567                 if (row == -1) {
1568                     if (xSection == LEADING) {
1569                         location = new DropLocation(p, getRowCount(), col, true, true);
1570                     } else if (xSection == TRAILING) {
1571                         location = new DropLocation(p, getRowCount(), col + 1, true, true);
1572                     } else {
1573                         location = new DropLocation(p, getRowCount(), col, true, false);
1574                     }
1575                 } else if (xSection == LEADING || xSection == TRAILING) {
1576                     ySection = SwingUtilities2.liesInVertical(rect, p, true);
1577                     if (ySection == LEADING) {
1578                         between = true;
1579                     } else if (ySection == TRAILING) {
1580                         row++;
1581                         between = true;
1582                     }
1583 
1584                     location = new DropLocation(p, row,
1585                                                 xSection == TRAILING ? col + 1 : col,
1586                                                 between, true);
1587                 } else {
1588                     if (SwingUtilities2.liesInVertical(rect, p, false) == TRAILING) {
1589                         row++;
1590                     }
1591 
1592                     location = new DropLocation(p, row, col, true, false);
1593                 }
1594 
1595                 break;
1596             case INSERT_ROWS:
1597                 if (row == -1 && col == -1) {
1598                     location = new DropLocation(p, -1, -1, false, false);
1599                     break;
1600                 }
1601 
1602                 if (row == -1) {
1603                     location = new DropLocation(p, getRowCount(), col, true, false);
1604                     break;
1605                 }
1606 
1607                 if (SwingUtilities2.liesInVertical(rect, p, false) == TRAILING) {
1608                     row++;
1609                 }
1610 
1611                 location = new DropLocation(p, row, col, true, false);
1612                 break;
1613             case ON_OR_INSERT_ROWS:
1614                 if (row == -1 && col == -1) {
1615                     location = new DropLocation(p, -1, -1, false, false);
1616                     break;
1617                 }
1618 
1619                 if (row == -1) {
1620                     location = new DropLocation(p, getRowCount(), col, true, false);
1621                     break;
1622                 }
1623 
1624                 ySection = SwingUtilities2.liesInVertical(rect, p, true);
1625                 if (ySection == LEADING) {
1626                     between = true;
1627                 } else if (ySection == TRAILING) {
1628                     row++;
1629                     between = true;
1630                 }
1631 
1632                 location = new DropLocation(p, row, col, between, false);
1633                 break;
1634             case INSERT_COLS:
1635                 if (row == -1) {
1636                     location = new DropLocation(p, -1, -1, false, false);
1637                     break;
1638                 }
1639 
1640                 if (col == -1) {
1641                     location = new DropLocation(p, getColumnCount(), col, false, true);
1642                     break;
1643                 }
1644 
1645                 if (SwingUtilities2.liesInHorizontal(rect, p, ltr, false) == TRAILING) {
1646                     col++;
1647                 }
1648 
1649                 location = new DropLocation(p, row, col, false, true);
1650                 break;
1651             case ON_OR_INSERT_COLS:
1652                 if (row == -1) {
1653                     location = new DropLocation(p, -1, -1, false, false);
1654                     break;
1655                 }
1656 
1657                 if (col == -1) {
1658                     location = new DropLocation(p, row, getColumnCount(), false, true);
1659                     break;
1660                 }
1661 
1662                 xSection = SwingUtilities2.liesInHorizontal(rect, p, ltr, true);
1663                 if (xSection == LEADING) {
1664                     between = true;
1665                 } else if (xSection == TRAILING) {
1666                     col++;
1667                     between = true;
1668                 }
1669 
1670                 location = new DropLocation(p, row, col, false, between);
1671                 break;
1672             case ON_OR_INSERT:
1673                 if (row == -1 && col == -1) {
1674                     location = new DropLocation(p, 0, 0, true, true);
1675                     break;
1676                 }
1677 
1678                 xSection = SwingUtilities2.liesInHorizontal(rect, p, ltr, true);
1679 
1680                 if (row == -1) {
1681                     if (xSection == LEADING) {
1682                         location = new DropLocation(p, getRowCount(), col, true, true);
1683                     } else if (xSection == TRAILING) {
1684                         location = new DropLocation(p, getRowCount(), col + 1, true, true);
1685                     } else {
1686                         location = new DropLocation(p, getRowCount(), col, true, false);
1687                     }
1688 
1689                     break;
1690                 }
1691 
1692                 ySection = SwingUtilities2.liesInVertical(rect, p, true);
1693                 if (ySection == LEADING) {
1694                     between = true;
1695                 } else if (ySection == TRAILING) {
1696                     row++;
1697                     between = true;
1698                 }
1699 
1700                 location = new DropLocation(p, row,
1701                                             xSection == TRAILING ? col + 1 : col,
1702                                             between,
1703                                             xSection != MIDDLE);
1704 
1705                 break;
1706             default:
1707                 assert false : "Unexpected drop mode";
1708         }
1709 
1710         return location;
1711     }
1712 
1713     /**
1714      * Called to set or clear the drop location during a DnD operation.
1715      * In some cases, the component may need to use it's internal selection
1716      * temporarily to indicate the drop location. To help facilitate this,
1717      * this method returns and accepts as a parameter a state object.
1718      * This state object can be used to store, and later restore, the selection
1719      * state. Whatever this method returns will be passed back to it in
1720      * future calls, as the state parameter. If it wants the DnD system to
1721      * continue storing the same state, it must pass it back every time.
1722      * Here's how this is used:
1723      * <p>
1724      * Let's say that on the first call to this method the component decides
1725      * to save some state (because it is about to use the selection to show
1726      * a drop index). It can return a state object to the caller encapsulating
1727      * any saved selection state. On a second call, let's say the drop location
1728      * is being changed to something else. The component doesn't need to
1729      * restore anything yet, so it simply passes back the same state object
1730      * to have the DnD system continue storing it. Finally, let's say this
1731      * method is messaged with <code>null</code>. This means DnD
1732      * is finished with this component for now, meaning it should restore
1733      * state. At this point, it can use the state parameter to restore
1734      * said state, and of course return <code>null</code> since there's
1735      * no longer anything to store.
1736      *
1737      * @param location the drop location (as calculated by
1738      *        <code>dropLocationForPoint</code>) or <code>null</code>
1739      *        if there's no longer a valid drop location
1740      * @param state the state object saved earlier for this component,
1741      *        or <code>null</code>
1742      * @param forDrop whether or not the method is being called because an
1743      *        actual drop occurred
1744      * @return any saved state for this component, or <code>null</code> if none
1745      */
setDropLocation(TransferHandler.DropLocation location, Object state, boolean forDrop)1746     Object setDropLocation(TransferHandler.DropLocation location,
1747                            Object state,
1748                            boolean forDrop) {
1749 
1750         Object retVal = null;
1751         DropLocation tableLocation = (DropLocation)location;
1752 
1753         if (dropMode == DropMode.USE_SELECTION) {
1754             if (tableLocation == null) {
1755                 if (!forDrop && state != null) {
1756                     clearSelection();
1757 
1758                     int[] rows = ((int[][])state)[0];
1759                     int[] cols = ((int[][])state)[1];
1760                     int[] anchleads = ((int[][])state)[2];
1761 
1762                     for (int row : rows) {
1763                         addRowSelectionInterval(row, row);
1764                     }
1765 
1766                     for (int col : cols) {
1767                         addColumnSelectionInterval(col, col);
1768                     }
1769 
1770                     SwingUtilities2.setLeadAnchorWithoutSelection(
1771                             getSelectionModel(), anchleads[1], anchleads[0]);
1772 
1773                     SwingUtilities2.setLeadAnchorWithoutSelection(
1774                             getColumnModel().getSelectionModel(),
1775                             anchleads[3], anchleads[2]);
1776                 }
1777             } else {
1778                 if (dropLocation == null) {
1779                     retVal = new int[][]{
1780                         getSelectedRows(),
1781                         getSelectedColumns(),
1782                         {getAdjustedIndex(getSelectionModel()
1783                              .getAnchorSelectionIndex(), true),
1784                          getAdjustedIndex(getSelectionModel()
1785                              .getLeadSelectionIndex(), true),
1786                          getAdjustedIndex(getColumnModel().getSelectionModel()
1787                              .getAnchorSelectionIndex(), false),
1788                          getAdjustedIndex(getColumnModel().getSelectionModel()
1789                              .getLeadSelectionIndex(), false)}};
1790                 } else {
1791                     retVal = state;
1792                 }
1793 
1794                 if (tableLocation.getRow() == -1) {
1795                     clearSelectionAndLeadAnchor();
1796                 } else {
1797                     setRowSelectionInterval(tableLocation.getRow(),
1798                                             tableLocation.getRow());
1799                     setColumnSelectionInterval(tableLocation.getColumn(),
1800                                                tableLocation.getColumn());
1801                 }
1802             }
1803         }
1804 
1805         DropLocation old = dropLocation;
1806         dropLocation = tableLocation;
1807         firePropertyChange("dropLocation", old, dropLocation);
1808 
1809         return retVal;
1810     }
1811 
1812     /**
1813      * Returns the location that this component should visually indicate
1814      * as the drop location during a DnD operation over the component,
1815      * or {@code null} if no location is to currently be shown.
1816      * <p>
1817      * This method is not meant for querying the drop location
1818      * from a {@code TransferHandler}, as the drop location is only
1819      * set after the {@code TransferHandler}'s <code>canImport</code>
1820      * has returned and has allowed for the location to be shown.
1821      * <p>
1822      * When this property changes, a property change event with
1823      * name "dropLocation" is fired by the component.
1824      *
1825      * @return the drop location
1826      * @see #setDropMode
1827      * @see TransferHandler#canImport(TransferHandler.TransferSupport)
1828      * @since 1.6
1829      */
1830     @BeanProperty(bound = false)
getDropLocation()1831     public final DropLocation getDropLocation() {
1832         return dropLocation;
1833     }
1834 
1835     /**
1836      * Specifies whether a {@code RowSorter} should be created for the
1837      * table whenever its model changes.
1838      * <p>
1839      * When {@code setAutoCreateRowSorter(true)} is invoked, a {@code
1840      * TableRowSorter} is immediately created and installed on the
1841      * table.  While the {@code autoCreateRowSorter} property remains
1842      * {@code true}, every time the model is changed, a new {@code
1843      * TableRowSorter} is created and set as the table's row sorter.
1844      * The default value for the {@code autoCreateRowSorter}
1845      * property is {@code false}.
1846      *
1847      * @param autoCreateRowSorter whether or not a {@code RowSorter}
1848      *        should be automatically created
1849      * @see javax.swing.table.TableRowSorter
1850      * @since 1.6
1851      */
1852     @BeanProperty(preferred = true, description
1853             = "Whether or not to turn on sorting by default.")
setAutoCreateRowSorter(boolean autoCreateRowSorter)1854     public void setAutoCreateRowSorter(boolean autoCreateRowSorter) {
1855         boolean oldValue = this.autoCreateRowSorter;
1856         this.autoCreateRowSorter = autoCreateRowSorter;
1857         if (autoCreateRowSorter) {
1858             setRowSorter(new TableRowSorter<TableModel>(getModel()));
1859         }
1860         firePropertyChange("autoCreateRowSorter", oldValue,
1861                            autoCreateRowSorter);
1862     }
1863 
1864     /**
1865      * Returns {@code true} if whenever the model changes, a new
1866      * {@code RowSorter} should be created and installed
1867      * as the table's sorter; otherwise, returns {@code false}.
1868      *
1869      * @return true if a {@code RowSorter} should be created when
1870      *         the model changes
1871      * @since 1.6
1872      */
getAutoCreateRowSorter()1873     public boolean getAutoCreateRowSorter() {
1874         return autoCreateRowSorter;
1875     }
1876 
1877     /**
1878      * Specifies whether the selection should be updated after sorting.
1879      * If true, on sorting the selection is reset such that
1880      * the same rows, in terms of the model, remain selected.  The default
1881      * is true.
1882      *
1883      * @param update whether or not to update the selection on sorting
1884      * @since 1.6
1885      */
1886     @BeanProperty(expert = true, description
1887             = "Whether or not to update the selection on sorting")
setUpdateSelectionOnSort(boolean update)1888     public void setUpdateSelectionOnSort(boolean update) {
1889         if (updateSelectionOnSort != update) {
1890             updateSelectionOnSort = update;
1891             firePropertyChange("updateSelectionOnSort", !update, update);
1892         }
1893     }
1894 
1895     /**
1896      * Returns true if the selection should be updated after sorting.
1897      *
1898      * @return whether to update the selection on a sort
1899      * @since 1.6
1900      */
getUpdateSelectionOnSort()1901     public boolean getUpdateSelectionOnSort() {
1902         return updateSelectionOnSort;
1903     }
1904 
1905     /**
1906      * Sets the <code>RowSorter</code>.  <code>RowSorter</code> is used
1907      * to provide sorting and filtering to a <code>JTable</code>.
1908      * <p>
1909      * This method clears the selection and resets any variable row heights.
1910      * <p>
1911      * This method fires a <code>PropertyChangeEvent</code> when appropriate,
1912      * with the property name <code>"rowSorter"</code>.  For
1913      * backward-compatibility, this method fires an additional event with the
1914      * property name <code>"sorter"</code>.
1915      * <p>
1916      * If the underlying model of the <code>RowSorter</code> differs from
1917      * that of this <code>JTable</code> undefined behavior will result.
1918      *
1919      * @param sorter the <code>RowSorter</code>; <code>null</code> turns
1920      *        sorting off
1921      * @see javax.swing.table.TableRowSorter
1922      * @since 1.6
1923      */
1924     @BeanProperty(description
1925             = "The table's RowSorter")
setRowSorter(RowSorter<? extends TableModel> sorter)1926     public void setRowSorter(RowSorter<? extends TableModel> sorter) {
1927         RowSorter<? extends TableModel> oldRowSorter = null;
1928         if (sortManager != null) {
1929             oldRowSorter = sortManager.sorter;
1930             sortManager.dispose();
1931             sortManager = null;
1932         }
1933         rowModel = null;
1934         clearSelectionAndLeadAnchor();
1935         if (sorter != null) {
1936             sortManager = new SortManager(sorter);
1937         }
1938         resizeAndRepaint();
1939         firePropertyChange("rowSorter", oldRowSorter, sorter);
1940         firePropertyChange("sorter", oldRowSorter, sorter);
1941     }
1942 
1943     /**
1944      * Returns the object responsible for sorting.
1945      *
1946      * @return the object responsible for sorting
1947      * @since 1.6
1948      */
getRowSorter()1949     public RowSorter<? extends TableModel> getRowSorter() {
1950         return (sortManager != null) ? sortManager.sorter : null;
1951     }
1952 
1953 //
1954 // Selection methods
1955 //
1956     /**
1957      * Sets the table's selection mode to allow only single selections, a single
1958      * contiguous interval, or multiple intervals.
1959      * <P>
1960      * <b>Note:</b>
1961      * <code>JTable</code> provides all the methods for handling
1962      * column and row selection.  When setting states,
1963      * such as <code>setSelectionMode</code>, it not only
1964      * updates the mode for the row selection model but also sets similar
1965      * values in the selection model of the <code>columnModel</code>.
1966      * If you want to have the row and column selection models operating
1967      * in different modes, set them both directly.
1968      * <p>
1969      * Both the row and column selection models for <code>JTable</code>
1970      * default to using a <code>DefaultListSelectionModel</code>
1971      * so that <code>JTable</code> works the same way as the
1972      * <code>JList</code>. See the <code>setSelectionMode</code> method
1973      * in <code>JList</code> for details about the modes.
1974      *
1975      * @param selectionMode the mode used by the row and column selection models
1976      * @see JList#setSelectionMode
1977      */
1978     @BeanProperty(enumerationValues = {
1979             "ListSelectionModel.SINGLE_SELECTION",
1980             "ListSelectionModel.SINGLE_INTERVAL_SELECTION",
1981             "ListSelectionModel.MULTIPLE_INTERVAL_SELECTION"}, description
1982             = "The selection mode used by the row and column selection models.")
setSelectionMode(int selectionMode)1983     public void setSelectionMode(int selectionMode) {
1984         clearSelection();
1985         getSelectionModel().setSelectionMode(selectionMode);
1986         getColumnModel().getSelectionModel().setSelectionMode(selectionMode);
1987     }
1988 
1989     /**
1990      * Sets whether the rows in this model can be selected.
1991      *
1992      * @param rowSelectionAllowed   true if this model will allow row selection
1993      * @see #getRowSelectionAllowed
1994      */
1995     @BeanProperty(visualUpdate = true, description
1996             = "If true, an entire row is selected for each selected cell.")
setRowSelectionAllowed(boolean rowSelectionAllowed)1997     public void setRowSelectionAllowed(boolean rowSelectionAllowed) {
1998         boolean old = this.rowSelectionAllowed;
1999         this.rowSelectionAllowed = rowSelectionAllowed;
2000         if (old != rowSelectionAllowed) {
2001             repaint();
2002         }
2003         firePropertyChange("rowSelectionAllowed", old, rowSelectionAllowed);
2004     }
2005 
2006     /**
2007      * Returns true if rows can be selected.
2008      *
2009      * @return true if rows can be selected, otherwise false
2010      * @see #setRowSelectionAllowed
2011      */
getRowSelectionAllowed()2012     public boolean getRowSelectionAllowed() {
2013         return rowSelectionAllowed;
2014     }
2015 
2016     /**
2017      * Sets whether the columns in this model can be selected.
2018      *
2019      * @param columnSelectionAllowed   true if this model will allow column selection
2020      * @see #getColumnSelectionAllowed
2021      */
2022     @BeanProperty(visualUpdate = true, description
2023             = "If true, an entire column is selected for each selected cell.")
setColumnSelectionAllowed(boolean columnSelectionAllowed)2024     public void setColumnSelectionAllowed(boolean columnSelectionAllowed) {
2025         boolean old = columnModel.getColumnSelectionAllowed();
2026         columnModel.setColumnSelectionAllowed(columnSelectionAllowed);
2027         if (old != columnSelectionAllowed) {
2028             repaint();
2029         }
2030         firePropertyChange("columnSelectionAllowed", old, columnSelectionAllowed);
2031     }
2032 
2033     /**
2034      * Returns true if columns can be selected.
2035      *
2036      * @return true if columns can be selected, otherwise false
2037      * @see #setColumnSelectionAllowed
2038      */
getColumnSelectionAllowed()2039     public boolean getColumnSelectionAllowed() {
2040         return columnModel.getColumnSelectionAllowed();
2041     }
2042 
2043     /**
2044      * Sets whether this table allows both a column selection and a
2045      * row selection to exist simultaneously. When set,
2046      * the table treats the intersection of the row and column selection
2047      * models as the selected cells. Override <code>isCellSelected</code> to
2048      * change this default behavior. This method is equivalent to setting
2049      * both the <code>rowSelectionAllowed</code> property and
2050      * <code>columnSelectionAllowed</code> property of the
2051      * <code>columnModel</code> to the supplied value.
2052      *
2053      * @param  cellSelectionEnabled     true if simultaneous row and column
2054      *                                  selection is allowed
2055      * @see #getCellSelectionEnabled
2056      * @see #isCellSelected
2057      */
2058     @BeanProperty(visualUpdate = true, description
2059             = "Select a rectangular region of cells rather than rows or columns.")
setCellSelectionEnabled(boolean cellSelectionEnabled)2060     public void setCellSelectionEnabled(boolean cellSelectionEnabled) {
2061         setRowSelectionAllowed(cellSelectionEnabled);
2062         setColumnSelectionAllowed(cellSelectionEnabled);
2063         boolean old = this.cellSelectionEnabled;
2064         this.cellSelectionEnabled = cellSelectionEnabled;
2065         firePropertyChange("cellSelectionEnabled", old, cellSelectionEnabled);
2066     }
2067 
2068     /**
2069      * Returns true if both row and column selection models are enabled.
2070      * Equivalent to <code>getRowSelectionAllowed() &amp;&amp;
2071      * getColumnSelectionAllowed()</code>.
2072      *
2073      * @return true if both row and column selection models are enabled
2074      *
2075      * @see #setCellSelectionEnabled
2076      */
getCellSelectionEnabled()2077     public boolean getCellSelectionEnabled() {
2078         return getRowSelectionAllowed() && getColumnSelectionAllowed();
2079     }
2080 
2081     /**
2082      *  Selects all rows, columns, and cells in the table.
2083      */
selectAll()2084     public void selectAll() {
2085         // If I'm currently editing, then I should stop editing
2086         if (isEditing()) {
2087             removeEditor();
2088         }
2089         if (getRowCount() > 0 && getColumnCount() > 0) {
2090             int oldLead;
2091             int oldAnchor;
2092             ListSelectionModel selModel;
2093 
2094             selModel = selectionModel;
2095             selModel.setValueIsAdjusting(true);
2096             oldLead = getAdjustedIndex(selModel.getLeadSelectionIndex(), true);
2097             oldAnchor = getAdjustedIndex(selModel.getAnchorSelectionIndex(), true);
2098 
2099             setRowSelectionInterval(0, getRowCount()-1);
2100 
2101             // this is done to restore the anchor and lead
2102             SwingUtilities2.setLeadAnchorWithoutSelection(selModel, oldLead, oldAnchor);
2103 
2104             selModel.setValueIsAdjusting(false);
2105 
2106             selModel = columnModel.getSelectionModel();
2107             selModel.setValueIsAdjusting(true);
2108             oldLead = getAdjustedIndex(selModel.getLeadSelectionIndex(), false);
2109             oldAnchor = getAdjustedIndex(selModel.getAnchorSelectionIndex(), false);
2110 
2111             setColumnSelectionInterval(0, getColumnCount()-1);
2112 
2113             // this is done to restore the anchor and lead
2114             SwingUtilities2.setLeadAnchorWithoutSelection(selModel, oldLead, oldAnchor);
2115 
2116             selModel.setValueIsAdjusting(false);
2117         }
2118     }
2119 
2120     /**
2121      * Deselects all selected columns and rows.
2122      */
clearSelection()2123     public void clearSelection() {
2124         selectionModel.clearSelection();
2125         columnModel.getSelectionModel().clearSelection();
2126     }
2127 
clearSelectionAndLeadAnchor()2128     private void clearSelectionAndLeadAnchor() {
2129         selectionModel.setValueIsAdjusting(true);
2130         columnModel.getSelectionModel().setValueIsAdjusting(true);
2131 
2132         clearSelection();
2133 
2134         selectionModel.setAnchorSelectionIndex(-1);
2135         selectionModel.setLeadSelectionIndex(-1);
2136         columnModel.getSelectionModel().setAnchorSelectionIndex(-1);
2137         columnModel.getSelectionModel().setLeadSelectionIndex(-1);
2138 
2139         selectionModel.setValueIsAdjusting(false);
2140         columnModel.getSelectionModel().setValueIsAdjusting(false);
2141     }
2142 
getAdjustedIndex(int index, boolean row)2143     private int getAdjustedIndex(int index, boolean row) {
2144         int compare = row ? getRowCount() : getColumnCount();
2145         return index < compare ? index : -1;
2146     }
2147 
boundRow(int row)2148     private int boundRow(int row) throws IllegalArgumentException {
2149         if (row < 0 || row >= getRowCount()) {
2150             throw new IllegalArgumentException("Row index out of range");
2151         }
2152         return row;
2153     }
2154 
boundColumn(int col)2155     private int boundColumn(int col) {
2156         if (col< 0 || col >= getColumnCount()) {
2157             throw new IllegalArgumentException("Column index out of range");
2158         }
2159         return col;
2160     }
2161 
2162     /**
2163      * Selects the rows from <code>index0</code> to <code>index1</code>,
2164      * inclusive.
2165      *
2166      * @exception IllegalArgumentException      if <code>index0</code> or
2167      *                                          <code>index1</code> lie outside
2168      *                                          [0, <code>getRowCount()</code>-1]
2169      * @param   index0 one end of the interval
2170      * @param   index1 the other end of the interval
2171      */
setRowSelectionInterval(int index0, int index1)2172     public void setRowSelectionInterval(int index0, int index1) {
2173         selectionModel.setSelectionInterval(boundRow(index0), boundRow(index1));
2174     }
2175 
2176     /**
2177      * Selects the columns from <code>index0</code> to <code>index1</code>,
2178      * inclusive.
2179      *
2180      * @exception IllegalArgumentException      if <code>index0</code> or
2181      *                                          <code>index1</code> lie outside
2182      *                                          [0, <code>getColumnCount()</code>-1]
2183      * @param   index0 one end of the interval
2184      * @param   index1 the other end of the interval
2185      */
setColumnSelectionInterval(int index0, int index1)2186     public void setColumnSelectionInterval(int index0, int index1) {
2187         columnModel.getSelectionModel().setSelectionInterval(boundColumn(index0), boundColumn(index1));
2188     }
2189 
2190     /**
2191      * Adds the rows from <code>index0</code> to <code>index1</code>, inclusive, to
2192      * the current selection.
2193      *
2194      * @exception IllegalArgumentException      if <code>index0</code> or <code>index1</code>
2195      *                                          lie outside [0, <code>getRowCount()</code>-1]
2196      * @param   index0 one end of the interval
2197      * @param   index1 the other end of the interval
2198      */
addRowSelectionInterval(int index0, int index1)2199     public void addRowSelectionInterval(int index0, int index1) {
2200         selectionModel.addSelectionInterval(boundRow(index0), boundRow(index1));
2201     }
2202 
2203     /**
2204      * Adds the columns from <code>index0</code> to <code>index1</code>,
2205      * inclusive, to the current selection.
2206      *
2207      * @exception IllegalArgumentException      if <code>index0</code> or
2208      *                                          <code>index1</code> lie outside
2209      *                                          [0, <code>getColumnCount()</code>-1]
2210      * @param   index0 one end of the interval
2211      * @param   index1 the other end of the interval
2212      */
addColumnSelectionInterval(int index0, int index1)2213     public void addColumnSelectionInterval(int index0, int index1) {
2214         columnModel.getSelectionModel().addSelectionInterval(boundColumn(index0), boundColumn(index1));
2215     }
2216 
2217     /**
2218      * Deselects the rows from <code>index0</code> to <code>index1</code>, inclusive.
2219      *
2220      * @exception IllegalArgumentException      if <code>index0</code> or
2221      *                                          <code>index1</code> lie outside
2222      *                                          [0, <code>getRowCount()</code>-1]
2223      * @param   index0 one end of the interval
2224      * @param   index1 the other end of the interval
2225      */
removeRowSelectionInterval(int index0, int index1)2226     public void removeRowSelectionInterval(int index0, int index1) {
2227         selectionModel.removeSelectionInterval(boundRow(index0), boundRow(index1));
2228     }
2229 
2230     /**
2231      * Deselects the columns from <code>index0</code> to <code>index1</code>, inclusive.
2232      *
2233      * @exception IllegalArgumentException      if <code>index0</code> or
2234      *                                          <code>index1</code> lie outside
2235      *                                          [0, <code>getColumnCount()</code>-1]
2236      * @param   index0 one end of the interval
2237      * @param   index1 the other end of the interval
2238      */
removeColumnSelectionInterval(int index0, int index1)2239     public void removeColumnSelectionInterval(int index0, int index1) {
2240         columnModel.getSelectionModel().removeSelectionInterval(boundColumn(index0), boundColumn(index1));
2241     }
2242 
2243     /**
2244      * Returns the index of the first selected row, -1 if no row is selected.
2245      * @return the index of the first selected row
2246      */
2247     @BeanProperty(bound = false)
getSelectedRow()2248     public int getSelectedRow() {
2249         return selectionModel.getMinSelectionIndex();
2250     }
2251 
2252     /**
2253      * Returns the index of the first selected column,
2254      * -1 if no column is selected.
2255      * @return the index of the first selected column
2256      */
2257     @BeanProperty(bound = false)
getSelectedColumn()2258     public int getSelectedColumn() {
2259         return columnModel.getSelectionModel().getMinSelectionIndex();
2260     }
2261 
2262     /**
2263      * Returns the indices of all selected rows.
2264      *
2265      * @return an array of integers containing the indices of all selected rows,
2266      *         or an empty array if no row is selected
2267      * @see #getSelectedRow
2268      */
2269     @BeanProperty(bound = false)
getSelectedRows()2270     public int[] getSelectedRows() {
2271         return selectionModel.getSelectedIndices();
2272     }
2273 
2274     /**
2275      * Returns the indices of all selected columns.
2276      *
2277      * @return an array of integers containing the indices of all selected columns,
2278      *         or an empty array if no column is selected
2279      * @see #getSelectedColumn
2280      */
2281     @BeanProperty(bound = false)
getSelectedColumns()2282     public int[] getSelectedColumns() {
2283         return columnModel.getSelectedColumns();
2284     }
2285 
2286     /**
2287      * Returns the number of selected rows.
2288      *
2289      * @return the number of selected rows, 0 if no rows are selected
2290      */
2291     @BeanProperty(bound = false)
getSelectedRowCount()2292     public int getSelectedRowCount() {
2293         return selectionModel.getSelectedItemsCount();
2294     }
2295 
2296     /**
2297      * Returns the number of selected columns.
2298      *
2299      * @return the number of selected columns, 0 if no columns are selected
2300      */
2301     @BeanProperty(bound = false)
getSelectedColumnCount()2302     public int getSelectedColumnCount() {
2303         return columnModel.getSelectedColumnCount();
2304     }
2305 
2306     /**
2307      * Returns true if the specified index is in the valid range of rows,
2308      * and the row at that index is selected.
2309      *
2310      * @param row a row in the row model
2311      * @return true if <code>row</code> is a valid index and the row at
2312      *              that index is selected (where 0 is the first row)
2313      */
isRowSelected(int row)2314     public boolean isRowSelected(int row) {
2315         return selectionModel.isSelectedIndex(row);
2316     }
2317 
2318     /**
2319      * Returns true if the specified index is in the valid range of columns,
2320      * and the column at that index is selected.
2321      *
2322      * @param   column   the column in the column model
2323      * @return true if <code>column</code> is a valid index and the column at
2324      *              that index is selected (where 0 is the first column)
2325      */
isColumnSelected(int column)2326     public boolean isColumnSelected(int column) {
2327         return columnModel.getSelectionModel().isSelectedIndex(column);
2328     }
2329 
2330     /**
2331      * Returns true if the specified indices are in the valid range of rows
2332      * and columns and the cell at the specified position is selected.
2333      * @param row   the row being queried
2334      * @param column  the column being queried
2335      *
2336      * @return true if <code>row</code> and <code>column</code> are valid indices
2337      *              and the cell at index <code>(row, column)</code> is selected,
2338      *              where the first row and first column are at index 0
2339      */
isCellSelected(int row, int column)2340     public boolean isCellSelected(int row, int column) {
2341         if (!getRowSelectionAllowed() && !getColumnSelectionAllowed()) {
2342             return false;
2343         }
2344         return (!getRowSelectionAllowed() || isRowSelected(row)) &&
2345                (!getColumnSelectionAllowed() || isColumnSelected(column));
2346     }
2347 
changeSelectionModel(ListSelectionModel sm, int index, boolean toggle, boolean extend, boolean selected, int anchor, boolean anchorSelected)2348     private void changeSelectionModel(ListSelectionModel sm, int index,
2349                                       boolean toggle, boolean extend, boolean selected,
2350                                       int anchor, boolean anchorSelected) {
2351         if (extend) {
2352             if (toggle) {
2353                 if (anchorSelected) {
2354                     sm.addSelectionInterval(anchor, index);
2355                 } else {
2356                     sm.removeSelectionInterval(anchor, index);
2357                     // this is a Windows-only behavior that we want for file lists
2358                     if (Boolean.TRUE == getClientProperty("Table.isFileList")) {
2359                         sm.addSelectionInterval(index, index);
2360                         sm.setAnchorSelectionIndex(anchor);
2361                     }
2362                 }
2363             }
2364             else {
2365                 sm.setSelectionInterval(anchor, index);
2366             }
2367         }
2368         else {
2369             if (toggle) {
2370                 if (selected) {
2371                     sm.removeSelectionInterval(index, index);
2372                 }
2373                 else {
2374                     sm.addSelectionInterval(index, index);
2375                 }
2376             }
2377             else {
2378                 sm.setSelectionInterval(index, index);
2379             }
2380         }
2381     }
2382 
2383     /**
2384      * Updates the selection models of the table, depending on the state of the
2385      * two flags: <code>toggle</code> and <code>extend</code>. Most changes
2386      * to the selection that are the result of keyboard or mouse events received
2387      * by the UI are channeled through this method so that the behavior may be
2388      * overridden by a subclass. Some UIs may need more functionality than
2389      * this method provides, such as when manipulating the lead for discontiguous
2390      * selection, and may not call into this method for some selection changes.
2391      * <p>
2392      * This implementation uses the following conventions:
2393      * <ul>
2394      * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>false</em>.
2395      *      Clear the previous selection and ensure the new cell is selected.
2396      * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>true</em>.
2397      *      Extend the previous selection from the anchor to the specified cell,
2398      *      clearing all other selections.
2399      * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>false</em>.
2400      *      If the specified cell is selected, deselect it. If it is not selected, select it.
2401      * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>true</em>.
2402      *      Apply the selection state of the anchor to all cells between it and the
2403      *      specified cell.
2404      * </ul>
2405      * @param  rowIndex   affects the selection at <code>row</code>
2406      * @param  columnIndex  affects the selection at <code>column</code>
2407      * @param  toggle  see description above
2408      * @param  extend  if true, extend the current selection
2409      *
2410      * @since 1.3
2411      */
changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend)2412     public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
2413         ListSelectionModel rsm = getSelectionModel();
2414         ListSelectionModel csm = getColumnModel().getSelectionModel();
2415 
2416         int anchorRow = getAdjustedIndex(rsm.getAnchorSelectionIndex(), true);
2417         int anchorCol = getAdjustedIndex(csm.getAnchorSelectionIndex(), false);
2418 
2419         boolean anchorSelected = true;
2420 
2421         if (anchorRow == -1) {
2422             if (getRowCount() > 0) {
2423                 anchorRow = 0;
2424             }
2425             anchorSelected = false;
2426         }
2427 
2428         if (anchorCol == -1) {
2429             if (getColumnCount() > 0) {
2430                 anchorCol = 0;
2431             }
2432             anchorSelected = false;
2433         }
2434 
2435         // Check the selection here rather than in each selection model.
2436         // This is significant in cell selection mode if we are supposed
2437         // to be toggling the selection. In this case it is better to
2438         // ensure that the cell's selection state will indeed be changed.
2439         // If this were done in the code for the selection model it
2440         // might leave a cell in selection state if the row was
2441         // selected but the column was not - as it would toggle them both.
2442         boolean selected = isCellSelected(rowIndex, columnIndex);
2443         anchorSelected = anchorSelected && isCellSelected(anchorRow, anchorCol);
2444 
2445         changeSelectionModel(csm, columnIndex, toggle, extend, selected,
2446                              anchorCol, anchorSelected);
2447         changeSelectionModel(rsm, rowIndex, toggle, extend, selected,
2448                              anchorRow, anchorSelected);
2449 
2450         // Scroll after changing the selection as blit scrolling is immediate,
2451         // so that if we cause the repaint after the scroll we end up painting
2452         // everything!
2453         if (getAutoscrolls()) {
2454             Rectangle cellRect = getCellRect(rowIndex, columnIndex, false);
2455             if (cellRect != null) {
2456                 scrollRectToVisible(cellRect);
2457             }
2458         }
2459     }
2460 
2461     /**
2462      * Returns the foreground color for selected cells.
2463      *
2464      * @return the <code>Color</code> object for the foreground property
2465      * @see #setSelectionForeground
2466      * @see #setSelectionBackground
2467      */
getSelectionForeground()2468     public Color getSelectionForeground() {
2469         return selectionForeground;
2470     }
2471 
2472     /**
2473      * Sets the foreground color for selected cells.  Cell renderers
2474      * can use this color to render text and graphics for selected
2475      * cells.
2476      * <p>
2477      * The default value of this property is defined by the look
2478      * and feel implementation.
2479      * <p>
2480      * This is a <a href="https://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html">JavaBeans</a> bound property.
2481      *
2482      * @param selectionForeground  the <code>Color</code> to use in the foreground
2483      *                             for selected list items
2484      * @see #getSelectionForeground
2485      * @see #setSelectionBackground
2486      * @see #setForeground
2487      * @see #setBackground
2488      * @see #setFont
2489      */
2490     @BeanProperty(description
2491             = "A default foreground color for selected cells.")
setSelectionForeground(Color selectionForeground)2492     public void setSelectionForeground(Color selectionForeground) {
2493         Color old = this.selectionForeground;
2494         this.selectionForeground = selectionForeground;
2495         firePropertyChange("selectionForeground", old, selectionForeground);
2496         repaint();
2497     }
2498 
2499     /**
2500      * Returns the background color for selected cells.
2501      *
2502      * @return the <code>Color</code> used for the background of selected list items
2503      * @see #setSelectionBackground
2504      * @see #setSelectionForeground
2505      */
getSelectionBackground()2506     public Color getSelectionBackground() {
2507         return selectionBackground;
2508     }
2509 
2510     /**
2511      * Sets the background color for selected cells.  Cell renderers
2512      * can use this color to the fill selected 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="https://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html">JavaBeans</a> bound property.
2518      *
2519      * @param selectionBackground  the <code>Color</code> to use for the background
2520      *                             of selected cells
2521      * @see #getSelectionBackground
2522      * @see #setSelectionForeground
2523      * @see #setForeground
2524      * @see #setBackground
2525      * @see #setFont
2526      */
2527     @BeanProperty(description
2528             = "A default background color for selected cells.")
setSelectionBackground(Color selectionBackground)2529     public void setSelectionBackground(Color selectionBackground) {
2530         Color old = this.selectionBackground;
2531         this.selectionBackground = selectionBackground;
2532         firePropertyChange("selectionBackground", old, selectionBackground);
2533         repaint();
2534     }
2535 
2536     /**
2537      * Returns the <code>TableColumn</code> object for the column in the table
2538      * whose identifier is equal to <code>identifier</code>, when compared using
2539      * <code>equals</code>.
2540      *
2541      * @return  the <code>TableColumn</code> object that matches the identifier
2542      * @exception IllegalArgumentException      if <code>identifier</code> is <code>null</code> or no <code>TableColumn</code> has this identifier
2543      *
2544      * @param   identifier                      the identifier object
2545      */
getColumn(Object identifier)2546     public TableColumn getColumn(Object identifier) {
2547         TableColumnModel cm = getColumnModel();
2548         int columnIndex = cm.getColumnIndex(identifier);
2549         return cm.getColumn(columnIndex);
2550     }
2551 
2552 //
2553 // Informally implement the TableModel interface.
2554 //
2555 
2556     /**
2557      * Maps the index of the column in the view at
2558      * <code>viewColumnIndex</code> to the index of the column
2559      * in the table model.  Returns the index of the corresponding
2560      * column in the model.  If <code>viewColumnIndex</code>
2561      * is less than zero, returns <code>viewColumnIndex</code>.
2562      *
2563      * @param   viewColumnIndex     the index of the column in the view
2564      * @return  the index of the corresponding column in the model
2565      *
2566      * @see #convertColumnIndexToView
2567      */
convertColumnIndexToModel(int viewColumnIndex)2568     public int convertColumnIndexToModel(int viewColumnIndex) {
2569         return SwingUtilities2.convertColumnIndexToModel(
2570                 getColumnModel(), viewColumnIndex);
2571     }
2572 
2573     /**
2574      * Maps the index of the column in the table model at
2575      * <code>modelColumnIndex</code> to the index of the column
2576      * in the view.  Returns the index of the
2577      * corresponding column in the view; returns -1 if this column is not
2578      * being displayed.  If <code>modelColumnIndex</code> is less than zero,
2579      * returns <code>modelColumnIndex</code>.
2580      *
2581      * @param   modelColumnIndex     the index of the column in the model
2582      * @return   the index of the corresponding column in the view
2583      *
2584      * @see #convertColumnIndexToModel
2585      */
convertColumnIndexToView(int modelColumnIndex)2586     public int convertColumnIndexToView(int modelColumnIndex) {
2587         return SwingUtilities2.convertColumnIndexToView(
2588                 getColumnModel(), modelColumnIndex);
2589     }
2590 
2591     /**
2592      * Maps the index of the row in terms of the
2593      * <code>TableModel</code> to the view.  If the contents of the
2594      * model are not sorted the model and view indices are the same.
2595      *
2596      * @param modelRowIndex the index of the row in terms of the model
2597      * @return the index of the corresponding row in the view, or -1 if
2598      *         the row isn't visible
2599      * @throws IndexOutOfBoundsException if sorting is enabled and passed an
2600      *         index outside the number of rows of the <code>TableModel</code>
2601      * @see javax.swing.table.TableRowSorter
2602      * @since 1.6
2603      */
convertRowIndexToView(int modelRowIndex)2604     public int convertRowIndexToView(int modelRowIndex) {
2605         RowSorter<?> sorter = getRowSorter();
2606         if (sorter != null) {
2607             return sorter.convertRowIndexToView(modelRowIndex);
2608         }
2609         return modelRowIndex;
2610     }
2611 
2612     /**
2613      * Maps the index of the row in terms of the view to the
2614      * underlying <code>TableModel</code>.  If the contents of the
2615      * model are not sorted the model and view indices are the same.
2616      *
2617      * @param viewRowIndex the index of the row in the view
2618      * @return the index of the corresponding row in the model
2619      * @throws IndexOutOfBoundsException if sorting is enabled and passed an
2620      *         index outside the range of the <code>JTable</code> as
2621      *         determined by the method <code>getRowCount</code>
2622      * @see javax.swing.table.TableRowSorter
2623      * @see #getRowCount
2624      * @since 1.6
2625      */
convertRowIndexToModel(int viewRowIndex)2626     public int convertRowIndexToModel(int viewRowIndex) {
2627         RowSorter<?> sorter = getRowSorter();
2628         if (sorter != null) {
2629             return sorter.convertRowIndexToModel(viewRowIndex);
2630         }
2631         return viewRowIndex;
2632     }
2633 
2634     /**
2635      * Returns the number of rows that can be shown in the
2636      * <code>JTable</code>, given unlimited space.  If a
2637      * <code>RowSorter</code> with a filter has been specified, the
2638      * number of rows returned may differ from that of the underlying
2639      * <code>TableModel</code>.
2640      *
2641      * @return the number of rows shown in the <code>JTable</code>
2642      * @see #getColumnCount
2643      */
2644     @BeanProperty(bound = false)
getRowCount()2645     public int getRowCount() {
2646         RowSorter<?> sorter = getRowSorter();
2647         if (sorter != null) {
2648             return sorter.getViewRowCount();
2649         }
2650         return getModel().getRowCount();
2651     }
2652 
2653     /**
2654      * Returns the number of columns in the column model. Note that this may
2655      * be different from the number of columns in the table model.
2656      *
2657      * @return  the number of columns in the table
2658      * @see #getRowCount
2659      * @see #removeColumn
2660      */
2661     @BeanProperty(bound = false)
getColumnCount()2662     public int getColumnCount() {
2663         return getColumnModel().getColumnCount();
2664     }
2665 
2666     /**
2667      * Returns the name of the column appearing in the view at
2668      * column position <code>column</code>.
2669      *
2670      * @param  column    the column in the view being queried
2671      * @return the name of the column at position <code>column</code>
2672                         in the view where the first column is column 0
2673      */
getColumnName(int column)2674     public String getColumnName(int column) {
2675         return getModel().getColumnName(convertColumnIndexToModel(column));
2676     }
2677 
2678     /**
2679      * Returns the type of the column appearing in the view at
2680      * column position <code>column</code>.
2681      *
2682      * @param   column   the column in the view being queried
2683      * @return the type of the column at position <code>column</code>
2684      *          in the view where the first column is column 0
2685      */
getColumnClass(int column)2686     public Class<?> getColumnClass(int column) {
2687         return getModel().getColumnClass(convertColumnIndexToModel(column));
2688     }
2689 
2690     /**
2691      * Returns the cell value at <code>row</code> and <code>column</code>.
2692      * <p>
2693      * <b>Note</b>: The column is specified in the table view's display
2694      *              order, and not in the <code>TableModel</code>'s column
2695      *              order.  This is an important distinction because as the
2696      *              user rearranges the columns in the table,
2697      *              the column at a given index in the view will change.
2698      *              Meanwhile the user's actions never affect the model's
2699      *              column ordering.
2700      *
2701      * @param   row             the row whose value is to be queried
2702      * @param   column          the column whose value is to be queried
2703      * @return  the Object at the specified cell
2704      */
getValueAt(int row, int column)2705     public Object getValueAt(int row, int column) {
2706         return getModel().getValueAt(convertRowIndexToModel(row),
2707                                      convertColumnIndexToModel(column));
2708     }
2709 
2710     /**
2711      * Sets the value for the cell in the table model at <code>row</code>
2712      * and <code>column</code>.
2713      * <p>
2714      * <b>Note</b>: The column is specified in the table view's display
2715      *              order, and not in the <code>TableModel</code>'s column
2716      *              order.  This is an important distinction because as the
2717      *              user rearranges the columns in the table,
2718      *              the column at a given index in the view will change.
2719      *              Meanwhile the user's actions never affect the model's
2720      *              column ordering.
2721      *
2722      * <code>aValue</code> is the new value.
2723      *
2724      * @param   aValue          the new value
2725      * @param   row             the row of the cell to be changed
2726      * @param   column          the column of the cell to be changed
2727      * @see #getValueAt
2728      */
setValueAt(Object aValue, int row, int column)2729     public void setValueAt(Object aValue, int row, int column) {
2730         getModel().setValueAt(aValue, convertRowIndexToModel(row),
2731                               convertColumnIndexToModel(column));
2732     }
2733 
2734     /**
2735      * Returns true if the cell at <code>row</code> and <code>column</code>
2736      * is editable.  Otherwise, invoking <code>setValueAt</code> on the cell
2737      * will have no effect.
2738      * <p>
2739      * <b>Note</b>: The column is specified in the table view's display
2740      *              order, and not in the <code>TableModel</code>'s column
2741      *              order.  This is an important distinction because as the
2742      *              user rearranges the columns in the table,
2743      *              the column at a given index in the view will change.
2744      *              Meanwhile the user's actions never affect the model's
2745      *              column ordering.
2746      *
2747      *
2748      * @param   row      the row whose value is to be queried
2749      * @param   column   the column whose value is to be queried
2750      * @return  true if the cell is editable
2751      * @see #setValueAt
2752      */
isCellEditable(int row, int column)2753     public boolean isCellEditable(int row, int column) {
2754         return getModel().isCellEditable(convertRowIndexToModel(row),
2755                                          convertColumnIndexToModel(column));
2756     }
2757 //
2758 // Adding and removing columns in the view
2759 //
2760 
2761     /**
2762      *  Appends <code>aColumn</code> to the end of the array of columns held by
2763      *  this <code>JTable</code>'s column model.
2764      *  If the column name of <code>aColumn</code> is <code>null</code>,
2765      *  sets the column name of <code>aColumn</code> to the name
2766      *  returned by <code>getModel().getColumnName()</code>.
2767      *  <p>
2768      *  To add a column to this <code>JTable</code> to display the
2769      *  <code>modelColumn</code>'th column of data in the model with a
2770      *  given <code>width</code>, <code>cellRenderer</code>,
2771      *  and <code>cellEditor</code> you can use:
2772      *  <pre>
2773      *
2774      *      addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
2775      *
2776      *  </pre>
2777      *  [Any of the <code>TableColumn</code> constructors can be used
2778      *  instead of this one.]
2779      *  The model column number is stored inside the <code>TableColumn</code>
2780      *  and is used during rendering and editing to locate the appropriates
2781      *  data values in the model. The model column number does not change
2782      *  when columns are reordered in the view.
2783      *
2784      *  @param  aColumn         the <code>TableColumn</code> to be added
2785      *  @see    #removeColumn
2786      */
addColumn(TableColumn aColumn)2787     public void addColumn(TableColumn aColumn) {
2788         if (aColumn.getHeaderValue() == null) {
2789             int modelColumn = aColumn.getModelIndex();
2790             String columnName = getModel().getColumnName(modelColumn);
2791             aColumn.setHeaderValue(columnName);
2792         }
2793         getColumnModel().addColumn(aColumn);
2794     }
2795 
2796     /**
2797      *  Removes <code>aColumn</code> from this <code>JTable</code>'s
2798      *  array of columns.  Note: this method does not remove the column
2799      *  of data from the model; it just removes the <code>TableColumn</code>
2800      *  that was responsible for displaying it.
2801      *
2802      *  @param  aColumn         the <code>TableColumn</code> to be removed
2803      *  @see    #addColumn
2804      */
removeColumn(TableColumn aColumn)2805     public void removeColumn(TableColumn aColumn) {
2806         getColumnModel().removeColumn(aColumn);
2807     }
2808 
2809     /**
2810      * Moves the column <code>column</code> to the position currently
2811      * occupied by the column <code>targetColumn</code> in the view.
2812      * The old column at <code>targetColumn</code> is
2813      * shifted left or right to make room.
2814      *
2815      * @param   column                  the index of column to be moved
2816      * @param   targetColumn            the new index of the column
2817      */
moveColumn(int column, int targetColumn)2818     public void moveColumn(int column, int targetColumn) {
2819         getColumnModel().moveColumn(column, targetColumn);
2820     }
2821 
2822 //
2823 // Cover methods for various models and helper methods
2824 //
2825 
2826     /**
2827      * Returns the index of the column that <code>point</code> lies in,
2828      * or -1 if the result is not in the range
2829      * [0, <code>getColumnCount()</code>-1].
2830      *
2831      * @param   point   the location of interest
2832      * @return  the index of the column that <code>point</code> lies in,
2833      *          or -1 if the result is not in the range
2834      *          [0, <code>getColumnCount()</code>-1]
2835      * @see     #rowAtPoint
2836      */
columnAtPoint(Point point)2837     public int columnAtPoint(Point point) {
2838         int x = point.x;
2839         if( !getComponentOrientation().isLeftToRight() ) {
2840             x = getWidth() - x - 1;
2841         }
2842         return getColumnModel().getColumnIndexAtX(x);
2843     }
2844 
2845     /**
2846      * Returns the index of the row that <code>point</code> lies in,
2847      * or -1 if the result is not in the range
2848      * [0, <code>getRowCount()</code>-1].
2849      *
2850      * @param   point   the location of interest
2851      * @return  the index of the row that <code>point</code> lies in,
2852      *          or -1 if the result is not in the range
2853      *          [0, <code>getRowCount()</code>-1]
2854      * @see     #columnAtPoint
2855      */
rowAtPoint(Point point)2856     public int rowAtPoint(Point point) {
2857         int y = point.y;
2858         int result = (rowModel == null) ?  y/getRowHeight() : rowModel.getIndex(y);
2859         if (result < 0) {
2860             return -1;
2861         }
2862         else if (result >= getRowCount()) {
2863             return -1;
2864         }
2865         else {
2866             return result;
2867         }
2868     }
2869 
2870     /**
2871      * Returns a rectangle for the cell that lies at the intersection of
2872      * <code>row</code> and <code>column</code>.
2873      * If <code>includeSpacing</code> is true then the value returned
2874      * has the full height and width of the row and column
2875      * specified. If it is false, the returned rectangle is inset by the
2876      * intercell spacing to return the true bounds of the rendering or
2877      * editing component as it will be set during rendering.
2878      * <p>
2879      * If the column index is valid but the row index is less
2880      * than zero the method returns a rectangle with the
2881      * <code>y</code> and <code>height</code> values set appropriately
2882      * and the <code>x</code> and <code>width</code> values both set
2883      * to zero. In general, when either the row or column indices indicate a
2884      * cell outside the appropriate range, the method returns a rectangle
2885      * depicting the closest edge of the closest cell that is within
2886      * the table's range. When both row and column indices are out
2887      * of range the returned rectangle covers the closest
2888      * point of the closest cell.
2889      * <p>
2890      * In all cases, calculations that use this method to calculate
2891      * results along one axis will not fail because of anomalies in
2892      * calculations along the other axis. When the cell is not valid
2893      * the <code>includeSpacing</code> parameter is ignored.
2894      *
2895      * @param   row                   the row index where the desired cell
2896      *                                is located
2897      * @param   column                the column index where the desired cell
2898      *                                is located in the display; this is not
2899      *                                necessarily the same as the column index
2900      *                                in the data model for the table; the
2901      *                                {@link #convertColumnIndexToView(int)}
2902      *                                method may be used to convert a data
2903      *                                model column index to a display
2904      *                                column index
2905      * @param   includeSpacing        if false, return the true cell bounds -
2906      *                                computed by subtracting the intercell
2907      *                                spacing from the height and widths of
2908      *                                the column and row models
2909      *
2910      * @return  the rectangle containing the cell at location
2911      *          <code>row</code>,<code>column</code>
2912      * @see #getIntercellSpacing
2913      */
getCellRect(int row, int column, boolean includeSpacing)2914     public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
2915         Rectangle r = new Rectangle();
2916         boolean valid = true;
2917         if (row < 0) {
2918             // y = height = 0;
2919             valid = false;
2920         }
2921         else if (row >= getRowCount()) {
2922             r.y = getHeight();
2923             valid = false;
2924         }
2925         else {
2926             r.height = getRowHeight(row);
2927             r.y = (rowModel == null) ? row * r.height : rowModel.getPosition(row);
2928         }
2929 
2930         if (column < 0) {
2931             if( !getComponentOrientation().isLeftToRight() ) {
2932                 r.x = getWidth();
2933             }
2934             // otherwise, x = width = 0;
2935             valid = false;
2936         }
2937         else if (column >= getColumnCount()) {
2938             if( getComponentOrientation().isLeftToRight() ) {
2939                 r.x = getWidth();
2940             }
2941             // otherwise, x = width = 0;
2942             valid = false;
2943         }
2944         else {
2945             TableColumnModel cm = getColumnModel();
2946             if( getComponentOrientation().isLeftToRight() ) {
2947                 for(int i = 0; i < column; i++) {
2948                     r.x += cm.getColumn(i).getWidth();
2949                 }
2950             } else {
2951                 for(int i = cm.getColumnCount()-1; i > column; i--) {
2952                     r.x += cm.getColumn(i).getWidth();
2953                 }
2954             }
2955             r.width = cm.getColumn(column).getWidth();
2956         }
2957 
2958         if (valid && !includeSpacing) {
2959             // Bound the margins by their associated dimensions to prevent
2960             // returning bounds with negative dimensions.
2961             int rm = Math.min(getRowMargin(), r.height);
2962             int cm = Math.min(getColumnModel().getColumnMargin(), r.width);
2963             // This is not the same as grow(), it rounds differently.
2964             r.setBounds(r.x + cm/2, r.y + rm/2, r.width - cm, r.height - rm);
2965         }
2966         return r;
2967     }
2968 
viewIndexForColumn(TableColumn aColumn)2969     private int viewIndexForColumn(TableColumn aColumn) {
2970         TableColumnModel cm = getColumnModel();
2971         for (int column = 0; column < cm.getColumnCount(); column++) {
2972             if (cm.getColumn(column) == aColumn) {
2973                 return column;
2974             }
2975         }
2976         return -1;
2977     }
2978 
2979     /**
2980      * Causes this table to lay out its rows and columns.  Overridden so
2981      * that columns can be resized to accommodate a change in the size of
2982      * a containing parent.
2983      * Resizes one or more of the columns in the table
2984      * so that the total width of all of this <code>JTable</code>'s
2985      * columns is equal to the width of the table.
2986      * <p>
2987      * Before the layout begins the method gets the
2988      * <code>resizingColumn</code> of the <code>tableHeader</code>.
2989      * When the method is called as a result of the resizing of an enclosing window,
2990      * the <code>resizingColumn</code> is <code>null</code>. This means that resizing
2991      * has taken place "outside" the <code>JTable</code> and the change -
2992      * or "delta" - should be distributed to all of the columns regardless
2993      * of this <code>JTable</code>'s automatic resize mode.
2994      * <p>
2995      * If the <code>resizingColumn</code> is not <code>null</code>, it is one of
2996      * the columns in the table that has changed size rather than
2997      * the table itself. In this case the auto-resize modes govern
2998      * the way the extra (or deficit) space is distributed
2999      * amongst the available columns.
3000      * <p>
3001      * The modes are:
3002      * <ul>
3003      * <li>  AUTO_RESIZE_OFF: Don't automatically adjust the column's
3004      * widths at all. Use a horizontal scrollbar to accommodate the
3005      * columns when their sum exceeds the width of the
3006      * <code>Viewport</code>.  If the <code>JTable</code> is not
3007      * enclosed in a <code>JScrollPane</code> this may
3008      * leave parts of the table invisible.
3009      * <li>  AUTO_RESIZE_NEXT_COLUMN: Use just the column after the
3010      * resizing column. This results in the "boundary" or divider
3011      * between adjacent cells being independently adjustable.
3012      * <li>  AUTO_RESIZE_SUBSEQUENT_COLUMNS: Use all columns after the
3013      * one being adjusted to absorb the changes.  This is the
3014      * default behavior.
3015      * <li>  AUTO_RESIZE_LAST_COLUMN: Automatically adjust the
3016      * size of the last column only. If the bounds of the last column
3017      * prevent the desired size from being allocated, set the
3018      * width of the last column to the appropriate limit and make
3019      * no further adjustments.
3020      * <li>  AUTO_RESIZE_ALL_COLUMNS: Spread the delta amongst all the columns
3021      * in the <code>JTable</code>, including the one that is being
3022      * adjusted.
3023      * </ul>
3024      * <p>
3025      * <b>Note:</b> When a <code>JTable</code> makes adjustments
3026      *   to the widths of the columns it respects their minimum and
3027      *   maximum values absolutely.  It is therefore possible that,
3028      *   even after this method is called, the total width of the columns
3029      *   is still not equal to the width of the table. When this happens
3030      *   the <code>JTable</code> does not put itself
3031      *   in AUTO_RESIZE_OFF mode to bring up a scroll bar, or break other
3032      *   commitments of its current auto-resize mode -- instead it
3033      *   allows its bounds to be set larger (or smaller) than the total of the
3034      *   column minimum or maximum, meaning, either that there
3035      *   will not be enough room to display all of the columns, or that the
3036      *   columns will not fill the <code>JTable</code>'s bounds.
3037      *   These respectively, result in the clipping of some columns
3038      *   or an area being painted in the <code>JTable</code>'s
3039      *   background color during painting.
3040      * <p>
3041      *   The mechanism for distributing the delta amongst the available
3042      *   columns is provided in a private method in the <code>JTable</code>
3043      *   class:
3044      * <pre>
3045      *   adjustSizes(long targetSize, final Resizable3 r, boolean inverse)
3046      * </pre>
3047      *   an explanation of which is provided in the following section.
3048      *   <code>Resizable3</code> is a private
3049      *   interface that allows any data structure containing a collection
3050      *   of elements with a size, preferred size, maximum size and minimum size
3051      *   to have its elements manipulated by the algorithm.
3052      *
3053      * <H4> Distributing the delta </H4>
3054      *
3055      * <H5> Overview </H5>
3056      * <P>
3057      * Call "DELTA" the difference between the target size and the
3058      * sum of the preferred sizes of the elements in r. The individual
3059      * sizes are calculated by taking the original preferred
3060      * sizes and adding a share of the DELTA - that share being based on
3061      * how far each preferred size is from its limiting bound (minimum or
3062      * maximum).
3063      *
3064      * <H5>Definition</H5>
3065      * <P>
3066      * Call the individual constraints min[i], max[i], and pref[i].
3067      * <p>
3068      * Call their respective sums: MIN, MAX, and PREF.
3069      * <p>
3070      * Each new size will be calculated using:
3071      *
3072      * <pre>
3073      *          size[i] = pref[i] + delta[i]
3074      * </pre>
3075      * where each individual delta[i] is calculated according to:
3076      * <p>
3077      * If (DELTA &lt; 0) we are in shrink mode where:
3078      *
3079      * <PRE>
3080      *                        DELTA
3081      *          delta[i] = ------------ * (pref[i] - min[i])
3082      *                     (PREF - MIN)
3083      * </PRE>
3084      * If (DELTA &gt; 0) we are in expand mode where:
3085      *
3086      * <PRE>
3087      *                        DELTA
3088      *          delta[i] = ------------ * (max[i] - pref[i])
3089      *                      (MAX - PREF)
3090      * </PRE>
3091      * <P>
3092      * The overall effect is that the total size moves that same percentage,
3093      * k, towards the total minimum or maximum and that percentage guarantees
3094      * accommodation of the required space, DELTA.
3095      *
3096      * <H5>Details</H5>
3097      * <P>
3098      * Naive evaluation of the formulae presented here would be subject to
3099      * the aggregated rounding errors caused by doing this operation in finite
3100      * precision (using ints). To deal with this, the multiplying factor above,
3101      * is constantly recalculated and this takes account of the rounding
3102      * errors in the previous iterations. The result is an algorithm that
3103      * produces a set of integers whose values exactly sum to the supplied
3104      * <code>targetSize</code>, and does so by spreading the rounding
3105      * errors evenly over the given elements.
3106      *
3107      * <H5>When the MAX and MIN bounds are hit</H5>
3108      * <P>
3109      * When <code>targetSize</code> is outside the [MIN, MAX] range,
3110      * the algorithm sets all sizes to their appropriate limiting value
3111      * (maximum or minimum).
3112      *
3113      */
doLayout()3114     public void doLayout() {
3115         TableColumn resizingColumn = getResizingColumn();
3116         if (resizingColumn == null) {
3117             setWidthsFromPreferredWidths(false);
3118         }
3119         else {
3120             // JTable behaves like a layout manger - but one in which the
3121             // user can come along and dictate how big one of the children
3122             // (columns) is supposed to be.
3123 
3124             // A column has been resized and JTable may need to distribute
3125             // any overall delta to other columns, according to the resize mode.
3126             int columnIndex = viewIndexForColumn(resizingColumn);
3127             int delta = getWidth() - getColumnModel().getTotalColumnWidth();
3128             accommodateDelta(columnIndex, delta);
3129             delta = getWidth() - getColumnModel().getTotalColumnWidth();
3130 
3131             // If the delta cannot be completely accomodated, then the
3132             // resizing column will have to take any remainder. This means
3133             // that the column is not being allowed to take the requested
3134             // width. This happens under many circumstances: For example,
3135             // AUTO_RESIZE_NEXT_COLUMN specifies that any delta be distributed
3136             // to the column after the resizing column. If one were to attempt
3137             // to resize the last column of the table, there would be no
3138             // columns after it, and hence nowhere to distribute the delta.
3139             // It would then be given entirely back to the resizing column,
3140             // preventing it from changing size.
3141             if (delta != 0) {
3142                 resizingColumn.setWidth(resizingColumn.getWidth() + delta);
3143             }
3144 
3145             // At this point the JTable has to work out what preferred sizes
3146             // would have resulted in the layout the user has chosen.
3147             // Thereafter, during window resizing etc. it has to work off
3148             // the preferred sizes as usual - the idea being that, whatever
3149             // the user does, everything stays in synch and things don't jump
3150             // around.
3151             setWidthsFromPreferredWidths(true);
3152         }
3153 
3154         super.doLayout();
3155     }
3156 
getResizingColumn()3157     private TableColumn getResizingColumn() {
3158         return (tableHeader == null) ? null
3159                                      : tableHeader.getResizingColumn();
3160     }
3161 
3162     /**
3163      * Sizes the table columns to fit the available space.
3164      *
3165      * @param lastColumnOnly determines whether to resize last column only
3166      * @deprecated As of Swing version 1.0.3,
3167      * replaced by <code>doLayout()</code>.
3168      * @see #doLayout
3169      */
3170     @Deprecated
sizeColumnsToFit(boolean lastColumnOnly)3171     public void sizeColumnsToFit(boolean lastColumnOnly) {
3172         int oldAutoResizeMode = autoResizeMode;
3173         setAutoResizeMode(lastColumnOnly ? AUTO_RESIZE_LAST_COLUMN
3174                                          : AUTO_RESIZE_ALL_COLUMNS);
3175         sizeColumnsToFit(-1);
3176         setAutoResizeMode(oldAutoResizeMode);
3177     }
3178 
3179     /**
3180      * Obsolete as of Java 2 platform v1.4.  Please use the
3181      * <code>doLayout()</code> method instead.
3182      * @param resizingColumn    the column whose resizing made this adjustment
3183      *                          necessary or -1 if there is no such column
3184      * @see  #doLayout
3185      */
sizeColumnsToFit(int resizingColumn)3186     public void sizeColumnsToFit(int resizingColumn) {
3187         if (resizingColumn == -1) {
3188             setWidthsFromPreferredWidths(false);
3189         }
3190         else {
3191             if (autoResizeMode == AUTO_RESIZE_OFF) {
3192                 TableColumn aColumn = getColumnModel().getColumn(resizingColumn);
3193                 aColumn.setPreferredWidth(aColumn.getWidth());
3194             }
3195             else {
3196                 int delta = getWidth() - getColumnModel().getTotalColumnWidth();
3197                 accommodateDelta(resizingColumn, delta);
3198                 setWidthsFromPreferredWidths(true);
3199             }
3200         }
3201     }
3202 
setWidthsFromPreferredWidths(final boolean inverse)3203     private void setWidthsFromPreferredWidths(final boolean inverse) {
3204         int totalWidth     = getWidth();
3205         int totalPreferred = getPreferredSize().width;
3206         int target = !inverse ? totalWidth : totalPreferred;
3207 
3208         final TableColumnModel cm = columnModel;
3209         Resizable3 r = new Resizable3() {
3210             public int  getElementCount()      { return cm.getColumnCount(); }
3211             public int  getLowerBoundAt(int i) { return cm.getColumn(i).getMinWidth(); }
3212             public int  getUpperBoundAt(int i) { return cm.getColumn(i).getMaxWidth(); }
3213             public int  getMidPointAt(int i)  {
3214                 if (!inverse) {
3215                     return cm.getColumn(i).getPreferredWidth();
3216                 }
3217                 else {
3218                     return cm.getColumn(i).getWidth();
3219                 }
3220             }
3221             public void setSizeAt(int s, int i) {
3222                 if (!inverse) {
3223                     cm.getColumn(i).setWidth(s);
3224                 }
3225                 else {
3226                     cm.getColumn(i).setPreferredWidth(s);
3227                 }
3228             }
3229         };
3230 
3231         adjustSizes(target, r, inverse);
3232     }
3233 
3234 
3235     // Distribute delta over columns, as indicated by the autoresize mode.
accommodateDelta(int resizingColumnIndex, int delta)3236     private void accommodateDelta(int resizingColumnIndex, int delta) {
3237         int columnCount = getColumnCount();
3238         int from = resizingColumnIndex;
3239         int to;
3240 
3241         // Use the mode to determine how to absorb the changes.
3242         switch(autoResizeMode) {
3243             case AUTO_RESIZE_NEXT_COLUMN:
3244                 from = from + 1;
3245                 to = Math.min(from + 1, columnCount); break;
3246             case AUTO_RESIZE_SUBSEQUENT_COLUMNS:
3247                 from = from + 1;
3248                 to = columnCount; break;
3249             case AUTO_RESIZE_LAST_COLUMN:
3250                 from = columnCount - 1;
3251                 to = from + 1; break;
3252             case AUTO_RESIZE_ALL_COLUMNS:
3253                 from = 0;
3254                 to = columnCount; break;
3255             default:
3256                 return;
3257         }
3258 
3259         final int start = from;
3260         final int end = to;
3261         final TableColumnModel cm = columnModel;
3262         Resizable3 r = new Resizable3() {
3263             public int  getElementCount()       { return end-start; }
3264             public int  getLowerBoundAt(int i)  { return cm.getColumn(i+start).getMinWidth(); }
3265             public int  getUpperBoundAt(int i)  { return cm.getColumn(i+start).getMaxWidth(); }
3266             public int  getMidPointAt(int i)    { return cm.getColumn(i+start).getWidth(); }
3267             public void setSizeAt(int s, int i) {        cm.getColumn(i+start).setWidth(s); }
3268         };
3269 
3270         int totalWidth = 0;
3271         for(int i = from; i < to; i++) {
3272             TableColumn aColumn = columnModel.getColumn(i);
3273             int input = aColumn.getWidth();
3274             totalWidth = totalWidth + input;
3275         }
3276 
3277         adjustSizes(totalWidth + delta, r, false);
3278     }
3279 
3280     private interface Resizable2 {
getElementCount()3281         public int  getElementCount();
getLowerBoundAt(int i)3282         public int  getLowerBoundAt(int i);
getUpperBoundAt(int i)3283         public int  getUpperBoundAt(int i);
setSizeAt(int newSize, int i)3284         public void setSizeAt(int newSize, int i);
3285     }
3286 
3287     private interface Resizable3 extends Resizable2 {
getMidPointAt(int i)3288         public int  getMidPointAt(int i);
3289     }
3290 
3291 
adjustSizes(long target, final Resizable3 r, boolean inverse)3292     private void adjustSizes(long target, final Resizable3 r, boolean inverse) {
3293         int N = r.getElementCount();
3294         long totalPreferred = 0;
3295         for(int i = 0; i < N; i++) {
3296             totalPreferred += r.getMidPointAt(i);
3297         }
3298         Resizable2 s;
3299         if ((target < totalPreferred) == !inverse) {
3300             s = new Resizable2() {
3301                 public int  getElementCount()      { return r.getElementCount(); }
3302                 public int  getLowerBoundAt(int i) { return r.getLowerBoundAt(i); }
3303                 public int  getUpperBoundAt(int i) { return r.getMidPointAt(i); }
3304                 public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
3305 
3306             };
3307         }
3308         else {
3309             s = new Resizable2() {
3310                 public int  getElementCount()      { return r.getElementCount(); }
3311                 public int  getLowerBoundAt(int i) { return r.getMidPointAt(i); }
3312                 public int  getUpperBoundAt(int i) { return r.getUpperBoundAt(i); }
3313                 public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
3314 
3315             };
3316         }
3317         adjustSizes(target, s, !inverse);
3318     }
3319 
adjustSizes(long target, Resizable2 r, boolean limitToRange)3320     private void adjustSizes(long target, Resizable2 r, boolean limitToRange) {
3321         long totalLowerBound = 0;
3322         long totalUpperBound = 0;
3323         for(int i = 0; i < r.getElementCount(); i++) {
3324             totalLowerBound += r.getLowerBoundAt(i);
3325             totalUpperBound += r.getUpperBoundAt(i);
3326         }
3327 
3328         if (limitToRange) {
3329             target = Math.min(Math.max(totalLowerBound, target), totalUpperBound);
3330         }
3331 
3332         for(int i = 0; i < r.getElementCount(); i++) {
3333             int lowerBound = r.getLowerBoundAt(i);
3334             int upperBound = r.getUpperBoundAt(i);
3335             // Check for zero. This happens when the distribution of the delta
3336             // finishes early due to a series of "fixed" entries at the end.
3337             // In this case, lowerBound == upperBound, for all subsequent terms.
3338             int newSize;
3339             if (totalLowerBound == totalUpperBound) {
3340                 newSize = lowerBound;
3341             }
3342             else {
3343                 double f = (double)(target - totalLowerBound)/(totalUpperBound - totalLowerBound);
3344                 newSize = (int)Math.round(lowerBound+f*(upperBound - lowerBound));
3345                 // We'd need to round manually in an all integer version.
3346                 // size[i] = (int)(((totalUpperBound - target) * lowerBound +
3347                 //     (target - totalLowerBound) * upperBound)/(totalUpperBound-totalLowerBound));
3348             }
3349             r.setSizeAt(newSize, i);
3350             target -= newSize;
3351             totalLowerBound -= lowerBound;
3352             totalUpperBound -= upperBound;
3353         }
3354     }
3355 
3356     /**
3357      * Overrides <code>JComponent</code>'s <code>getToolTipText</code>
3358      * method in order to allow the renderer's tips to be used
3359      * if it has text set.
3360      * <p>
3361      * <b>Note:</b> For <code>JTable</code> to properly display
3362      * tooltips of its renderers
3363      * <code>JTable</code> must be a registered component with the
3364      * <code>ToolTipManager</code>.
3365      * This is done automatically in <code>initializeLocalVars</code>,
3366      * but if at a later point <code>JTable</code> is told
3367      * <code>setToolTipText(null)</code> it will unregister the table
3368      * component, and no tips from renderers will display anymore.
3369      *
3370      * @see JComponent#getToolTipText
3371      */
getToolTipText(MouseEvent event)3372     public String getToolTipText(MouseEvent event) {
3373         String tip = null;
3374         Point p = event.getPoint();
3375 
3376         // Locate the renderer under the event location
3377         int hitColumnIndex = columnAtPoint(p);
3378         int hitRowIndex = rowAtPoint(p);
3379 
3380         if ((hitColumnIndex != -1) && (hitRowIndex != -1)) {
3381             TableCellRenderer renderer = getCellRenderer(hitRowIndex, hitColumnIndex);
3382             Component component = prepareRenderer(renderer, hitRowIndex, hitColumnIndex);
3383 
3384             // Now have to see if the component is a JComponent before
3385             // getting the tip
3386             if (component instanceof JComponent) {
3387                 // Convert the event to the renderer's coordinate system
3388                 Rectangle cellRect = getCellRect(hitRowIndex, hitColumnIndex, false);
3389                 p.translate(-cellRect.x, -cellRect.y);
3390                 @SuppressWarnings("deprecation")
3391                 final int modifiers = event.getModifiers();
3392                 MouseEvent newEvent = new MouseEvent(component, event.getID(),
3393                                           event.getWhen(), modifiers,
3394                                           p.x, p.y,
3395                                           event.getXOnScreen(),
3396                                           event.getYOnScreen(),
3397                                           event.getClickCount(),
3398                                           event.isPopupTrigger(),
3399                                           MouseEvent.NOBUTTON);
3400                 MouseEventAccessor meAccessor = AWTAccessor.getMouseEventAccessor();
3401                 meAccessor.setCausedByTouchEvent(newEvent,
3402                     meAccessor.isCausedByTouchEvent(event));
3403 
3404                 tip = ((JComponent)component).getToolTipText(newEvent);
3405             }
3406         }
3407 
3408         // No tip from the renderer get our own tip
3409         if (tip == null)
3410             tip = getToolTipText();
3411 
3412         return tip;
3413     }
3414 
3415 //
3416 // Editing Support
3417 //
3418 
3419     /**
3420      * Sets whether editors in this JTable get the keyboard focus
3421      * when an editor is activated as a result of the JTable
3422      * forwarding keyboard events for a cell.
3423      * By default, this property is false, and the JTable
3424      * retains the focus unless the cell is clicked.
3425      *
3426      * @param surrendersFocusOnKeystroke true if the editor should get the focus
3427      *          when keystrokes cause the editor to be
3428      *          activated
3429      *
3430      *
3431      * @see #getSurrendersFocusOnKeystroke
3432      * @since 1.4
3433      */
setSurrendersFocusOnKeystroke(boolean surrendersFocusOnKeystroke)3434     public void setSurrendersFocusOnKeystroke(boolean surrendersFocusOnKeystroke) {
3435         this.surrendersFocusOnKeystroke = surrendersFocusOnKeystroke;
3436     }
3437 
3438     /**
3439      * Returns true if the editor should get the focus
3440      * when keystrokes cause the editor to be activated
3441      *
3442      * @return  true if the editor should get the focus
3443      *          when keystrokes cause the editor to be
3444      *          activated
3445      *
3446      * @see #setSurrendersFocusOnKeystroke
3447      * @since 1.4
3448      */
getSurrendersFocusOnKeystroke()3449     public boolean getSurrendersFocusOnKeystroke() {
3450         return surrendersFocusOnKeystroke;
3451     }
3452 
3453     /**
3454      * Programmatically starts editing the cell at <code>row</code> and
3455      * <code>column</code>, if those indices are in the valid range, and
3456      * the cell at those indices is editable.
3457      * Note that this is a convenience method for
3458      * <code>editCellAt(int, int, null)</code>.
3459      *
3460      * @param   row                             the row to be edited
3461      * @param   column                          the column to be edited
3462      * @return  false if for any reason the cell cannot be edited,
3463      *                or if the indices are invalid
3464      */
editCellAt(int row, int column)3465     public boolean editCellAt(int row, int column) {
3466         return editCellAt(row, column, null);
3467     }
3468 
3469     /**
3470      * Programmatically starts editing the cell at <code>row</code> and
3471      * <code>column</code>, if those indices are in the valid range, and
3472      * the cell at those indices is editable.
3473      * To prevent the <code>JTable</code> from
3474      * editing a particular table, column or cell value, return false from
3475      * the <code>isCellEditable</code> method in the <code>TableModel</code>
3476      * interface.
3477      *
3478      * @param   row     the row to be edited
3479      * @param   column  the column to be edited
3480      * @param   e       event to pass into <code>shouldSelectCell</code>;
3481      *                  note that as of Java 2 platform v1.2, the call to
3482      *                  <code>shouldSelectCell</code> is no longer made
3483      * @return  false if for any reason the cell cannot be edited,
3484      *                or if the indices are invalid
3485      */
editCellAt(int row, int column, EventObject e)3486     public boolean editCellAt(int row, int column, EventObject e){
3487         if (cellEditor != null && !cellEditor.stopCellEditing()) {
3488             return false;
3489         }
3490 
3491         if (row < 0 || row >= getRowCount() ||
3492             column < 0 || column >= getColumnCount()) {
3493             return false;
3494         }
3495 
3496         if (!isCellEditable(row, column))
3497             return false;
3498 
3499         if (editorRemover == null) {
3500             KeyboardFocusManager fm =
3501                 KeyboardFocusManager.getCurrentKeyboardFocusManager();
3502             editorRemover = new CellEditorRemover(fm);
3503             fm.addPropertyChangeListener("permanentFocusOwner", editorRemover);
3504         }
3505 
3506         TableCellEditor editor = getCellEditor(row, column);
3507         if (editor != null && editor.isCellEditable(e)) {
3508             editorComp = prepareEditor(editor, row, column);
3509             if (editorComp == null) {
3510                 removeEditor();
3511                 return false;
3512             }
3513             editorComp.setBounds(getCellRect(row, column, false));
3514             add(editorComp);
3515             editorComp.validate();
3516             editorComp.repaint();
3517 
3518             setCellEditor(editor);
3519             setEditingRow(row);
3520             setEditingColumn(column);
3521             editor.addCellEditorListener(this);
3522 
3523             return true;
3524         }
3525         return false;
3526     }
3527 
3528     /**
3529      * Returns true if a cell is being edited.
3530      *
3531      * @return  true if the table is editing a cell
3532      * @see     #editingColumn
3533      * @see     #editingRow
3534      */
3535     @BeanProperty(bound = false)
isEditing()3536     public boolean isEditing() {
3537         return cellEditor != null;
3538     }
3539 
3540     /**
3541      * Returns the component that is handling the editing session.
3542      * If nothing is being edited, returns null.
3543      *
3544      * @return  Component handling editing session
3545      */
3546     @BeanProperty(bound = false)
getEditorComponent()3547     public Component getEditorComponent() {
3548         return editorComp;
3549     }
3550 
3551     /**
3552      * Returns the index of the column that contains the cell currently
3553      * being edited.  If nothing is being edited, returns -1.
3554      *
3555      * @return  the index of the column that contains the cell currently
3556      *          being edited; returns -1 if nothing being edited
3557      * @see #editingRow
3558      */
getEditingColumn()3559     public int getEditingColumn() {
3560         return editingColumn;
3561     }
3562 
3563     /**
3564      * Returns the index of the row that contains the cell currently
3565      * being edited.  If nothing is being edited, returns -1.
3566      *
3567      * @return  the index of the row that contains the cell currently
3568      *          being edited; returns -1 if nothing being edited
3569      * @see #editingColumn
3570      */
getEditingRow()3571     public int getEditingRow() {
3572         return editingRow;
3573     }
3574 
3575 //
3576 // Managing TableUI
3577 //
3578 
3579     /**
3580      * Returns the L&amp;F object that renders this component.
3581      *
3582      * @return the <code>TableUI</code> object that renders this component
3583      */
getUI()3584     public TableUI getUI() {
3585         return (TableUI)ui;
3586     }
3587 
3588     /**
3589      * Sets the L&amp;F object that renders this component and repaints.
3590      *
3591      * @param ui  the TableUI L&amp;F object
3592      * @see UIDefaults#getUI
3593      */
3594     @BeanProperty(hidden = true, visualUpdate = true, description
3595             = "The UI object that implements the Component's LookAndFeel.")
setUI(TableUI ui)3596     public void setUI(TableUI ui) {
3597         if (this.ui != ui) {
3598             super.setUI(ui);
3599             repaint();
3600         }
3601     }
3602 
3603     /**
3604      * Notification from the <code>UIManager</code> that the L&amp;F has changed.
3605      * Replaces the current UI object with the latest version from the
3606      * <code>UIManager</code>.
3607      *
3608      * @see JComponent#updateUI
3609      */
updateUI()3610     public void updateUI() {
3611         if (updateInProgress) {
3612             return;
3613         }
3614 
3615         updateInProgress = true;
3616 
3617         try {
3618             // Update the UIs of the cell renderers, cell editors and header renderers.
3619             TableColumnModel cm = getColumnModel();
3620             for(int column = 0; column < cm.getColumnCount(); column++) {
3621                 TableColumn aColumn = cm.getColumn(column);
3622                 SwingUtilities.updateRendererOrEditorUI(aColumn.getCellRenderer());
3623                 SwingUtilities.updateRendererOrEditorUI(aColumn.getCellEditor());
3624                 SwingUtilities.updateRendererOrEditorUI(aColumn.getHeaderRenderer());
3625             }
3626 
3627             // Update the UIs of all the default renderers.
3628             Enumeration<?> defaultRenderers = defaultRenderersByColumnClass.elements();
3629             while (defaultRenderers.hasMoreElements()) {
3630                 SwingUtilities.updateRendererOrEditorUI(defaultRenderers.nextElement());
3631             }
3632 
3633             // Update the UIs of all the default editors.
3634             Enumeration<?> defaultEditors = defaultEditorsByColumnClass.elements();
3635             while (defaultEditors.hasMoreElements()) {
3636                 SwingUtilities.updateRendererOrEditorUI(defaultEditors.nextElement());
3637             }
3638 
3639             // Update the UI of the table header
3640             if (tableHeader != null && tableHeader.getParent() == null) {
3641                 tableHeader.updateUI();
3642             }
3643 
3644             // Update UI applied to parent ScrollPane
3645             configureEnclosingScrollPaneUI();
3646 
3647             setUI((TableUI)UIManager.getUI(this));
3648         } finally {
3649             updateInProgress = false;
3650         }
3651     }
3652 
3653     /**
3654      * Returns the suffix used to construct the name of the L&amp;F class used to
3655      * render this component.
3656      *
3657      * @return the string "TableUI"
3658      * @see JComponent#getUIClassID
3659      * @see UIDefaults#getUI
3660      */
3661     @BeanProperty(bound = false)
getUIClassID()3662     public String getUIClassID() {
3663         return uiClassID;
3664     }
3665 
3666 
3667 //
3668 // Managing models
3669 //
3670 
3671     /**
3672      * Sets the data model for this table to {@code dataModel} and registers
3673      * with it for listener notifications from the new data model.
3674      *
3675      * @param  dataModel the new data source for this table
3676      * @throws IllegalArgumentException if {@code dataModel} is {@code null}
3677      * @see #getModel
3678      */
3679     @BeanProperty(description
3680             = "The model that is the source of the data for this view.")
setModel(final TableModel dataModel)3681     public void setModel(final TableModel dataModel) {
3682         if (dataModel == null) {
3683             throw new IllegalArgumentException("Cannot set a null TableModel");
3684         }
3685         if (this.dataModel != dataModel) {
3686             TableModel old = this.dataModel;
3687             if (old != null) {
3688                 old.removeTableModelListener(this);
3689             }
3690             this.dataModel = dataModel;
3691             dataModel.addTableModelListener(this);
3692 
3693             tableChanged(new TableModelEvent(dataModel, TableModelEvent.HEADER_ROW));
3694 
3695             firePropertyChange("model", old, dataModel);
3696 
3697             if (getAutoCreateRowSorter()) {
3698                 setRowSorter(new TableRowSorter<TableModel>(dataModel));
3699             }
3700         }
3701     }
3702 
3703     /**
3704      * Returns the {@code TableModel} that provides the data displayed by this
3705      * {@code JTable}.
3706      *
3707      * @return the {@code TableModel} that provides the data displayed by this
3708      *         {@code JTable}
3709      * @see #setModel
3710      */
getModel()3711     public TableModel getModel() {
3712         return dataModel;
3713     }
3714 
3715     /**
3716      * Sets the column model for this table to {@code columnModel} and registers
3717      * for listener notifications from the new column model. Also sets the
3718      * column model of the {@code JTableHeader} to {@code columnModel}.
3719      *
3720      * @param  columnModel the new data source for this table
3721      * @throws IllegalArgumentException if {@code columnModel} is {@code null}
3722      * @see #getColumnModel
3723      */
3724     @BeanProperty(description
3725             = "The object governing the way columns appear in the view.")
setColumnModel(final TableColumnModel columnModel)3726     public void setColumnModel(final TableColumnModel columnModel) {
3727         if (columnModel == null) {
3728             throw new IllegalArgumentException("Cannot set a null ColumnModel");
3729         }
3730         TableColumnModel old = this.columnModel;
3731         if (columnModel != old) {
3732             if (old != null) {
3733                 old.removeColumnModelListener(this);
3734             }
3735             this.columnModel = columnModel;
3736             columnModel.addColumnModelListener(this);
3737 
3738             // Set the column model of the header as well.
3739             if (tableHeader != null) {
3740                 tableHeader.setColumnModel(columnModel);
3741             }
3742 
3743             firePropertyChange("columnModel", old, columnModel);
3744             resizeAndRepaint();
3745         }
3746     }
3747 
3748     /**
3749      * Returns the {@code TableColumnModel} that contains all column information
3750      * of this table.
3751      *
3752      * @return the object that provides the column state of the table
3753      * @see #setColumnModel
3754      */
getColumnModel()3755     public TableColumnModel getColumnModel() {
3756         return columnModel;
3757     }
3758 
3759     /**
3760      * Sets the row selection model for this table to {@code selectionModel}
3761      * and registers for listener notifications from the new selection model.
3762      *
3763      * @param  selectionModel the new selection model
3764      * @throws IllegalArgumentException if {@code selectionModel} is
3765      *         {@code null}
3766      * @see #getSelectionModel
3767      */
3768     @BeanProperty(description
3769             = "The selection model for rows.")
setSelectionModel(final ListSelectionModel selectionModel)3770     public void setSelectionModel(final ListSelectionModel selectionModel) {
3771         if (selectionModel == null) {
3772             throw new IllegalArgumentException("Cannot set a null SelectionModel");
3773         }
3774 
3775         ListSelectionModel oldModel = this.selectionModel;
3776 
3777         if (selectionModel != oldModel) {
3778             if (oldModel != null) {
3779                 oldModel.removeListSelectionListener(this);
3780             }
3781 
3782             this.selectionModel = selectionModel;
3783             selectionModel.addListSelectionListener(this);
3784 
3785             firePropertyChange("selectionModel", oldModel, selectionModel);
3786             repaint();
3787         }
3788     }
3789 
3790     /**
3791      * Returns the {@code ListSelectionModel} that is used to maintain row
3792      * selection state.
3793      *
3794      * @return the object that provides row selection state, {@code null} if row
3795      *         selection is not allowed
3796      * @see #setSelectionModel
3797      */
getSelectionModel()3798     public ListSelectionModel getSelectionModel() {
3799         return selectionModel;
3800     }
3801 
3802 //
3803 // RowSorterListener
3804 //
3805 
3806     /**
3807      * <code>RowSorterListener</code> notification that the
3808      * <code>RowSorter</code> has changed in some way.
3809      *
3810      * @param e the <code>RowSorterEvent</code> describing the change
3811      * @throws NullPointerException if <code>e</code> is <code>null</code>
3812      * @since 1.6
3813      */
sorterChanged(RowSorterEvent e)3814     public void sorterChanged(RowSorterEvent e) {
3815         if (e.getType() == RowSorterEvent.Type.SORT_ORDER_CHANGED) {
3816             JTableHeader header = getTableHeader();
3817             if (header != null) {
3818                 header.repaint();
3819             }
3820         }
3821         else if (e.getType() == RowSorterEvent.Type.SORTED) {
3822             sorterChanged = true;
3823             if (!ignoreSortChange) {
3824                 sortedTableChanged(e, null);
3825             }
3826         }
3827     }
3828 
3829 
3830     /**
3831      * SortManager provides support for managing the selection and variable
3832      * row heights when sorting is enabled. This information is encapsulated
3833      * into a class to avoid bulking up JTable.
3834      */
3835     private final class SortManager {
3836         RowSorter<? extends TableModel> sorter;
3837 
3838         // Selection, in terms of the model. This is lazily created
3839         // as needed.
3840         private ListSelectionModel modelSelection;
3841         private int modelLeadIndex;
3842         // Set to true while in the process of changing the selection.
3843         // If this is true the selection change is ignored.
3844         private boolean syncingSelection;
3845         // Temporary cache of selection, in terms of model. This is only used
3846         // if we don't need the full weight of modelSelection.
3847         private int[] lastModelSelection;
3848 
3849         // Heights of the rows in terms of the model.
3850         private SizeSequence modelRowSizes;
3851 
3852 
SortManager(RowSorter<? extends TableModel> sorter)3853         SortManager(RowSorter<? extends TableModel> sorter) {
3854             this.sorter = sorter;
3855             sorter.addRowSorterListener(JTable.this);
3856         }
3857 
3858         /**
3859          * Disposes any resources used by this SortManager.
3860          */
dispose()3861         public void dispose() {
3862             if (sorter != null) {
3863                 sorter.removeRowSorterListener(JTable.this);
3864             }
3865         }
3866 
3867         /**
3868          * Sets the height for a row at a specified index.
3869          */
setViewRowHeight(int viewIndex, int rowHeight)3870         public void setViewRowHeight(int viewIndex, int rowHeight) {
3871             if (modelRowSizes == null) {
3872                 modelRowSizes = new SizeSequence(getModel().getRowCount(),
3873                                                  getRowHeight());
3874             }
3875             modelRowSizes.setSize(convertRowIndexToModel(viewIndex),rowHeight);
3876         }
3877 
3878         /**
3879          * Invoked when the underlying model has completely changed.
3880          */
allChanged()3881         public void allChanged() {
3882             modelLeadIndex = -1;
3883             modelSelection = null;
3884             modelRowSizes = null;
3885         }
3886 
3887         /**
3888          * Invoked when the selection, on the view, has changed.
3889          */
viewSelectionChanged(ListSelectionEvent e)3890         public void viewSelectionChanged(ListSelectionEvent e) {
3891             if (!syncingSelection && modelSelection != null) {
3892                 modelSelection = null;
3893             }
3894         }
3895 
3896         /**
3897          * Invoked when either the table model has changed, or the RowSorter
3898          * has changed. This is invoked prior to notifying the sorter of the
3899          * change.
3900          */
prepareForChange(RowSorterEvent sortEvent, ModelChange change)3901         public void prepareForChange(RowSorterEvent sortEvent,
3902                                      ModelChange change) {
3903             if (getUpdateSelectionOnSort()) {
3904                 cacheSelection(sortEvent, change);
3905             }
3906         }
3907 
3908         /**
3909          * Updates the internal cache of the selection based on the change.
3910          */
cacheSelection(RowSorterEvent sortEvent, ModelChange change)3911         private void cacheSelection(RowSorterEvent sortEvent,
3912                                     ModelChange change) {
3913             if (sortEvent != null) {
3914                 // sort order changed. If modelSelection is null and filtering
3915                 // is enabled we need to cache the selection in terms of the
3916                 // underlying model, this will allow us to correctly restore
3917                 // the selection even if rows are filtered out.
3918                 if (modelSelection == null &&
3919                         sorter.getViewRowCount() != getModel().getRowCount()) {
3920                     modelSelection = new DefaultListSelectionModel();
3921                     ListSelectionModel viewSelection = getSelectionModel();
3922                     int min = viewSelection.getMinSelectionIndex();
3923                     int max = viewSelection.getMaxSelectionIndex();
3924                     int modelIndex;
3925                     for (int viewIndex = min; viewIndex <= max; viewIndex++) {
3926                         if (viewSelection.isSelectedIndex(viewIndex)) {
3927                             modelIndex = convertRowIndexToModel(
3928                                     sortEvent, viewIndex);
3929                             if (modelIndex != -1) {
3930                                 modelSelection.addSelectionInterval(
3931                                     modelIndex, modelIndex);
3932                             }
3933                         }
3934                     }
3935                     modelIndex = convertRowIndexToModel(sortEvent,
3936                             viewSelection.getLeadSelectionIndex());
3937                     SwingUtilities2.setLeadAnchorWithoutSelection(
3938                             modelSelection, modelIndex, modelIndex);
3939                 } else if (modelSelection == null) {
3940                     // Sorting changed, haven't cached selection in terms
3941                     // of model and no filtering. Temporarily cache selection.
3942                     cacheModelSelection(sortEvent);
3943                 }
3944             } else if (change.allRowsChanged) {
3945                 // All the rows have changed, chuck any cached selection.
3946                 modelSelection = null;
3947             } else if (modelSelection != null) {
3948                 // Table changed, reflect changes in cached selection model.
3949                 switch(change.type) {
3950                 case TableModelEvent.DELETE:
3951                     modelSelection.removeIndexInterval(change.startModelIndex,
3952                                                        change.endModelIndex);
3953                     break;
3954                 case TableModelEvent.INSERT:
3955                     modelSelection.insertIndexInterval(change.startModelIndex,
3956                                                        change.length,
3957                                                        true);
3958                     break;
3959                 default:
3960                     break;
3961                 }
3962             } else {
3963                 // table changed, but haven't cached rows, temporarily
3964                 // cache them.
3965                 cacheModelSelection(null);
3966             }
3967         }
3968 
cacheModelSelection(RowSorterEvent sortEvent)3969         private void cacheModelSelection(RowSorterEvent sortEvent) {
3970             lastModelSelection = convertSelectionToModel(sortEvent);
3971             modelLeadIndex = convertRowIndexToModel(sortEvent,
3972                         selectionModel.getLeadSelectionIndex());
3973         }
3974 
3975         /**
3976          * Inovked when either the table has changed or the sorter has changed
3977          * and after the sorter has been notified. If necessary this will
3978          * reapply the selection and variable row heights.
3979          */
processChange(RowSorterEvent sortEvent, ModelChange change, boolean sorterChanged)3980         public void processChange(RowSorterEvent sortEvent,
3981                                   ModelChange change,
3982                                   boolean sorterChanged) {
3983             if (change != null) {
3984                 if (change.allRowsChanged) {
3985                     modelRowSizes = null;
3986                     rowModel = null;
3987                 } else if (modelRowSizes != null) {
3988                     if (change.type == TableModelEvent.INSERT) {
3989                         modelRowSizes.insertEntries(change.startModelIndex,
3990                                                     change.endModelIndex -
3991                                                     change.startModelIndex + 1,
3992                                                     getRowHeight());
3993                     } else if (change.type == TableModelEvent.DELETE) {
3994                         modelRowSizes.removeEntries(change.startModelIndex,
3995                                                     change.endModelIndex -
3996                                                     change.startModelIndex +1 );
3997                     }
3998                 }
3999             }
4000             if (sorterChanged) {
4001                 setViewRowHeightsFromModel();
4002                 restoreSelection(change);
4003             }
4004         }
4005 
4006         /**
4007          * Resets the variable row heights in terms of the view from
4008          * that of the variable row heights in terms of the model.
4009          */
setViewRowHeightsFromModel()4010         private void setViewRowHeightsFromModel() {
4011             if (modelRowSizes != null) {
4012                 rowModel.setSizes(getRowCount(), getRowHeight());
4013                 for (int viewIndex = getRowCount() - 1; viewIndex >= 0;
4014                          viewIndex--) {
4015                     int modelIndex = convertRowIndexToModel(viewIndex);
4016                     rowModel.setSize(viewIndex,
4017                                      modelRowSizes.getSize(modelIndex));
4018                 }
4019             }
4020         }
4021 
4022         /**
4023          * Restores the selection from that in terms of the model.
4024          */
restoreSelection(ModelChange change)4025         private void restoreSelection(ModelChange change) {
4026             syncingSelection = true;
4027             if (lastModelSelection != null) {
4028                 restoreSortingSelection(lastModelSelection,
4029                                         modelLeadIndex, change);
4030                 lastModelSelection = null;
4031             } else if (modelSelection != null) {
4032                 ListSelectionModel viewSelection = getSelectionModel();
4033                 viewSelection.setValueIsAdjusting(true);
4034                 viewSelection.clearSelection();
4035                 int min = modelSelection.getMinSelectionIndex();
4036                 int max = modelSelection.getMaxSelectionIndex();
4037                 int viewIndex;
4038                 for (int modelIndex = min; modelIndex <= max; modelIndex++) {
4039                     if (modelSelection.isSelectedIndex(modelIndex)) {
4040                         viewIndex = convertRowIndexToView(modelIndex);
4041                         if (viewIndex != -1) {
4042                             viewSelection.addSelectionInterval(viewIndex,
4043                                                                viewIndex);
4044                         }
4045                     }
4046                 }
4047                 // Restore the lead
4048                 int viewLeadIndex = modelSelection.getLeadSelectionIndex();
4049                 if (viewLeadIndex != -1 && !modelSelection.isSelectionEmpty()) {
4050                     viewLeadIndex = convertRowIndexToView(viewLeadIndex);
4051                 }
4052                 SwingUtilities2.setLeadAnchorWithoutSelection(
4053                         viewSelection, viewLeadIndex, viewLeadIndex);
4054                 viewSelection.setValueIsAdjusting(false);
4055             }
4056             syncingSelection = false;
4057         }
4058     }
4059 
4060 
4061     /**
4062      * ModelChange is used when sorting to restore state, it corresponds
4063      * to data from a TableModelEvent.  The values are precalculated as
4064      * they are used extensively.
4065      */
4066     private final class ModelChange {
4067         // Starting index of the change, in terms of the model
4068         int startModelIndex;
4069 
4070         // Ending index of the change, in terms of the model
4071         int endModelIndex;
4072 
4073         // Type of change
4074         int type;
4075 
4076         // Number of rows in the model
4077         int modelRowCount;
4078 
4079         // The event that triggered this.
4080         TableModelEvent event;
4081 
4082         // Length of the change (end - start + 1)
4083         int length;
4084 
4085         // True if the event indicates all the contents have changed
4086         boolean allRowsChanged;
4087 
ModelChange(TableModelEvent e)4088         ModelChange(TableModelEvent e) {
4089             startModelIndex = Math.max(0, e.getFirstRow());
4090             endModelIndex = e.getLastRow();
4091             modelRowCount = getModel().getRowCount();
4092             if (endModelIndex < 0) {
4093                 endModelIndex = Math.max(0, modelRowCount - 1);
4094             }
4095             length = endModelIndex - startModelIndex + 1;
4096             type = e.getType();
4097             event = e;
4098             allRowsChanged = (e.getLastRow() == Integer.MAX_VALUE);
4099         }
4100     }
4101 
4102     /**
4103      * Invoked when <code>sorterChanged</code> is invoked, or
4104      * when <code>tableChanged</code> is invoked and sorting is enabled.
4105      */
sortedTableChanged(RowSorterEvent sortedEvent, TableModelEvent e)4106     private void sortedTableChanged(RowSorterEvent sortedEvent,
4107                                     TableModelEvent e) {
4108         int editingModelIndex = -1;
4109         ModelChange change = (e != null) ? new ModelChange(e) : null;
4110 
4111         if ((change == null || !change.allRowsChanged) &&
4112                 this.editingRow != -1) {
4113             editingModelIndex = convertRowIndexToModel(sortedEvent,
4114                                                        this.editingRow);
4115         }
4116 
4117         sortManager.prepareForChange(sortedEvent, change);
4118 
4119         if (e != null) {
4120             if (change.type == TableModelEvent.UPDATE) {
4121                 repaintSortedRows(change);
4122             }
4123             notifySorter(change);
4124             if (change.type != TableModelEvent.UPDATE) {
4125                 // If the Sorter is unsorted we will not have received
4126                 // notification, force treating insert/delete as a change.
4127                 sorterChanged = true;
4128             }
4129         }
4130         else {
4131             sorterChanged = true;
4132         }
4133 
4134         sortManager.processChange(sortedEvent, change, sorterChanged);
4135 
4136         if (sorterChanged) {
4137             // Update the editing row
4138             if (this.editingRow != -1) {
4139                 int newIndex = (editingModelIndex == -1) ? -1 :
4140                         convertRowIndexToView(editingModelIndex,change);
4141                 restoreSortingEditingRow(newIndex);
4142             }
4143 
4144             // And handle the appropriate repainting.
4145             if (e == null || change.type != TableModelEvent.UPDATE) {
4146                 resizeAndRepaint();
4147             }
4148         }
4149 
4150         // Check if lead/anchor need to be reset.
4151         if (change != null && change.allRowsChanged) {
4152             clearSelectionAndLeadAnchor();
4153             resizeAndRepaint();
4154         }
4155     }
4156 
4157     /**
4158      * Repaints the sort of sorted rows in response to a TableModelEvent.
4159      */
repaintSortedRows(ModelChange change)4160     private void repaintSortedRows(ModelChange change) {
4161         if (change.startModelIndex > change.endModelIndex ||
4162                 change.startModelIndex + 10 < change.endModelIndex) {
4163             // Too much has changed, punt
4164             repaint();
4165             return;
4166         }
4167         int eventColumn = change.event.getColumn();
4168         int columnViewIndex = eventColumn;
4169         if (columnViewIndex == TableModelEvent.ALL_COLUMNS) {
4170             columnViewIndex = 0;
4171         }
4172         else {
4173             columnViewIndex = convertColumnIndexToView(columnViewIndex);
4174             if (columnViewIndex == -1) {
4175                 return;
4176             }
4177         }
4178         int modelIndex = change.startModelIndex;
4179         while (modelIndex <= change.endModelIndex) {
4180             int viewIndex = convertRowIndexToView(modelIndex++);
4181             if (viewIndex != -1) {
4182                 Rectangle dirty = getCellRect(viewIndex, columnViewIndex,
4183                                               false);
4184                 int x = dirty.x;
4185                 int w = dirty.width;
4186                 if (eventColumn == TableModelEvent.ALL_COLUMNS) {
4187                     x = 0;
4188                     w = getWidth();
4189                 }
4190                 repaint(x, dirty.y, w, dirty.height);
4191             }
4192         }
4193     }
4194 
4195     /**
4196      * Restores the selection after a model event/sort order changes.
4197      * All coordinates are in terms of the model.
4198      */
restoreSortingSelection(int[] selection, int lead, ModelChange change)4199     private void restoreSortingSelection(int[] selection, int lead,
4200             ModelChange change) {
4201         // Convert the selection from model to view
4202         for (int i = selection.length - 1; i >= 0; i--) {
4203             selection[i] = convertRowIndexToView(selection[i], change);
4204         }
4205         lead = convertRowIndexToView(lead, change);
4206 
4207         // Check for the common case of no change in selection for 1 row
4208         if (selection.length == 0 ||
4209             (selection.length == 1 && selection[0] == getSelectedRow())) {
4210             return;
4211         }
4212 
4213         // And apply the new selection
4214         selectionModel.setValueIsAdjusting(true);
4215         selectionModel.clearSelection();
4216         for (int i = selection.length - 1; i >= 0; i--) {
4217             if (selection[i] != -1) {
4218                 selectionModel.addSelectionInterval(selection[i],
4219                                                     selection[i]);
4220             }
4221         }
4222         SwingUtilities2.setLeadAnchorWithoutSelection(
4223                 selectionModel, lead, lead);
4224         selectionModel.setValueIsAdjusting(false);
4225     }
4226 
4227     /**
4228      * Restores the editing row after a model event/sort order change.
4229      *
4230      * @param editingRow new index of the editingRow, in terms of the view
4231      */
restoreSortingEditingRow(int editingRow)4232     private void restoreSortingEditingRow(int editingRow) {
4233         if (editingRow == -1) {
4234             // Editing row no longer being shown, cancel editing
4235             TableCellEditor editor = getCellEditor();
4236             if (editor != null) {
4237                 // First try and cancel
4238                 editor.cancelCellEditing();
4239                 if (getCellEditor() != null) {
4240                     // CellEditor didn't cede control, forcefully
4241                     // remove it
4242                     removeEditor();
4243                 }
4244             }
4245         }
4246         else {
4247             // Repositioning handled in BasicTableUI
4248             this.editingRow = editingRow;
4249             repaint();
4250         }
4251     }
4252 
4253     /**
4254      * Notifies the sorter of a change in the underlying model.
4255      */
notifySorter(ModelChange change)4256     private void notifySorter(ModelChange change) {
4257         try {
4258             ignoreSortChange = true;
4259             sorterChanged = false;
4260             switch(change.type) {
4261             case TableModelEvent.UPDATE:
4262                 if (change.event.getLastRow() == Integer.MAX_VALUE) {
4263                     sortManager.sorter.allRowsChanged();
4264                 } else if (change.event.getColumn() ==
4265                            TableModelEvent.ALL_COLUMNS) {
4266                     sortManager.sorter.rowsUpdated(change.startModelIndex,
4267                                        change.endModelIndex);
4268                 } else {
4269                     sortManager.sorter.rowsUpdated(change.startModelIndex,
4270                                        change.endModelIndex,
4271                                        change.event.getColumn());
4272                 }
4273                 break;
4274             case TableModelEvent.INSERT:
4275                 sortManager.sorter.rowsInserted(change.startModelIndex,
4276                                     change.endModelIndex);
4277                 break;
4278             case TableModelEvent.DELETE:
4279                 sortManager.sorter.rowsDeleted(change.startModelIndex,
4280                                    change.endModelIndex);
4281                 break;
4282             }
4283         } finally {
4284             ignoreSortChange = false;
4285         }
4286     }
4287 
4288     /**
4289      * Converts a model index to view index.  This is called when the
4290      * sorter or model changes and sorting is enabled.
4291      *
4292      * @param change describes the TableModelEvent that initiated the change;
4293      *        will be null if called as the result of a sort
4294      */
convertRowIndexToView(int modelIndex, ModelChange change)4295     private int convertRowIndexToView(int modelIndex, ModelChange change) {
4296         if (modelIndex < 0) {
4297             return -1;
4298         }
4299         if (change != null && modelIndex >= change.startModelIndex) {
4300             if (change.type == TableModelEvent.INSERT) {
4301                 if (modelIndex + change.length >= change.modelRowCount) {
4302                     return -1;
4303                 }
4304                 return sortManager.sorter.convertRowIndexToView(
4305                         modelIndex + change.length);
4306             }
4307             else if (change.type == TableModelEvent.DELETE) {
4308                 if (modelIndex <= change.endModelIndex) {
4309                     // deleted
4310                     return -1;
4311                 }
4312                 else {
4313                     if (modelIndex - change.length >= change.modelRowCount) {
4314                         return -1;
4315                     }
4316                     return sortManager.sorter.convertRowIndexToView(
4317                             modelIndex - change.length);
4318                 }
4319             }
4320             // else, updated
4321         }
4322         if (modelIndex >= getModel().getRowCount()) {
4323             return -1;
4324         }
4325         return sortManager.sorter.convertRowIndexToView(modelIndex);
4326     }
4327 
4328     /**
4329      * Converts the selection to model coordinates.  This is used when
4330      * the model changes or the sorter changes.
4331      */
convertSelectionToModel(RowSorterEvent e)4332     private int[] convertSelectionToModel(RowSorterEvent e) {
4333         int[] selection = getSelectedRows();
4334         for (int i = selection.length - 1; i >= 0; i--) {
4335             selection[i] = convertRowIndexToModel(e, selection[i]);
4336         }
4337         return selection;
4338     }
4339 
convertRowIndexToModel(RowSorterEvent e, int viewIndex)4340     private int convertRowIndexToModel(RowSorterEvent e, int viewIndex) {
4341         if (e != null) {
4342             if (e.getPreviousRowCount() == 0) {
4343                 return viewIndex;
4344             }
4345             // range checking handled by RowSorterEvent
4346             return e.convertPreviousRowIndexToModel(viewIndex);
4347         }
4348         // Make sure the viewIndex is valid
4349         if (viewIndex < 0 || viewIndex >= getRowCount()) {
4350             return -1;
4351         }
4352         return convertRowIndexToModel(viewIndex);
4353     }
4354 
4355 //
4356 // Implementing TableModelListener interface
4357 //
4358 
4359     /**
4360      * Invoked when this table's <code>TableModel</code> generates
4361      * a <code>TableModelEvent</code>.
4362      * The <code>TableModelEvent</code> should be constructed in the
4363      * coordinate system of the model; the appropriate mapping to the
4364      * view coordinate system is performed by this <code>JTable</code>
4365      * when it receives the event.
4366      * <p>
4367      * Application code will not use these methods explicitly, they
4368      * are used internally by <code>JTable</code>.
4369      * <p>
4370      * Note that as of 1.3, this method clears the selection, if any.
4371      */
tableChanged(TableModelEvent e)4372     public void tableChanged(TableModelEvent e) {
4373         if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
4374             // The whole thing changed
4375             clearSelectionAndLeadAnchor();
4376 
4377             rowModel = null;
4378 
4379             if (sortManager != null) {
4380                 try {
4381                     ignoreSortChange = true;
4382                     sortManager.sorter.modelStructureChanged();
4383                 } finally {
4384                     ignoreSortChange = false;
4385                 }
4386                 sortManager.allChanged();
4387             }
4388 
4389             if (getAutoCreateColumnsFromModel()) {
4390                 // This will effect invalidation of the JTable and JTableHeader.
4391                 createDefaultColumnsFromModel();
4392                 return;
4393             }
4394 
4395             resizeAndRepaint();
4396             return;
4397         }
4398 
4399         if (sortManager != null) {
4400             sortedTableChanged(null, e);
4401             return;
4402         }
4403 
4404         // The totalRowHeight calculated below will be incorrect if
4405         // there are variable height rows. Repaint the visible region,
4406         // but don't return as a revalidate may be necessary as well.
4407         if (rowModel != null) {
4408             repaint();
4409         }
4410 
4411         if (e.getType() == TableModelEvent.INSERT) {
4412             tableRowsInserted(e);
4413             return;
4414         }
4415 
4416         if (e.getType() == TableModelEvent.DELETE) {
4417             tableRowsDeleted(e);
4418             return;
4419         }
4420 
4421         int modelColumn = e.getColumn();
4422         int start = e.getFirstRow();
4423         int end = e.getLastRow();
4424 
4425         Rectangle dirtyRegion;
4426         if (modelColumn == TableModelEvent.ALL_COLUMNS) {
4427             // 1 or more rows changed
4428             dirtyRegion = new Rectangle(0, start * getRowHeight(),
4429                                         getColumnModel().getTotalColumnWidth(), 0);
4430         }
4431         else {
4432             // A cell or column of cells has changed.
4433             // Unlike the rest of the methods in the JTable, the TableModelEvent
4434             // uses the coordinate system of the model instead of the view.
4435             // This is the only place in the JTable where this "reverse mapping"
4436             // is used.
4437             int column = convertColumnIndexToView(modelColumn);
4438             dirtyRegion = getCellRect(start, column, false);
4439         }
4440 
4441         // Now adjust the height of the dirty region according to the value of "end".
4442         // Check for Integer.MAX_VALUE as this will cause an overflow.
4443         if (end != Integer.MAX_VALUE) {
4444             dirtyRegion.height = (end-start+1)*getRowHeight();
4445             repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
4446         }
4447         // In fact, if the end is Integer.MAX_VALUE we need to revalidate anyway
4448         // because the scrollbar may need repainting.
4449         else {
4450             clearSelectionAndLeadAnchor();
4451             resizeAndRepaint();
4452             rowModel = null;
4453         }
4454     }
4455 
4456     /*
4457      * Invoked when rows have been inserted into the table.
4458      * <p>
4459      * Application code will not use these methods explicitly, they
4460      * are used internally by JTable.
4461      *
4462      * @param e the TableModelEvent encapsulating the insertion
4463      */
tableRowsInserted(TableModelEvent e)4464     private void tableRowsInserted(TableModelEvent e) {
4465         int start = e.getFirstRow();
4466         int end = e.getLastRow();
4467         if (start < 0) {
4468             start = 0;
4469         }
4470         if (end < 0) {
4471             end = getRowCount()-1;
4472         }
4473 
4474         // Adjust the selection to account for the new rows.
4475         int length = end - start + 1;
4476         selectionModel.insertIndexInterval(start, length, true);
4477 
4478         // If we have variable height rows, adjust the row model.
4479         if (rowModel != null) {
4480             rowModel.insertEntries(start, length, getRowHeight());
4481         }
4482         int rh = getRowHeight() ;
4483         Rectangle drawRect = new Rectangle(0, start * rh,
4484                                         getColumnModel().getTotalColumnWidth(),
4485                                            (getRowCount()-start) * rh);
4486 
4487         revalidate();
4488         // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
4489         // repaint still required in the unusual case where there is no ScrollPane
4490         repaint(drawRect);
4491     }
4492 
4493     /*
4494      * Invoked when rows have been removed from the table.
4495      * <p>
4496      * Application code will not use these methods explicitly, they
4497      * are used internally by JTable.
4498      *
4499      * @param e the TableModelEvent encapsulating the deletion
4500      */
tableRowsDeleted(TableModelEvent e)4501     private void tableRowsDeleted(TableModelEvent e) {
4502         int start = e.getFirstRow();
4503         int end = e.getLastRow();
4504         if (start < 0) {
4505             start = 0;
4506         }
4507         if (end < 0) {
4508             end = getRowCount()-1;
4509         }
4510 
4511         int deletedCount = end - start + 1;
4512         int previousRowCount = getRowCount() + deletedCount;
4513         // Adjust the selection to account for the new rows
4514         selectionModel.removeIndexInterval(start, end);
4515 
4516         // If we have variable height rows, adjust the row model.
4517         if (rowModel != null) {
4518             rowModel.removeEntries(start, deletedCount);
4519         }
4520 
4521         int rh = getRowHeight();
4522         Rectangle drawRect = new Rectangle(0, start * rh,
4523                                         getColumnModel().getTotalColumnWidth(),
4524                                         (previousRowCount - start) * rh);
4525 
4526         revalidate();
4527         // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
4528         // repaint still required in the unusual case where there is no ScrollPane
4529         repaint(drawRect);
4530     }
4531 
4532 //
4533 // Implementing TableColumnModelListener interface
4534 //
4535 
4536     /**
4537      * Invoked when a column is added to the table column model.
4538      * <p>
4539      * Application code will not use these methods explicitly, they
4540      * are used internally by JTable.
4541      *
4542      * @see TableColumnModelListener
4543      */
columnAdded(TableColumnModelEvent e)4544     public void columnAdded(TableColumnModelEvent e) {
4545         // If I'm currently editing, then I should stop editing
4546         if (isEditing()) {
4547             removeEditor();
4548         }
4549         resizeAndRepaint();
4550     }
4551 
4552     /**
4553      * Invoked when a column is removed from the table column model.
4554      * <p>
4555      * Application code will not use these methods explicitly, they
4556      * are used internally by JTable.
4557      *
4558      * @see TableColumnModelListener
4559      */
columnRemoved(TableColumnModelEvent e)4560     public void columnRemoved(TableColumnModelEvent e) {
4561         // If I'm currently editing, then I should stop editing
4562         if (isEditing()) {
4563             removeEditor();
4564         }
4565         resizeAndRepaint();
4566     }
4567 
4568     /**
4569      * Invoked when a column is repositioned. If a cell is being
4570      * edited, then editing is stopped and the cell is redrawn.
4571      * <p>
4572      * Application code will not use these methods explicitly, they
4573      * are used internally by JTable.
4574      *
4575      * @param e   the event received
4576      * @see TableColumnModelListener
4577      */
columnMoved(TableColumnModelEvent e)4578     public void columnMoved(TableColumnModelEvent e) {
4579         if (isEditing() && !getCellEditor().stopCellEditing()) {
4580             getCellEditor().cancelCellEditing();
4581         }
4582         repaint();
4583     }
4584 
4585     /**
4586      * Invoked when a column is moved due to a margin change.
4587      * If a cell is being edited, then editing is stopped and the cell
4588      * is redrawn.
4589      * <p>
4590      * Application code will not use these methods explicitly, they
4591      * are used internally by JTable.
4592      *
4593      * @param  e    the event received
4594      * @see TableColumnModelListener
4595      */
columnMarginChanged(ChangeEvent e)4596     public void columnMarginChanged(ChangeEvent e) {
4597         if (isEditing() && !getCellEditor().stopCellEditing()) {
4598             getCellEditor().cancelCellEditing();
4599         }
4600         TableColumn resizingColumn = getResizingColumn();
4601         // Need to do this here, before the parent's
4602         // layout manager calls getPreferredSize().
4603         if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF) {
4604             resizingColumn.setPreferredWidth(resizingColumn.getWidth());
4605         }
4606         resizeAndRepaint();
4607     }
4608 
limit(int i, int a, int b)4609     private int limit(int i, int a, int b) {
4610         return Math.min(b, Math.max(i, a));
4611     }
4612 
4613     /**
4614      * Invoked when the selection model of the <code>TableColumnModel</code>
4615      * is changed.
4616      * <p>
4617      * Application code will not use these methods explicitly, they
4618      * are used internally by JTable.
4619      *
4620      * @param  e  the event received
4621      * @see TableColumnModelListener
4622      */
columnSelectionChanged(ListSelectionEvent e)4623     public void columnSelectionChanged(ListSelectionEvent e) {
4624         boolean isAdjusting = e.getValueIsAdjusting();
4625         if (columnSelectionAdjusting && !isAdjusting) {
4626             // The assumption is that when the model is no longer adjusting
4627             // we will have already gotten all the changes, and therefore
4628             // don't need to do an additional paint.
4629             columnSelectionAdjusting = false;
4630             return;
4631         }
4632         columnSelectionAdjusting = isAdjusting;
4633         // The getCellRect() call will fail unless there is at least one row.
4634         if (getRowCount() <= 0 || getColumnCount() <= 0) {
4635             return;
4636         }
4637         int firstIndex = limit(e.getFirstIndex(), 0, getColumnCount()-1);
4638         int lastIndex = limit(e.getLastIndex(), 0, getColumnCount()-1);
4639         int minRow = 0;
4640         int maxRow = getRowCount() - 1;
4641         if (getRowSelectionAllowed()) {
4642             minRow = selectionModel.getMinSelectionIndex();
4643             maxRow = selectionModel.getMaxSelectionIndex();
4644             int leadRow = getAdjustedIndex(selectionModel.getLeadSelectionIndex(), true);
4645 
4646             if (minRow == -1 || maxRow == -1) {
4647                 if (leadRow == -1) {
4648                     // nothing to repaint, return
4649                     return;
4650                 }
4651 
4652                 // only thing to repaint is the lead
4653                 minRow = maxRow = leadRow;
4654             } else {
4655                 // We need to consider more than just the range between
4656                 // the min and max selected index. The lead row, which could
4657                 // be outside this range, should be considered also.
4658                 if (leadRow != -1) {
4659                     minRow = Math.min(minRow, leadRow);
4660                     maxRow = Math.max(maxRow, leadRow);
4661                 }
4662             }
4663         }
4664         Rectangle firstColumnRect = getCellRect(minRow, firstIndex, false);
4665         Rectangle lastColumnRect = getCellRect(maxRow, lastIndex, false);
4666         Rectangle dirtyRegion = firstColumnRect.union(lastColumnRect);
4667         repaint(dirtyRegion);
4668     }
4669 
4670 //
4671 // Implementing ListSelectionListener interface
4672 //
4673 
4674     /**
4675      * Invoked when the row selection changes -- repaints to show the new
4676      * selection.
4677      * <p>
4678      * Application code will not use these methods explicitly, they
4679      * are used internally by JTable.
4680      *
4681      * @param e   the event received
4682      * @see ListSelectionListener
4683      */
valueChanged(ListSelectionEvent e)4684     public void valueChanged(ListSelectionEvent e) {
4685         if (sortManager != null) {
4686             sortManager.viewSelectionChanged(e);
4687         }
4688         boolean isAdjusting = e.getValueIsAdjusting();
4689         if (rowSelectionAdjusting && !isAdjusting) {
4690             // The assumption is that when the model is no longer adjusting
4691             // we will have already gotten all the changes, and therefore
4692             // don't need to do an additional paint.
4693             rowSelectionAdjusting = false;
4694             return;
4695         }
4696         rowSelectionAdjusting = isAdjusting;
4697         // The getCellRect() calls will fail unless there is at least one column.
4698         if (getRowCount() <= 0 || getColumnCount() <= 0) {
4699             return;
4700         }
4701         int firstIndex = limit(e.getFirstIndex(), 0, getRowCount()-1);
4702         int lastIndex = limit(e.getLastIndex(), 0, getRowCount()-1);
4703         Rectangle firstRowRect = getCellRect(firstIndex, 0, false);
4704         Rectangle lastRowRect = getCellRect(lastIndex, getColumnCount()-1, false);
4705         Rectangle dirtyRegion = firstRowRect.union(lastRowRect);
4706         repaint(dirtyRegion);
4707     }
4708 
4709 //
4710 // Implementing the CellEditorListener interface
4711 //
4712 
4713     /**
4714      * Invoked when editing is finished. The changes are saved and the
4715      * editor is discarded.
4716      * <p>
4717      * Application code will not use these methods explicitly, they
4718      * are used internally by JTable.
4719      *
4720      * @param  e  the event received
4721      * @see CellEditorListener
4722      */
editingStopped(ChangeEvent e)4723     public void editingStopped(ChangeEvent e) {
4724         // Take in the new value
4725         TableCellEditor editor = getCellEditor();
4726         if (editor != null) {
4727             Object value = editor.getCellEditorValue();
4728             setValueAt(value, editingRow, editingColumn);
4729             removeEditor();
4730         }
4731     }
4732 
4733     /**
4734      * Invoked when editing is canceled. The editor object is discarded
4735      * and the cell is rendered once again.
4736      * <p>
4737      * Application code will not use these methods explicitly, they
4738      * are used internally by JTable.
4739      *
4740      * @param  e  the event received
4741      * @see CellEditorListener
4742      */
editingCanceled(ChangeEvent e)4743     public void editingCanceled(ChangeEvent e) {
4744         removeEditor();
4745     }
4746 
4747 //
4748 // Implementing the Scrollable interface
4749 //
4750 
4751     /**
4752      * Sets the preferred size of the viewport for this table.
4753      *
4754      * @param size  a <code>Dimension</code> object specifying the <code>preferredSize</code> of a
4755      *              <code>JViewport</code> whose view is this table
4756      * @see Scrollable#getPreferredScrollableViewportSize
4757      */
4758     @BeanProperty(bound = false, description
4759             = "The preferred size of the viewport.")
setPreferredScrollableViewportSize(Dimension size)4760     public void setPreferredScrollableViewportSize(Dimension size) {
4761         preferredViewportSize = size;
4762     }
4763 
4764     /**
4765      * Returns the preferred size of the viewport for this table.
4766      *
4767      * @return a <code>Dimension</code> object containing the <code>preferredSize</code> of the <code>JViewport</code>
4768      *         which displays this table
4769      * @see Scrollable#getPreferredScrollableViewportSize
4770      */
getPreferredScrollableViewportSize()4771     public Dimension getPreferredScrollableViewportSize() {
4772         return preferredViewportSize;
4773     }
4774 
4775     /**
4776      * Returns the scroll increment (in pixels) that completely exposes one new
4777      * row or column (depending on the orientation).
4778      * <p>
4779      * This method is called each time the user requests a unit scroll.
4780      *
4781      * @param visibleRect the view area visible within the viewport
4782      * @param orientation either <code>SwingConstants.VERTICAL</code>
4783      *                  or <code>SwingConstants.HORIZONTAL</code>
4784      * @param direction less than zero to scroll up/left,
4785      *                  greater than zero for down/right
4786      * @return the "unit" increment for scrolling in the specified direction
4787      * @see Scrollable#getScrollableUnitIncrement
4788      */
getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)4789     public int getScrollableUnitIncrement(Rectangle visibleRect,
4790                                           int orientation,
4791                                           int direction) {
4792         int leadingRow;
4793         int leadingCol;
4794         Rectangle leadingCellRect;
4795 
4796         int leadingVisibleEdge;
4797         int leadingCellEdge;
4798         int leadingCellSize;
4799 
4800         leadingRow = getLeadingRow(visibleRect);
4801         leadingCol = getLeadingCol(visibleRect);
4802         if (orientation == SwingConstants.VERTICAL && leadingRow < 0) {
4803             // Couldn't find leading row - return some default value
4804             return getRowHeight();
4805         }
4806         else if (orientation == SwingConstants.HORIZONTAL && leadingCol < 0) {
4807             // Couldn't find leading col - return some default value
4808             return 100;
4809         }
4810 
4811         // Note that it's possible for one of leadingCol or leadingRow to be
4812         // -1, depending on the orientation.  This is okay, as getCellRect()
4813         // still provides enough information to calculate the unit increment.
4814         leadingCellRect = getCellRect(leadingRow, leadingCol, true);
4815         leadingVisibleEdge = leadingEdge(visibleRect, orientation);
4816         leadingCellEdge = leadingEdge(leadingCellRect, orientation);
4817 
4818         if (orientation == SwingConstants.VERTICAL) {
4819             leadingCellSize = leadingCellRect.height;
4820 
4821         }
4822         else {
4823             leadingCellSize = leadingCellRect.width;
4824         }
4825 
4826         // 4 cases:
4827         // #1: Leading cell fully visible, reveal next cell
4828         // #2: Leading cell fully visible, hide leading cell
4829         // #3: Leading cell partially visible, hide rest of leading cell
4830         // #4: Leading cell partially visible, reveal rest of leading cell
4831 
4832         if (leadingVisibleEdge == leadingCellEdge) { // Leading cell is fully
4833                                                      // visible
4834             // Case #1: Reveal previous cell
4835             if (direction < 0) {
4836                 int retVal = 0;
4837 
4838                 if (orientation == SwingConstants.VERTICAL) {
4839                     // Loop past any zero-height rows
4840                     while (--leadingRow >= 0) {
4841                         retVal = getRowHeight(leadingRow);
4842                         if (retVal != 0) {
4843                             break;
4844                         }
4845                     }
4846                 }
4847                 else { // HORIZONTAL
4848                     // Loop past any zero-width cols
4849                     while (--leadingCol >= 0) {
4850                         retVal = getCellRect(leadingRow, leadingCol, true).width;
4851                         if (retVal != 0) {
4852                             break;
4853                         }
4854                     }
4855                 }
4856                 return retVal;
4857             }
4858             else { // Case #2: hide leading cell
4859                 return leadingCellSize;
4860             }
4861         }
4862         else { // Leading cell is partially hidden
4863             // Compute visible, hidden portions
4864             int hiddenAmt = Math.abs(leadingVisibleEdge - leadingCellEdge);
4865             int visibleAmt = leadingCellSize - hiddenAmt;
4866 
4867             if (direction > 0) {
4868                 // Case #3: hide showing portion of leading cell
4869                 return visibleAmt;
4870             }
4871             else { // Case #4: reveal hidden portion of leading cell
4872                 return hiddenAmt;
4873             }
4874         }
4875     }
4876 
4877     /**
4878      * Returns <code>visibleRect.height</code> or
4879      * <code>visibleRect.width</code>,
4880      * depending on this table's orientation.  Note that as of Swing 1.1.1
4881      * (Java 2 v 1.2.2) the value
4882      * returned will ensure that the viewport is cleanly aligned on
4883      * a row boundary.
4884      *
4885      * @return <code>visibleRect.height</code> or
4886      *                                  <code>visibleRect.width</code>
4887      *                                  per the orientation
4888      * @see Scrollable#getScrollableBlockIncrement
4889      */
getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)4890     public int getScrollableBlockIncrement(Rectangle visibleRect,
4891             int orientation, int direction) {
4892 
4893         if (getRowCount() == 0) {
4894             // Short-circuit empty table model
4895             if (SwingConstants.VERTICAL == orientation) {
4896                 int rh = getRowHeight();
4897                 return (rh > 0) ? Math.max(rh, (visibleRect.height / rh) * rh) :
4898                                   visibleRect.height;
4899             }
4900             else {
4901                 return visibleRect.width;
4902             }
4903         }
4904         // Shortcut for vertical scrolling of a table w/ uniform row height
4905         if (null == rowModel && SwingConstants.VERTICAL == orientation) {
4906             int row = rowAtPoint(visibleRect.getLocation());
4907             assert row != -1;
4908             int col = columnAtPoint(visibleRect.getLocation());
4909             Rectangle cellRect = getCellRect(row, col, true);
4910 
4911             if (cellRect.y == visibleRect.y) {
4912                 int rh = getRowHeight();
4913                 assert rh > 0;
4914                 return Math.max(rh, (visibleRect.height / rh) * rh);
4915             }
4916         }
4917         if (direction < 0) {
4918             return getPreviousBlockIncrement(visibleRect, orientation);
4919         }
4920         else {
4921             return getNextBlockIncrement(visibleRect, orientation);
4922         }
4923     }
4924 
4925     /**
4926      * Called to get the block increment for upward scrolling in cases of
4927      * horizontal scrolling, or for vertical scrolling of a table with
4928      * variable row heights.
4929      */
getPreviousBlockIncrement(Rectangle visibleRect, int orientation)4930     private int getPreviousBlockIncrement(Rectangle visibleRect,
4931                                           int orientation) {
4932         // Measure back from visible leading edge
4933         // If we hit the cell on its leading edge, it becomes the leading cell.
4934         // Else, use following cell
4935 
4936         int row;
4937         int col;
4938 
4939         int   newEdge;
4940         Point newCellLoc;
4941 
4942         int visibleLeadingEdge = leadingEdge(visibleRect, orientation);
4943         boolean leftToRight = getComponentOrientation().isLeftToRight();
4944         int newLeadingEdge;
4945 
4946         // Roughly determine the new leading edge by measuring back from the
4947         // leading visible edge by the size of the visible rect, and find the
4948         // cell there.
4949         if (orientation == SwingConstants.VERTICAL) {
4950             newEdge = visibleLeadingEdge - visibleRect.height;
4951             int x = visibleRect.x + (leftToRight ? 0 : visibleRect.width);
4952             newCellLoc = new Point(x, newEdge);
4953         }
4954         else if (leftToRight) {
4955             newEdge = visibleLeadingEdge - visibleRect.width;
4956             newCellLoc = new Point(newEdge, visibleRect.y);
4957         }
4958         else { // Horizontal, right-to-left
4959             newEdge = visibleLeadingEdge + visibleRect.width;
4960             newCellLoc = new Point(newEdge - 1, visibleRect.y);
4961         }
4962         row = rowAtPoint(newCellLoc);
4963         col = columnAtPoint(newCellLoc);
4964 
4965         // If we're measuring past the beginning of the table, we get an invalid
4966         // cell.  Just go to the beginning of the table in this case.
4967         if (orientation == SwingConstants.VERTICAL & row < 0) {
4968             newLeadingEdge = 0;
4969         }
4970         else if (orientation == SwingConstants.HORIZONTAL & col < 0) {
4971             if (leftToRight) {
4972                 newLeadingEdge = 0;
4973             }
4974             else {
4975                 newLeadingEdge = getWidth();
4976             }
4977         }
4978         else {
4979             // Refine our measurement
4980             Rectangle newCellRect = getCellRect(row, col, true);
4981             int newCellLeadingEdge = leadingEdge(newCellRect, orientation);
4982             int newCellTrailingEdge = trailingEdge(newCellRect, orientation);
4983 
4984             // Usually, we hit in the middle of newCell, and want to scroll to
4985             // the beginning of the cell after newCell.  But there are a
4986             // couple corner cases where we want to scroll to the beginning of
4987             // newCell itself.  These cases are:
4988             // 1) newCell is so large that it ends at or extends into the
4989             //    visibleRect (newCell is the leading cell, or is adjacent to
4990             //    the leading cell)
4991             // 2) newEdge happens to fall right on the beginning of a cell
4992 
4993             // Case 1
4994             if ((orientation == SwingConstants.VERTICAL || leftToRight) &&
4995                 (newCellTrailingEdge >= visibleLeadingEdge)) {
4996                 newLeadingEdge = newCellLeadingEdge;
4997             }
4998             else if (orientation == SwingConstants.HORIZONTAL &&
4999                      !leftToRight &&
5000                      newCellTrailingEdge <= visibleLeadingEdge) {
5001                 newLeadingEdge = newCellLeadingEdge;
5002             }
5003             // Case 2:
5004             else if (newEdge == newCellLeadingEdge) {
5005                 newLeadingEdge = newCellLeadingEdge;
5006             }
5007             // Common case: scroll to cell after newCell
5008             else {
5009                 newLeadingEdge = newCellTrailingEdge;
5010             }
5011         }
5012         return Math.abs(visibleLeadingEdge - newLeadingEdge);
5013     }
5014 
5015     /**
5016      * Called to get the block increment for downward scrolling in cases of
5017      * horizontal scrolling, or for vertical scrolling of a table with
5018      * variable row heights.
5019      */
getNextBlockIncrement(Rectangle visibleRect, int orientation)5020     private int getNextBlockIncrement(Rectangle visibleRect,
5021                                       int orientation) {
5022         // Find the cell at the trailing edge.  Return the distance to put
5023         // that cell at the leading edge.
5024         int trailingRow = getTrailingRow(visibleRect);
5025         int trailingCol = getTrailingCol(visibleRect);
5026 
5027         Rectangle cellRect;
5028         boolean cellFillsVis;
5029 
5030         int cellLeadingEdge;
5031         int cellTrailingEdge;
5032         int newLeadingEdge;
5033         int visibleLeadingEdge = leadingEdge(visibleRect, orientation);
5034 
5035         // If we couldn't find trailing cell, just return the size of the
5036         // visibleRect.  Note that, for instance, we don't need the
5037         // trailingCol to proceed if we're scrolling vertically, because
5038         // cellRect will still fill in the required dimensions.  This would
5039         // happen if we're scrolling vertically, and the table is not wide
5040         // enough to fill the visibleRect.
5041         if (orientation == SwingConstants.VERTICAL && trailingRow < 0) {
5042             return visibleRect.height;
5043         }
5044         else if (orientation == SwingConstants.HORIZONTAL && trailingCol < 0) {
5045             return visibleRect.width;
5046         }
5047         cellRect = getCellRect(trailingRow, trailingCol, true);
5048         cellLeadingEdge = leadingEdge(cellRect, orientation);
5049         cellTrailingEdge = trailingEdge(cellRect, orientation);
5050 
5051         if (orientation == SwingConstants.VERTICAL ||
5052             getComponentOrientation().isLeftToRight()) {
5053             cellFillsVis = cellLeadingEdge <= visibleLeadingEdge;
5054         }
5055         else { // Horizontal, right-to-left
5056             cellFillsVis = cellLeadingEdge >= visibleLeadingEdge;
5057         }
5058 
5059         if (cellFillsVis) {
5060             // The visibleRect contains a single large cell.  Scroll to the end
5061             // of this cell, so the following cell is the first cell.
5062             newLeadingEdge = cellTrailingEdge;
5063         }
5064         else if (cellTrailingEdge == trailingEdge(visibleRect, orientation)) {
5065             // The trailing cell happens to end right at the end of the
5066             // visibleRect.  Again, scroll to the beginning of the next cell.
5067             newLeadingEdge = cellTrailingEdge;
5068         }
5069         else {
5070             // Common case: the trailing cell is partially visible, and isn't
5071             // big enough to take up the entire visibleRect.  Scroll so it
5072             // becomes the leading cell.
5073             newLeadingEdge = cellLeadingEdge;
5074         }
5075         return Math.abs(newLeadingEdge - visibleLeadingEdge);
5076     }
5077 
5078     /*
5079      * Return the row at the top of the visibleRect
5080      *
5081      * May return -1
5082      */
getLeadingRow(Rectangle visibleRect)5083     private int getLeadingRow(Rectangle visibleRect) {
5084         Point leadingPoint;
5085 
5086         if (getComponentOrientation().isLeftToRight()) {
5087             leadingPoint = new Point(visibleRect.x, visibleRect.y);
5088         }
5089         else {
5090             leadingPoint = new Point(visibleRect.x + visibleRect.width - 1,
5091                                      visibleRect.y);
5092         }
5093         return rowAtPoint(leadingPoint);
5094     }
5095 
5096     /*
5097      * Return the column at the leading edge of the visibleRect.
5098      *
5099      * May return -1
5100      */
getLeadingCol(Rectangle visibleRect)5101     private int getLeadingCol(Rectangle visibleRect) {
5102         Point leadingPoint;
5103 
5104         if (getComponentOrientation().isLeftToRight()) {
5105             leadingPoint = new Point(visibleRect.x, visibleRect.y);
5106         }
5107         else {
5108             leadingPoint = new Point(visibleRect.x + visibleRect.width - 1,
5109                                      visibleRect.y);
5110         }
5111         return columnAtPoint(leadingPoint);
5112     }
5113 
5114     /*
5115      * Return the row at the bottom of the visibleRect.
5116      *
5117      * May return -1
5118      */
getTrailingRow(Rectangle visibleRect)5119     private int getTrailingRow(Rectangle visibleRect) {
5120         Point trailingPoint;
5121 
5122         if (getComponentOrientation().isLeftToRight()) {
5123             trailingPoint = new Point(visibleRect.x,
5124                                       visibleRect.y + visibleRect.height - 1);
5125         }
5126         else {
5127             trailingPoint = new Point(visibleRect.x + visibleRect.width - 1,
5128                                       visibleRect.y + visibleRect.height - 1);
5129         }
5130         return rowAtPoint(trailingPoint);
5131     }
5132 
5133     /*
5134      * Return the column at the trailing edge of the visibleRect.
5135      *
5136      * May return -1
5137      */
getTrailingCol(Rectangle visibleRect)5138     private int getTrailingCol(Rectangle visibleRect) {
5139         Point trailingPoint;
5140 
5141         if (getComponentOrientation().isLeftToRight()) {
5142             trailingPoint = new Point(visibleRect.x + visibleRect.width - 1,
5143                                       visibleRect.y);
5144         }
5145         else {
5146             trailingPoint = new Point(visibleRect.x, visibleRect.y);
5147         }
5148         return columnAtPoint(trailingPoint);
5149     }
5150 
5151     /*
5152      * Returns the leading edge ("beginning") of the given Rectangle.
5153      * For VERTICAL, this is the top, for left-to-right, the left side, and for
5154      * right-to-left, the right side.
5155      */
leadingEdge(Rectangle rect, int orientation)5156     private int leadingEdge(Rectangle rect, int orientation) {
5157         if (orientation == SwingConstants.VERTICAL) {
5158             return rect.y;
5159         }
5160         else if (getComponentOrientation().isLeftToRight()) {
5161             return rect.x;
5162         }
5163         else { // Horizontal, right-to-left
5164             return rect.x + rect.width;
5165         }
5166     }
5167 
5168     /*
5169      * Returns the trailing edge ("end") of the given Rectangle.
5170      * For VERTICAL, this is the bottom, for left-to-right, the right side, and
5171      * for right-to-left, the left side.
5172      */
trailingEdge(Rectangle rect, int orientation)5173     private int trailingEdge(Rectangle rect, int orientation) {
5174         if (orientation == SwingConstants.VERTICAL) {
5175             return rect.y + rect.height;
5176         }
5177         else if (getComponentOrientation().isLeftToRight()) {
5178             return rect.x + rect.width;
5179         }
5180         else { // Horizontal, right-to-left
5181             return rect.x;
5182         }
5183     }
5184 
5185     /**
5186      * Returns false if <code>autoResizeMode</code> is set to
5187      * <code>AUTO_RESIZE_OFF</code>, which indicates that the
5188      * width of the viewport does not determine the width
5189      * of the table.  Otherwise returns true.
5190      *
5191      * @return false if <code>autoResizeMode</code> is set
5192      *   to <code>AUTO_RESIZE_OFF</code>, otherwise returns true
5193      * @see Scrollable#getScrollableTracksViewportWidth
5194      */
5195     @BeanProperty(bound = false)
getScrollableTracksViewportWidth()5196     public boolean getScrollableTracksViewportWidth() {
5197         return !(autoResizeMode == AUTO_RESIZE_OFF);
5198     }
5199 
5200     /**
5201      * Returns {@code false} to indicate that the height of the viewport does
5202      * not determine the height of the table, unless
5203      * {@code getFillsViewportHeight} is {@code true} and the preferred height
5204      * of the table is smaller than the viewport's height.
5205      *
5206      * @return {@code false} unless {@code getFillsViewportHeight} is
5207      *         {@code true} and the table needs to be stretched to fill
5208      *         the viewport
5209      * @see Scrollable#getScrollableTracksViewportHeight
5210      * @see #setFillsViewportHeight
5211      * @see #getFillsViewportHeight
5212      */
5213     @BeanProperty(bound = false)
getScrollableTracksViewportHeight()5214     public boolean getScrollableTracksViewportHeight() {
5215         Container parent = SwingUtilities.getUnwrappedParent(this);
5216         return getFillsViewportHeight()
5217                && parent instanceof JViewport
5218                && parent.getHeight() > getPreferredSize().height;
5219     }
5220 
5221     /**
5222      * Sets whether or not this table is always made large enough
5223      * to fill the height of an enclosing viewport. If the preferred
5224      * height of the table is smaller than the viewport, then the table
5225      * will be stretched to fill the viewport. In other words, this
5226      * ensures the table is never smaller than the viewport.
5227      * The default for this property is {@code false}.
5228      *
5229      * @param fillsViewportHeight whether or not this table is always
5230      *        made large enough to fill the height of an enclosing
5231      *        viewport
5232      * @see #getFillsViewportHeight
5233      * @see #getScrollableTracksViewportHeight
5234      * @since 1.6
5235      */
5236     @BeanProperty(description
5237             = "Whether or not this table is always made large enough to fill the height of an enclosing viewport")
setFillsViewportHeight(boolean fillsViewportHeight)5238     public void setFillsViewportHeight(boolean fillsViewportHeight) {
5239         boolean old = this.fillsViewportHeight;
5240         this.fillsViewportHeight = fillsViewportHeight;
5241         resizeAndRepaint();
5242         firePropertyChange("fillsViewportHeight", old, fillsViewportHeight);
5243     }
5244 
5245     /**
5246      * Returns whether or not this table is always made large enough
5247      * to fill the height of an enclosing viewport.
5248      *
5249      * @return whether or not this table is always made large enough
5250      *         to fill the height of an enclosing viewport
5251      * @see #setFillsViewportHeight
5252      * @since 1.6
5253      */
getFillsViewportHeight()5254     public boolean getFillsViewportHeight() {
5255         return fillsViewportHeight;
5256     }
5257 
5258 //
5259 // Protected Methods
5260 //
5261 
processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed)5262     protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
5263                                         int condition, boolean pressed) {
5264         boolean retValue = super.processKeyBinding(ks, e, condition, pressed);
5265 
5266         // Start editing when a key is typed. UI classes can disable this behavior
5267         // by setting the client property JTable.autoStartsEdit to Boolean.FALSE.
5268         if (!retValue && condition == WHEN_ANCESTOR_OF_FOCUSED_COMPONENT &&
5269             isFocusOwner() &&
5270             !Boolean.FALSE.equals(getClientProperty("JTable.autoStartsEdit"))) {
5271             // We do not have a binding for the event.
5272             Component editorComponent = getEditorComponent();
5273             if (editorComponent == null) {
5274                 // Only attempt to install the editor on a KEY_PRESSED,
5275                 if (e == null || e.getID() != KeyEvent.KEY_PRESSED) {
5276                     return false;
5277                 }
5278                 // Don't start when just a modifier is pressed
5279                 int code = e.getKeyCode();
5280                 if (code == KeyEvent.VK_SHIFT || code == KeyEvent.VK_CONTROL ||
5281                     code == KeyEvent.VK_ALT || code == KeyEvent.VK_META ||
5282                     code == KeyEvent.VK_ALT_GRAPH) {
5283                     return false;
5284                 }
5285                 // Try to install the editor
5286                 int leadRow = getSelectionModel().getLeadSelectionIndex();
5287                 int leadColumn = getColumnModel().getSelectionModel().
5288                                    getLeadSelectionIndex();
5289                 if (leadRow != -1 && leadColumn != -1 && !isEditing()) {
5290                     if (!editCellAt(leadRow, leadColumn, e)) {
5291                         return false;
5292                     }
5293                 }
5294                 editorComponent = getEditorComponent();
5295                 if (editorComponent == null) {
5296                     return false;
5297                 }
5298             }
5299             // If the editorComponent is a JComponent, pass the event to it.
5300             if (editorComponent instanceof JComponent) {
5301                 retValue = ((JComponent)editorComponent).processKeyBinding
5302                                         (ks, e, WHEN_FOCUSED, pressed);
5303                 // If we have started an editor as a result of the user
5304                 // pressing a key and the surrendersFocusOnKeystroke property
5305                 // is true, give the focus to the new editor.
5306                 Object prop = getClientProperty("JTable.forceAutoStartsEdit");
5307                 if (getSurrendersFocusOnKeystroke()
5308                         || Boolean.TRUE.equals(prop)) {
5309                     editorComponent.requestFocus();
5310                 }
5311             }
5312         }
5313         return retValue;
5314     }
5315 
5316     /**
5317      * Creates default cell renderers for objects, numbers, doubles, dates,
5318      * booleans, and icons.
5319      * @see javax.swing.table.DefaultTableCellRenderer
5320      *
5321      */
createDefaultRenderers()5322     protected void createDefaultRenderers() {
5323         defaultRenderersByColumnClass = new UIDefaults(8, 0.75f);
5324 
5325         // Objects
5326         defaultRenderersByColumnClass.put(Object.class, (UIDefaults.LazyValue)
5327                 t -> new DefaultTableCellRenderer.UIResource());
5328 
5329         // Numbers
5330         defaultRenderersByColumnClass.put(Number.class, (UIDefaults.LazyValue)
5331                 t -> new NumberRenderer());
5332 
5333         // Doubles and Floats
5334         defaultRenderersByColumnClass.put(Float.class, (UIDefaults.LazyValue)
5335                 t -> new DoubleRenderer());
5336         defaultRenderersByColumnClass.put(Double.class, (UIDefaults.LazyValue)
5337                 t -> new DoubleRenderer());
5338 
5339         // Dates
5340         defaultRenderersByColumnClass.put(Date.class, (UIDefaults.LazyValue)
5341                 t -> new DateRenderer());
5342 
5343         // Icons and ImageIcons
5344         defaultRenderersByColumnClass.put(Icon.class, (UIDefaults.LazyValue)
5345                 t -> new IconRenderer());
5346         defaultRenderersByColumnClass.put(ImageIcon.class, (UIDefaults.LazyValue)
5347                 t -> new IconRenderer());
5348 
5349         // Booleans
5350         defaultRenderersByColumnClass.put(Boolean.class, (UIDefaults.LazyValue)
5351                 t -> new BooleanRenderer());
5352     }
5353 
5354     /**
5355      * Default Renderers
5356      **/
5357     static class NumberRenderer extends DefaultTableCellRenderer.UIResource {
NumberRenderer()5358         public NumberRenderer() {
5359             super();
5360             setHorizontalAlignment(JLabel.RIGHT);
5361         }
5362     }
5363 
5364     static class DoubleRenderer extends NumberRenderer {
5365         NumberFormat formatter;
DoubleRenderer()5366         public DoubleRenderer() { super(); }
5367 
setValue(Object value)5368         public void setValue(Object value) {
5369             if (formatter == null) {
5370                 formatter = NumberFormat.getInstance();
5371             }
5372             setText((value == null) ? "" : formatter.format(value));
5373         }
5374     }
5375 
5376     static class DateRenderer extends DefaultTableCellRenderer.UIResource {
5377         DateFormat formatter;
DateRenderer()5378         public DateRenderer() { super(); }
5379 
setValue(Object value)5380         public void setValue(Object value) {
5381             if (formatter==null) {
5382                 formatter = DateFormat.getDateInstance();
5383             }
5384             setText((value == null) ? "" : formatter.format(value));
5385         }
5386     }
5387 
5388     static class IconRenderer extends DefaultTableCellRenderer.UIResource {
IconRenderer()5389         public IconRenderer() {
5390             super();
5391             setHorizontalAlignment(JLabel.CENTER);
5392         }
setValue(Object value)5393         public void setValue(Object value) { setIcon((value instanceof Icon) ? (Icon)value : null); }
5394     }
5395 
5396 
5397     static class BooleanRenderer extends JCheckBox implements TableCellRenderer, UIResource
5398     {
5399         private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
5400 
BooleanRenderer()5401         public BooleanRenderer() {
5402             super();
5403             setHorizontalAlignment(JLabel.CENTER);
5404             setBorderPainted(true);
5405         }
5406 
getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)5407         public Component getTableCellRendererComponent(JTable table, Object value,
5408                                                        boolean isSelected, boolean hasFocus, int row, int column) {
5409             if (isSelected) {
5410                 setForeground(table.getSelectionForeground());
5411                 super.setBackground(table.getSelectionBackground());
5412             }
5413             else {
5414                 setForeground(table.getForeground());
5415                 setBackground(table.getBackground());
5416             }
5417             setSelected((value != null && ((Boolean)value).booleanValue()));
5418 
5419             if (hasFocus) {
5420                 setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
5421             } else {
5422                 setBorder(noFocusBorder);
5423             }
5424 
5425             return this;
5426         }
5427     }
5428 
5429     /**
5430      * Creates default cell editors for objects, numbers, and boolean values.
5431      * @see DefaultCellEditor
5432      */
createDefaultEditors()5433     protected void createDefaultEditors() {
5434         defaultEditorsByColumnClass = new UIDefaults(3, 0.75f);
5435 
5436         // Objects
5437         defaultEditorsByColumnClass.put(Object.class, (UIDefaults.LazyValue)
5438                 t -> new GenericEditor());
5439 
5440         // Numbers
5441         defaultEditorsByColumnClass.put(Number.class, (UIDefaults.LazyValue)
5442                 t -> new NumberEditor());
5443 
5444         // Booleans
5445         defaultEditorsByColumnClass.put(Boolean.class, (UIDefaults.LazyValue)
5446                 t -> new BooleanEditor());
5447     }
5448 
5449     /**
5450      * Default Editors
5451      */
5452     static class GenericEditor extends DefaultCellEditor {
5453 
5454         Class<?>[] argTypes = new Class<?>[]{String.class};
5455         java.lang.reflect.Constructor<?> constructor;
5456         Object value;
5457 
GenericEditor()5458         public GenericEditor() {
5459             super(new JTextField());
5460             getComponent().setName("Table.editor");
5461         }
5462 
stopCellEditing()5463         public boolean stopCellEditing() {
5464             String s = (String)super.getCellEditorValue();
5465             // Here we are dealing with the case where a user
5466             // has deleted the string value in a cell, possibly
5467             // after a failed validation. Return null, so that
5468             // they have the option to replace the value with
5469             // null or use escape to restore the original.
5470             // For Strings, return "" for backward compatibility.
5471             try {
5472                 if ("".equals(s)) {
5473                     if (constructor.getDeclaringClass() == String.class) {
5474                         value = s;
5475                     }
5476                     return super.stopCellEditing();
5477                 }
5478 
5479                 SwingUtilities2.checkAccess(constructor.getModifiers());
5480                 value = constructor.newInstance(new Object[]{s});
5481             }
5482             catch (Exception e) {
5483                 ((JComponent)getComponent()).setBorder(new LineBorder(Color.red));
5484                 return false;
5485             }
5486             return super.stopCellEditing();
5487         }
5488 
getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)5489         public Component getTableCellEditorComponent(JTable table, Object value,
5490                                                  boolean isSelected,
5491                                                  int row, int column) {
5492             this.value = null;
5493             ((JComponent)getComponent()).setBorder(new LineBorder(Color.black));
5494             try {
5495                 Class<?> type = table.getColumnClass(column);
5496                 // Since our obligation is to produce a value which is
5497                 // assignable for the required type it is OK to use the
5498                 // String constructor for columns which are declared
5499                 // to contain Objects. A String is an Object.
5500                 if (type == Object.class) {
5501                     type = String.class;
5502                 }
5503                 ReflectUtil.checkPackageAccess(type);
5504                 SwingUtilities2.checkAccess(type.getModifiers());
5505                 constructor = type.getConstructor(argTypes);
5506             }
5507             catch (Exception e) {
5508                 return null;
5509             }
5510             return super.getTableCellEditorComponent(table, value, isSelected, row, column);
5511         }
5512 
getCellEditorValue()5513         public Object getCellEditorValue() {
5514             return value;
5515         }
5516     }
5517 
5518     static class NumberEditor extends GenericEditor {
5519 
NumberEditor()5520         public NumberEditor() {
5521             ((JTextField)getComponent()).setHorizontalAlignment(JTextField.RIGHT);
5522         }
5523     }
5524 
5525     static class BooleanEditor extends DefaultCellEditor {
BooleanEditor()5526         public BooleanEditor() {
5527             super(new JCheckBox());
5528             JCheckBox checkBox = (JCheckBox)getComponent();
5529             checkBox.setHorizontalAlignment(JCheckBox.CENTER);
5530         }
5531     }
5532 
5533     /**
5534      * Initializes table properties to their default values.
5535      */
initializeLocalVars()5536     protected void initializeLocalVars() {
5537         updateSelectionOnSort = true;
5538         setOpaque(true);
5539         createDefaultRenderers();
5540         createDefaultEditors();
5541 
5542         setTableHeader(createDefaultTableHeader());
5543 
5544         setShowGrid(true);
5545         setAutoResizeMode(AUTO_RESIZE_SUBSEQUENT_COLUMNS);
5546         setRowHeight(16);
5547         isRowHeightSet = false;
5548         setRowMargin(1);
5549         setRowSelectionAllowed(true);
5550         setCellEditor(null);
5551         setEditingColumn(-1);
5552         setEditingRow(-1);
5553         setSurrendersFocusOnKeystroke(false);
5554         setPreferredScrollableViewportSize(new Dimension(450, 400));
5555 
5556         // I'm registered to do tool tips so we can draw tips for the renderers
5557         ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
5558         toolTipManager.registerComponent(this);
5559 
5560         setAutoscrolls(true);
5561     }
5562 
5563     /**
5564      * Returns the default table model object, which is
5565      * a <code>DefaultTableModel</code>.  A subclass can override this
5566      * method to return a different table model object.
5567      *
5568      * @return the default table model object
5569      * @see javax.swing.table.DefaultTableModel
5570      */
createDefaultDataModel()5571     protected TableModel createDefaultDataModel() {
5572         return new DefaultTableModel();
5573     }
5574 
5575     /**
5576      * Returns the default column model object, which is
5577      * a <code>DefaultTableColumnModel</code>.  A subclass can override this
5578      * method to return a different column model object.
5579      *
5580      * @return the default column model object
5581      * @see javax.swing.table.DefaultTableColumnModel
5582      */
createDefaultColumnModel()5583     protected TableColumnModel createDefaultColumnModel() {
5584         return new DefaultTableColumnModel();
5585     }
5586 
5587     /**
5588      * Returns the default selection model object, which is
5589      * a <code>DefaultListSelectionModel</code>.  A subclass can override this
5590      * method to return a different selection model object.
5591      *
5592      * @return the default selection model object
5593      * @see javax.swing.DefaultListSelectionModel
5594      */
createDefaultSelectionModel()5595     protected ListSelectionModel createDefaultSelectionModel() {
5596         return new DefaultListSelectionModel();
5597     }
5598 
5599     /**
5600      * Returns the default table header object, which is
5601      * a <code>JTableHeader</code>.  A subclass can override this
5602      * method to return a different table header object.
5603      *
5604      * @return the default table header object
5605      * @see javax.swing.table.JTableHeader
5606      */
createDefaultTableHeader()5607     protected JTableHeader createDefaultTableHeader() {
5608         return new JTableHeader(columnModel);
5609     }
5610 
5611     /**
5612      * Equivalent to <code>revalidate</code> followed by <code>repaint</code>.
5613      */
resizeAndRepaint()5614     protected void resizeAndRepaint() {
5615         revalidate();
5616         repaint();
5617     }
5618 
5619     /**
5620      * Returns the active cell editor, which is {@code null} if the table
5621      * is not currently editing.
5622      *
5623      * @return the {@code TableCellEditor} that does the editing,
5624      *         or {@code null} if the table is not currently editing.
5625      * @see #cellEditor
5626      * @see #getCellEditor(int, int)
5627      */
getCellEditor()5628     public TableCellEditor getCellEditor() {
5629         return cellEditor;
5630     }
5631 
5632     /**
5633      * Sets the active cell editor.
5634      *
5635      * @param anEditor the active cell editor
5636      * @see #cellEditor
5637      */
5638     @BeanProperty(description
5639             = "The table's active cell editor.")
setCellEditor(TableCellEditor anEditor)5640     public void setCellEditor(TableCellEditor anEditor) {
5641         TableCellEditor oldEditor = cellEditor;
5642         cellEditor = anEditor;
5643         firePropertyChange("tableCellEditor", oldEditor, anEditor);
5644     }
5645 
5646     /**
5647      * Sets the <code>editingColumn</code> variable.
5648      * @param aColumn  the column of the cell to be edited
5649      *
5650      * @see #editingColumn
5651      */
setEditingColumn(int aColumn)5652     public void setEditingColumn(int aColumn) {
5653         editingColumn = aColumn;
5654     }
5655 
5656     /**
5657      * Sets the <code>editingRow</code> variable.
5658      * @param aRow  the row of the cell to be edited
5659      *
5660      * @see #editingRow
5661      */
setEditingRow(int aRow)5662     public void setEditingRow(int aRow) {
5663         editingRow = aRow;
5664     }
5665 
5666     /**
5667      * Returns an appropriate renderer for the cell specified by this row and
5668      * column. If the <code>TableColumn</code> for this column has a non-null
5669      * renderer, returns that.  If not, finds the class of the data in
5670      * this column (using <code>getColumnClass</code>)
5671      * and returns the default renderer for this type of data.
5672      * <p>
5673      * <b>Note:</b>
5674      * Throughout the table package, the internal implementations always
5675      * use this method to provide renderers so that this default behavior
5676      * can be safely overridden by a subclass.
5677      *
5678      * @param row       the row of the cell to render, where 0 is the first row
5679      * @param column    the column of the cell to render,
5680      *                  where 0 is the first column
5681      * @return the assigned renderer; if <code>null</code>
5682      *                  returns the default renderer
5683      *                  for this type of object
5684      * @see javax.swing.table.DefaultTableCellRenderer
5685      * @see javax.swing.table.TableColumn#setCellRenderer
5686      * @see #setDefaultRenderer
5687      */
getCellRenderer(int row, int column)5688     public TableCellRenderer getCellRenderer(int row, int column) {
5689         TableColumn tableColumn = getColumnModel().getColumn(column);
5690         TableCellRenderer renderer = tableColumn.getCellRenderer();
5691         if (renderer == null) {
5692             renderer = getDefaultRenderer(getColumnClass(column));
5693         }
5694         return renderer;
5695     }
5696 
5697     /**
5698      * Prepares the renderer by querying the data model for the
5699      * value and selection state
5700      * of the cell at <code>row</code>, <code>column</code>.
5701      * Returns the component (may be a <code>Component</code>
5702      * or a <code>JComponent</code>) under the event location.
5703      * <p>
5704      * During a printing operation, this method will configure the
5705      * renderer without indicating selection or focus, to prevent
5706      * them from appearing in the printed output. To do other
5707      * customizations based on whether or not the table is being
5708      * printed, you can check the value of
5709      * {@link javax.swing.JComponent#isPaintingForPrint()}, either here
5710      * or within custom renderers.
5711      * <p>
5712      * <b>Note:</b>
5713      * Throughout the table package, the internal implementations always
5714      * use this method to prepare renderers so that this default behavior
5715      * can be safely overridden by a subclass.
5716      *
5717      * @param renderer  the <code>TableCellRenderer</code> to prepare
5718      * @param row       the row of the cell to render, where 0 is the first row
5719      * @param column    the column of the cell to render,
5720      *                  where 0 is the first column
5721      * @return          the <code>Component</code> under the event location
5722      */
prepareRenderer(TableCellRenderer renderer, int row, int column)5723     public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
5724         Object value = getValueAt(row, column);
5725 
5726         boolean isSelected = false;
5727         boolean hasFocus = false;
5728 
5729         // Only indicate the selection and focused cell if not printing
5730         if (!isPaintingForPrint()) {
5731             isSelected = isCellSelected(row, column);
5732 
5733             boolean rowIsLead =
5734                 (selectionModel.getLeadSelectionIndex() == row);
5735             boolean colIsLead =
5736                 (columnModel.getSelectionModel().getLeadSelectionIndex() == column);
5737 
5738             hasFocus = (rowIsLead && colIsLead) && isFocusOwner();
5739         }
5740 
5741         return renderer.getTableCellRendererComponent(this, value,
5742                                                       isSelected, hasFocus,
5743                                                       row, column);
5744     }
5745 
5746     /**
5747      * Returns an appropriate editor for the cell specified by
5748      * <code>row</code> and <code>column</code>. If the
5749      * <code>TableColumn</code> for this column has a non-null editor,
5750      * returns that.  If not, finds the class of the data in this
5751      * column (using <code>getColumnClass</code>)
5752      * and returns the default editor for this type of data.
5753      * <p>
5754      * <b>Note:</b>
5755      * Throughout the table package, the internal implementations always
5756      * use this method to provide editors so that this default behavior
5757      * can be safely overridden by a subclass.
5758      *
5759      * @param row       the row of the cell to edit, where 0 is the first row
5760      * @param column    the column of the cell to edit,
5761      *                  where 0 is the first column
5762      * @return          the editor for this cell;
5763      *                  if <code>null</code> return the default editor for
5764      *                  this type of cell
5765      * @see DefaultCellEditor
5766      */
getCellEditor(int row, int column)5767     public TableCellEditor getCellEditor(int row, int column) {
5768         TableColumn tableColumn = getColumnModel().getColumn(column);
5769         TableCellEditor editor = tableColumn.getCellEditor();
5770         if (editor == null) {
5771             editor = getDefaultEditor(getColumnClass(column));
5772         }
5773         return editor;
5774     }
5775 
5776 
5777     /**
5778      * Prepares the editor by querying the data model for the value and
5779      * selection state of the cell at <code>row</code>, <code>column</code>.
5780      * <p>
5781      * <b>Note:</b>
5782      * Throughout the table package, the internal implementations always
5783      * use this method to prepare editors so that this default behavior
5784      * can be safely overridden by a subclass.
5785      *
5786      * @param editor  the <code>TableCellEditor</code> to set up
5787      * @param row     the row of the cell to edit,
5788      *                where 0 is the first row
5789      * @param column  the column of the cell to edit,
5790      *                where 0 is the first column
5791      * @return the <code>Component</code> being edited
5792      */
5793     @SuppressWarnings("deprecation")
prepareEditor(TableCellEditor editor, int row, int column)5794     public Component prepareEditor(TableCellEditor editor, int row, int column) {
5795         Object value = getValueAt(row, column);
5796         boolean isSelected = isCellSelected(row, column);
5797         Component comp = editor.getTableCellEditorComponent(this, value, isSelected,
5798                                                   row, column);
5799         if (comp instanceof JComponent) {
5800             JComponent jComp = (JComponent)comp;
5801             if (jComp.getNextFocusableComponent() == null) {
5802                 jComp.setNextFocusableComponent(this);
5803             }
5804         }
5805         return comp;
5806     }
5807 
5808     /**
5809      * Discards the editor object and frees the real estate it used for
5810      * cell rendering.
5811      */
removeEditor()5812     public void removeEditor() {
5813         KeyboardFocusManager.getCurrentKeyboardFocusManager().
5814             removePropertyChangeListener("permanentFocusOwner", editorRemover);
5815         editorRemover = null;
5816 
5817         TableCellEditor editor = getCellEditor();
5818         if(editor != null) {
5819             editor.removeCellEditorListener(this);
5820             if (editorComp != null) {
5821                 Component focusOwner =
5822                         KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
5823                 boolean isFocusOwnerInTheTable = focusOwner != null?
5824                         SwingUtilities.isDescendingFrom(focusOwner, this):false;
5825                 remove(editorComp);
5826                 if(isFocusOwnerInTheTable) {
5827                     requestFocusInWindow();
5828                 }
5829             }
5830 
5831             Rectangle cellRect = getCellRect(editingRow, editingColumn, false);
5832 
5833             setCellEditor(null);
5834             setEditingColumn(-1);
5835             setEditingRow(-1);
5836             editorComp = null;
5837 
5838             repaint(cellRect);
5839         }
5840     }
5841 
5842 //
5843 // Serialization
5844 //
5845 
5846     /**
5847      * See readObject() and writeObject() in JComponent for more
5848      * information about serialization in Swing.
5849      */
writeObject(ObjectOutputStream s)5850     private void writeObject(ObjectOutputStream s) throws IOException {
5851         s.defaultWriteObject();
5852         if (getUIClassID().equals(uiClassID)) {
5853             byte count = JComponent.getWriteObjCounter(this);
5854             JComponent.setWriteObjCounter(this, --count);
5855             if (count == 0 && ui != null) {
5856                 ui.installUI(this);
5857             }
5858         }
5859     }
5860 
readObject(ObjectInputStream s)5861     private void readObject(ObjectInputStream s)
5862         throws IOException, ClassNotFoundException
5863     {
5864         ObjectInputStream.GetField f = s.readFields();
5865 
5866         TableModel newDataModel = (TableModel) f.get("dataModel", null);
5867         if (newDataModel == null) {
5868             throw new InvalidObjectException("Null dataModel");
5869         }
5870         dataModel = newDataModel;
5871 
5872         TableColumnModel newColumnModel = (TableColumnModel) f.get("columnModel", null);
5873         if (newColumnModel == null) {
5874             throw new InvalidObjectException("Null columnModel");
5875         }
5876         columnModel = newColumnModel;
5877 
5878         ListSelectionModel newSelectionModel = (ListSelectionModel) f.get("selectionModel", null);
5879         if (newSelectionModel == null) {
5880             throw new InvalidObjectException("Null selectionModel");
5881         }
5882         selectionModel = newSelectionModel;
5883 
5884         tableHeader = (JTableHeader) f.get("tableHeader", null);
5885         int newRowHeight = f.get("rowHeight", 0);
5886         if (newRowHeight <= 0) {
5887             throw new InvalidObjectException("Row height less than 1");
5888         }
5889         rowHeight = newRowHeight;
5890 
5891         rowMargin = f.get("rowMargin", 0);
5892         Color newGridColor = (Color) f.get("gridColor", null);
5893         if (newGridColor == null) {
5894             throw new InvalidObjectException("Null gridColor");
5895         }
5896         gridColor = newGridColor;
5897 
5898         showHorizontalLines = f.get("showHorizontalLines", false);
5899         showVerticalLines = f.get("showVerticalLines", false);
5900         int newAutoResizeMode = f.get("autoResizeMode", 0);
5901         if (!isValidAutoResizeMode(newAutoResizeMode)) {
5902             throw new InvalidObjectException("autoResizeMode is not valid");
5903         }
5904         autoResizeMode = newAutoResizeMode;
5905         autoCreateColumnsFromModel = f.get("autoCreateColumnsFromModel", false);
5906         preferredViewportSize = (Dimension) f.get("preferredViewportSize", null);
5907         rowSelectionAllowed = f.get("rowSelectionAllowed", false);
5908         cellSelectionEnabled = f.get("cellSelectionEnabled", false);
5909         selectionForeground = (Color) f.get("selectionForeground", null);
5910         selectionBackground = (Color) f.get("selectionBackground", null);
5911         rowModel = (SizeSequence) f.get("rowModel", null);
5912 
5913         boolean newDragEnabled = f.get("dragEnabled", false);
5914         checkDragEnabled(newDragEnabled);
5915         dragEnabled = newDragEnabled;
5916 
5917         surrendersFocusOnKeystroke = f.get("surrendersFocusOnKeystroke", false);
5918         editorRemover = (PropertyChangeListener) f.get("editorRemover", null);
5919         columnSelectionAdjusting = f.get("columnSelectionAdjusting", false);
5920         rowSelectionAdjusting = f.get("rowSelectionAdjusting", false);
5921         printError = (Throwable) f.get("printError", null);
5922         isRowHeightSet = f.get("isRowHeightSet", false);
5923         updateSelectionOnSort = f.get("updateSelectionOnSort", false);
5924         ignoreSortChange = f.get("ignoreSortChange", false);
5925         sorterChanged = f.get("sorterChanged", false);
5926         autoCreateRowSorter = f.get("autoCreateRowSorter", false);
5927         fillsViewportHeight = f.get("fillsViewportHeight", false);
5928         DropMode newDropMode = (DropMode) f.get("dropMode",
5929                 DropMode.USE_SELECTION);
5930         checkDropMode(newDropMode);
5931         dropMode = newDropMode;
5932 
5933         if ((ui != null) && (getUIClassID().equals(uiClassID))) {
5934             ui.installUI(this);
5935         }
5936         createDefaultRenderers();
5937         createDefaultEditors();
5938 
5939         // If ToolTipText != null, then the tooltip has already been
5940         // registered by JComponent.readObject() and we don't want
5941         // to re-register here
5942         if (getToolTipText() == null) {
5943             ToolTipManager.sharedInstance().registerComponent(this);
5944          }
5945     }
5946 
5947     /* Called from the JComponent's EnableSerializationFocusListener to
5948      * do any Swing-specific pre-serialization configuration.
5949      */
compWriteObjectNotify()5950     void compWriteObjectNotify() {
5951         super.compWriteObjectNotify();
5952         // If ToolTipText != null, then the tooltip has already been
5953         // unregistered by JComponent.compWriteObjectNotify()
5954         if (getToolTipText() == null) {
5955             ToolTipManager.sharedInstance().unregisterComponent(this);
5956         }
5957     }
5958 
5959     /**
5960      * Returns a string representation of this table. This method
5961      * is intended to be used only for debugging purposes, and the
5962      * content and format of the returned string may vary between
5963      * implementations. The returned string may be empty but may not
5964      * be <code>null</code>.
5965      *
5966      * @return  a string representation of this table
5967      */
paramString()5968     protected String paramString() {
5969         String gridColorString = (gridColor != null ?
5970                                   gridColor.toString() : "");
5971         String showHorizontalLinesString = (showHorizontalLines ?
5972                                             "true" : "false");
5973         String showVerticalLinesString = (showVerticalLines ?
5974                                           "true" : "false");
5975         String autoResizeModeString;
5976         if (autoResizeMode == AUTO_RESIZE_OFF) {
5977             autoResizeModeString = "AUTO_RESIZE_OFF";
5978         } else if (autoResizeMode == AUTO_RESIZE_NEXT_COLUMN) {
5979             autoResizeModeString = "AUTO_RESIZE_NEXT_COLUMN";
5980         } else if (autoResizeMode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) {
5981             autoResizeModeString = "AUTO_RESIZE_SUBSEQUENT_COLUMNS";
5982         } else if (autoResizeMode == AUTO_RESIZE_LAST_COLUMN) {
5983             autoResizeModeString = "AUTO_RESIZE_LAST_COLUMN";
5984         } else if (autoResizeMode == AUTO_RESIZE_ALL_COLUMNS)  {
5985             autoResizeModeString = "AUTO_RESIZE_ALL_COLUMNS";
5986         } else autoResizeModeString = "";
5987         String autoCreateColumnsFromModelString = (autoCreateColumnsFromModel ?
5988                                                    "true" : "false");
5989         String preferredViewportSizeString = (preferredViewportSize != null ?
5990                                               preferredViewportSize.toString()
5991                                               : "");
5992         String rowSelectionAllowedString = (rowSelectionAllowed ?
5993                                             "true" : "false");
5994         String cellSelectionEnabledString = (cellSelectionEnabled ?
5995                                             "true" : "false");
5996         String selectionForegroundString = (selectionForeground != null ?
5997                                             selectionForeground.toString() :
5998                                             "");
5999         String selectionBackgroundString = (selectionBackground != null ?
6000                                             selectionBackground.toString() :
6001                                             "");
6002 
6003         return super.paramString() +
6004         ",autoCreateColumnsFromModel=" + autoCreateColumnsFromModelString +
6005         ",autoResizeMode=" + autoResizeModeString +
6006         ",cellSelectionEnabled=" + cellSelectionEnabledString +
6007         ",editingColumn=" + editingColumn +
6008         ",editingRow=" + editingRow +
6009         ",gridColor=" + gridColorString +
6010         ",preferredViewportSize=" + preferredViewportSizeString +
6011         ",rowHeight=" + rowHeight +
6012         ",rowMargin=" + rowMargin +
6013         ",rowSelectionAllowed=" + rowSelectionAllowedString +
6014         ",selectionBackground=" + selectionBackgroundString +
6015         ",selectionForeground=" + selectionForegroundString +
6016         ",showHorizontalLines=" + showHorizontalLinesString +
6017         ",showVerticalLines=" + showVerticalLinesString;
6018     }
6019 
6020     // This class tracks changes in the keyboard focus state. It is used
6021     // when the JTable is editing to determine when to cancel the edit.
6022     // If focus switches to a component outside of the jtable, but in the
6023     // same window, this will cancel editing.
6024     class CellEditorRemover implements PropertyChangeListener {
6025         KeyboardFocusManager focusManager;
6026 
CellEditorRemover(KeyboardFocusManager fm)6027         public CellEditorRemover(KeyboardFocusManager fm) {
6028             this.focusManager = fm;
6029         }
6030 
6031         @SuppressWarnings("deprecation")
propertyChange(PropertyChangeEvent ev)6032         public void propertyChange(PropertyChangeEvent ev) {
6033             if (!isEditing() || getClientProperty("terminateEditOnFocusLost") != Boolean.TRUE) {
6034                 return;
6035             }
6036 
6037             Component c = focusManager.getPermanentFocusOwner();
6038             while (c != null) {
6039                 if (c == JTable.this) {
6040                     // focus remains inside the table
6041                     return;
6042                 } else if ((c instanceof Window) ||
6043                            (c instanceof Applet && c.getParent() == null)) {
6044                     if (c == SwingUtilities.getRoot(JTable.this)) {
6045                         if (!getCellEditor().stopCellEditing()) {
6046                             getCellEditor().cancelCellEditing();
6047                         }
6048                     }
6049                     break;
6050                 }
6051                 c = c.getParent();
6052             }
6053         }
6054     }
6055 
6056 /////////////////
6057 // Printing Support
6058 /////////////////
6059 
6060     /**
6061      * A convenience method that displays a printing dialog, and then prints
6062      * this <code>JTable</code> in mode <code>PrintMode.FIT_WIDTH</code>,
6063      * with no header or footer text. A modal progress dialog, with an abort
6064      * option, will be shown for the duration of printing.
6065      * <p>
6066      * Note: In headless mode, no dialogs are shown and printing
6067      * occurs on the default printer.
6068      *
6069      * @return true, unless printing is cancelled by the user
6070      * @throws SecurityException if this thread is not allowed to
6071      *                           initiate a print job request
6072      * @throws PrinterException if an error in the print system causes the job
6073      *                          to be aborted
6074      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6075      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
6076      * @see #getPrintable
6077      *
6078      * @since 1.5
6079      */
print()6080     public boolean print() throws PrinterException {
6081 
6082         return print(PrintMode.FIT_WIDTH);
6083     }
6084 
6085     /**
6086      * A convenience method that displays a printing dialog, and then prints
6087      * this <code>JTable</code> in the given printing mode,
6088      * with no header or footer text. A modal progress dialog, with an abort
6089      * option, will be shown for the duration of printing.
6090      * <p>
6091      * Note: In headless mode, no dialogs are shown and printing
6092      * occurs on the default printer.
6093      *
6094      * @param  printMode        the printing mode that the printable should use
6095      * @return true, unless printing is cancelled by the user
6096      * @throws SecurityException if this thread is not allowed to
6097      *                           initiate a print job request
6098      * @throws PrinterException if an error in the print system causes the job
6099      *                          to be aborted
6100      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6101      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
6102      * @see #getPrintable
6103      *
6104      * @since 1.5
6105      */
print(PrintMode printMode)6106     public boolean print(PrintMode printMode) throws PrinterException {
6107 
6108         return print(printMode, null, null);
6109     }
6110 
6111     /**
6112      * A convenience method that displays a printing dialog, and then prints
6113      * this <code>JTable</code> in the given printing mode,
6114      * with the specified header and footer text. A modal progress dialog,
6115      * with an abort option, will be shown for the duration of printing.
6116      * <p>
6117      * Note: In headless mode, no dialogs are shown and printing
6118      * occurs on the default printer.
6119      *
6120      * @param  printMode        the printing mode that the printable should use
6121      * @param  headerFormat     a <code>MessageFormat</code> specifying the text
6122      *                          to be used in printing a header,
6123      *                          or null for none
6124      * @param  footerFormat     a <code>MessageFormat</code> specifying the text
6125      *                          to be used in printing a footer,
6126      *                          or null for none
6127      * @return true, unless printing is cancelled by the user
6128      * @throws SecurityException if this thread is not allowed to
6129      *                           initiate a print job request
6130      * @throws PrinterException if an error in the print system causes the job
6131      *                          to be aborted
6132      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6133      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
6134      * @see #getPrintable
6135      *
6136      * @since 1.5
6137      */
print(PrintMode printMode, MessageFormat headerFormat, MessageFormat footerFormat)6138     public boolean print(PrintMode printMode,
6139                          MessageFormat headerFormat,
6140                          MessageFormat footerFormat) throws PrinterException {
6141 
6142         boolean showDialogs = !GraphicsEnvironment.isHeadless();
6143         return print(printMode, headerFormat, footerFormat,
6144                      showDialogs, null, showDialogs);
6145     }
6146 
6147     /**
6148      * Prints this table, as specified by the fully featured
6149      * {@link #print(JTable.PrintMode, MessageFormat, MessageFormat,
6150      * boolean, PrintRequestAttributeSet, boolean, PrintService) print}
6151      * method, with the default printer specified as the print service.
6152      *
6153      * @param  printMode        the printing mode that the printable should use
6154      * @param  headerFormat     a <code>MessageFormat</code> specifying the text
6155      *                          to be used in printing a header,
6156      *                          or <code>null</code> for none
6157      * @param  footerFormat     a <code>MessageFormat</code> specifying the text
6158      *                          to be used in printing a footer,
6159      *                          or <code>null</code> for none
6160      * @param  showPrintDialog  whether or not to display a print dialog
6161      * @param  attr             a <code>PrintRequestAttributeSet</code>
6162      *                          specifying any printing attributes,
6163      *                          or <code>null</code> for none
6164      * @param  interactive      whether or not to print in an interactive mode
6165      * @return true, unless printing is cancelled by the user
6166      * @throws HeadlessException if the method is asked to show a printing
6167      *                           dialog or run interactively, and
6168      *                           <code>GraphicsEnvironment.isHeadless</code>
6169      *                           returns <code>true</code>
6170      * @throws SecurityException if this thread is not allowed to
6171      *                           initiate a print job request
6172      * @throws PrinterException if an error in the print system causes the job
6173      *                          to be aborted
6174      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6175      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
6176      * @see #getPrintable
6177      *
6178      * @since 1.5
6179      */
print(PrintMode printMode, MessageFormat headerFormat, MessageFormat footerFormat, boolean showPrintDialog, PrintRequestAttributeSet attr, boolean interactive)6180     public boolean print(PrintMode printMode,
6181                          MessageFormat headerFormat,
6182                          MessageFormat footerFormat,
6183                          boolean showPrintDialog,
6184                          PrintRequestAttributeSet attr,
6185                          boolean interactive) throws PrinterException,
6186                                                      HeadlessException {
6187 
6188         return print(printMode,
6189                      headerFormat,
6190                      footerFormat,
6191                      showPrintDialog,
6192                      attr,
6193                      interactive,
6194                      null);
6195     }
6196 
6197     /**
6198      * Prints this <code>JTable</code>. Takes steps that the majority of
6199      * developers would take in order to print a <code>JTable</code>.
6200      * In short, it prepares the table, calls <code>getPrintable</code> to
6201      * fetch an appropriate <code>Printable</code>, and then sends it to the
6202      * printer.
6203      * <p>
6204      * A <code>boolean</code> parameter allows you to specify whether or not
6205      * a printing dialog is displayed to the user. When it is, the user may
6206      * use the dialog to change the destination printer or printing attributes,
6207      * or even to cancel the print. Another two parameters allow for a
6208      * <code>PrintService</code> and printing attributes to be specified.
6209      * These parameters can be used either to provide initial values for the
6210      * print dialog, or to specify values when the dialog is not shown.
6211      * <p>
6212      * A second <code>boolean</code> parameter allows you to specify whether
6213      * or not to perform printing in an interactive mode. If <code>true</code>,
6214      * a modal progress dialog, with an abort option, is displayed for the
6215      * duration of printing . This dialog also prevents any user action which
6216      * may affect the table. However, it can not prevent the table from being
6217      * modified by code (for example, another thread that posts updates using
6218      * <code>SwingUtilities.invokeLater</code>). It is therefore the
6219      * responsibility of the developer to ensure that no other code modifies
6220      * the table in any way during printing (invalid modifications include
6221      * changes in: size, renderers, or underlying data). Printing behavior is
6222      * undefined when the table is changed during printing.
6223      * <p>
6224      * If <code>false</code> is specified for this parameter, no dialog will
6225      * be displayed and printing will begin immediately on the event-dispatch
6226      * thread. This blocks any other events, including repaints, from being
6227      * processed until printing is complete. Although this effectively prevents
6228      * the table from being changed, it doesn't provide a good user experience.
6229      * For this reason, specifying <code>false</code> is only recommended when
6230      * printing from an application with no visible GUI.
6231      * <p>
6232      * Note: Attempting to show the printing dialog or run interactively, while
6233      * in headless mode, will result in a <code>HeadlessException</code>.
6234      * <p>
6235      * Before fetching the printable, this method will gracefully terminate
6236      * editing, if necessary, to prevent an editor from showing in the printed
6237      * result. Additionally, <code>JTable</code> will prepare its renderers
6238      * during printing such that selection and focus are not indicated.
6239      * As far as customizing further how the table looks in the printout,
6240      * developers can provide custom renderers or paint code that conditionalize
6241      * on the value of {@link javax.swing.JComponent#isPaintingForPrint()}.
6242      * <p>
6243      * See {@link #getPrintable} for more description on how the table is
6244      * printed.
6245      *
6246      * @param  printMode        the printing mode that the printable should use
6247      * @param  headerFormat     a <code>MessageFormat</code> specifying the text
6248      *                          to be used in printing a header,
6249      *                          or <code>null</code> for none
6250      * @param  footerFormat     a <code>MessageFormat</code> specifying the text
6251      *                          to be used in printing a footer,
6252      *                          or <code>null</code> for none
6253      * @param  showPrintDialog  whether or not to display a print dialog
6254      * @param  attr             a <code>PrintRequestAttributeSet</code>
6255      *                          specifying any printing attributes,
6256      *                          or <code>null</code> for none
6257      * @param  interactive      whether or not to print in an interactive mode
6258      * @param  service          the destination <code>PrintService</code>,
6259      *                          or <code>null</code> to use the default printer
6260      * @return true, unless printing is cancelled by the user
6261      * @throws HeadlessException if the method is asked to show a printing
6262      *                           dialog or run interactively, and
6263      *                           <code>GraphicsEnvironment.isHeadless</code>
6264      *                           returns <code>true</code>
6265      * @throws  SecurityException if a security manager exists and its
6266      *          {@link java.lang.SecurityManager#checkPrintJobAccess}
6267      *          method disallows this thread from creating a print job request
6268      * @throws PrinterException if an error in the print system causes the job
6269      *                          to be aborted
6270      * @see #getPrintable
6271      * @see java.awt.GraphicsEnvironment#isHeadless
6272      *
6273      * @since 1.6
6274      */
print(PrintMode printMode, MessageFormat headerFormat, MessageFormat footerFormat, boolean showPrintDialog, PrintRequestAttributeSet attr, boolean interactive, PrintService service)6275     public boolean print(PrintMode printMode,
6276                          MessageFormat headerFormat,
6277                          MessageFormat footerFormat,
6278                          boolean showPrintDialog,
6279                          PrintRequestAttributeSet attr,
6280                          boolean interactive,
6281                          PrintService service) throws PrinterException,
6282                                                       HeadlessException {
6283 
6284         // complain early if an invalid parameter is specified for headless mode
6285         boolean isHeadless = GraphicsEnvironment.isHeadless();
6286         if (isHeadless) {
6287             if (showPrintDialog) {
6288                 throw new HeadlessException("Can't show print dialog.");
6289             }
6290 
6291             if (interactive) {
6292                 throw new HeadlessException("Can't run interactively.");
6293             }
6294         }
6295 
6296         // Get a PrinterJob.
6297         // Do this before anything with side-effects since it may throw a
6298         // security exception - in which case we don't want to do anything else.
6299         final PrinterJob job = PrinterJob.getPrinterJob();
6300 
6301         if (isEditing()) {
6302             // try to stop cell editing, and failing that, cancel it
6303             if (!getCellEditor().stopCellEditing()) {
6304                 getCellEditor().cancelCellEditing();
6305             }
6306         }
6307 
6308         if (attr == null) {
6309             attr = new HashPrintRequestAttributeSet();
6310         }
6311 
6312         final PrintingStatus printingStatus;
6313 
6314          // fetch the Printable
6315         Printable printable =
6316              getPrintable(printMode, headerFormat, footerFormat);
6317 
6318         if (interactive) {
6319             // wrap the Printable so that we can print on another thread
6320             printable = new ThreadSafePrintable(printable);
6321             printingStatus = PrintingStatus.createPrintingStatus(this, job);
6322             printable = printingStatus.createNotificationPrintable(printable);
6323         } else {
6324             // to please compiler
6325             printingStatus = null;
6326         }
6327 
6328         // set the printable on the PrinterJob
6329         job.setPrintable(printable);
6330 
6331         // if specified, set the PrintService on the PrinterJob
6332         if (service != null) {
6333             job.setPrintService(service);
6334         }
6335 
6336         // if requested, show the print dialog
6337         if (showPrintDialog && !job.printDialog(attr)) {
6338             // the user cancelled the print dialog
6339             return false;
6340         }
6341 
6342         // if not interactive, just print on this thread (no dialog)
6343         if (!interactive) {
6344             // do the printing
6345             job.print(attr);
6346 
6347             // we're done
6348             return true;
6349         }
6350 
6351         // make sure this is clear since we'll check it after
6352         printError = null;
6353 
6354         // to synchronize on
6355         final Object lock = new Object();
6356 
6357         // copied so we can access from the inner class
6358         final PrintRequestAttributeSet copyAttr = attr;
6359 
6360         // this runnable will be used to do the printing
6361         // (and save any throwables) on another thread
6362         Runnable runnable = () -> {
6363             try {
6364                 // do the printing
6365                 job.print(copyAttr);
6366             } catch (Throwable t) {
6367                 // save any Throwable to be rethrown
6368                 synchronized(lock) {
6369                     printError = t;
6370                 }
6371             } finally {
6372                 // we're finished - hide the dialog
6373                 printingStatus.dispose();
6374             }
6375         };
6376 
6377         // start printing on another thread
6378         Thread th = new Thread(null, runnable, "JTablePrint", 0, false);
6379         th.start();
6380 
6381         printingStatus.showModal(true);
6382 
6383         // look for any error that the printing may have generated
6384         Throwable pe;
6385         synchronized(lock) {
6386             pe = printError;
6387             printError = null;
6388         }
6389 
6390         // check the type of error and handle it
6391         if (pe != null) {
6392             // a subclass of PrinterException meaning the job was aborted,
6393             // in this case, by the user
6394             if (pe instanceof PrinterAbortException) {
6395                 return false;
6396             } else if (pe instanceof PrinterException) {
6397                 throw (PrinterException)pe;
6398             } else if (pe instanceof RuntimeException) {
6399                 throw (RuntimeException)pe;
6400             } else if (pe instanceof Error) {
6401                 throw (Error)pe;
6402             }
6403 
6404             // can not happen
6405             throw new AssertionError(pe);
6406         }
6407 
6408         return true;
6409     }
6410 
6411     /**
6412      * Return a <code>Printable</code> for use in printing this JTable.
6413      * <p>
6414      * This method is meant for those wishing to customize the default
6415      * <code>Printable</code> implementation used by <code>JTable</code>'s
6416      * <code>print</code> methods. Developers wanting simply to print the table
6417      * should use one of those methods directly.
6418      * <p>
6419      * The <code>Printable</code> can be requested in one of two printing modes.
6420      * In both modes, it spreads table rows naturally in sequence across
6421      * multiple pages, fitting as many rows as possible per page.
6422      * <code>PrintMode.NORMAL</code> specifies that the table be
6423      * printed at its current size. In this mode, there may be a need to spread
6424      * columns across pages in a similar manner to that of the rows. When the
6425      * need arises, columns are distributed in an order consistent with the
6426      * table's <code>ComponentOrientation</code>.
6427      * <code>PrintMode.FIT_WIDTH</code> specifies that the output be
6428      * scaled smaller, if necessary, to fit the table's entire width
6429      * (and thereby all columns) on each page. Width and height are scaled
6430      * equally, maintaining the aspect ratio of the output.
6431      * <p>
6432      * The <code>Printable</code> heads the portion of table on each page
6433      * with the appropriate section from the table's <code>JTableHeader</code>,
6434      * if it has one.
6435      * <p>
6436      * Header and footer text can be added to the output by providing
6437      * <code>MessageFormat</code> arguments. The printing code requests
6438      * Strings from the formats, providing a single item which may be included
6439      * in the formatted string: an <code>Integer</code> representing the current
6440      * page number.
6441      * <p>
6442      * You are encouraged to read the documentation for
6443      * <code>MessageFormat</code> as some characters, such as single-quote,
6444      * are special and need to be escaped.
6445      * <p>
6446      * Here's an example of creating a <code>MessageFormat</code> that can be
6447      * used to print "Duke's Table: Page - " and the current page number:
6448      *
6449      * <pre>
6450      *     // notice the escaping of the single quote
6451      *     // notice how the page number is included with "{0}"
6452      *     MessageFormat format = new MessageFormat("Duke''s Table: Page - {0}");
6453      * </pre>
6454      * <p>
6455      * The <code>Printable</code> constrains what it draws to the printable
6456      * area of each page that it prints. Under certain circumstances, it may
6457      * find it impossible to fit all of a page's content into that area. In
6458      * these cases the output may be clipped, but the implementation
6459      * makes an effort to do something reasonable. Here are a few situations
6460      * where this is known to occur, and how they may be handled by this
6461      * particular implementation:
6462      * <ul>
6463      *   <li>In any mode, when the header or footer text is too wide to fit
6464      *       completely in the printable area -- print as much of the text as
6465      *       possible starting from the beginning, as determined by the table's
6466      *       <code>ComponentOrientation</code>.
6467      *   <li>In any mode, when a row is too tall to fit in the
6468      *       printable area -- print the upper-most portion of the row
6469      *       and paint no lower border on the table.
6470      *   <li>In <code>PrintMode.NORMAL</code> when a column
6471      *       is too wide to fit in the printable area -- print the center
6472      *       portion of the column and leave the left and right borders
6473      *       off the table.
6474      * </ul>
6475      * <p>
6476      * It is entirely valid for this <code>Printable</code> to be wrapped
6477      * inside another in order to create complex reports and documents. You may
6478      * even request that different pages be rendered into different sized
6479      * printable areas. The implementation must be prepared to handle this
6480      * (possibly by doing its layout calculations on the fly). However,
6481      * providing different heights to each page will likely not work well
6482      * with <code>PrintMode.NORMAL</code> when it has to spread columns
6483      * across pages.
6484      * <p>
6485      * As far as customizing how the table looks in the printed result,
6486      * <code>JTable</code> itself will take care of hiding the selection
6487      * and focus during printing. For additional customizations, your
6488      * renderers or painting code can customize the look based on the value
6489      * of {@link javax.swing.JComponent#isPaintingForPrint()}
6490      * <p>
6491      * Also, <i>before</i> calling this method you may wish to <i>first</i>
6492      * modify the state of the table, such as to cancel cell editing or
6493      * have the user size the table appropriately. However, you must not
6494      * modify the state of the table <i>after</i> this <code>Printable</code>
6495      * has been fetched (invalid modifications include changes in size or
6496      * underlying data). The behavior of the returned <code>Printable</code>
6497      * is undefined once the table has been changed.
6498      *
6499      * @param  printMode     the printing mode that the printable should use
6500      * @param  headerFormat  a <code>MessageFormat</code> specifying the text to
6501      *                       be used in printing a header, or null for none
6502      * @param  footerFormat  a <code>MessageFormat</code> specifying the text to
6503      *                       be used in printing a footer, or null for none
6504      * @return a <code>Printable</code> for printing this JTable
6505      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6506      *             boolean, PrintRequestAttributeSet, boolean)
6507      * @see Printable
6508      * @see PrinterJob
6509      *
6510      * @since 1.5
6511      */
getPrintable(PrintMode printMode, MessageFormat headerFormat, MessageFormat footerFormat)6512     public Printable getPrintable(PrintMode printMode,
6513                                   MessageFormat headerFormat,
6514                                   MessageFormat footerFormat) {
6515 
6516         return new TablePrintable(this, printMode, headerFormat, footerFormat);
6517     }
6518 
6519 
6520     /**
6521      * A <code>Printable</code> implementation that wraps another
6522      * <code>Printable</code>, making it safe for printing on another thread.
6523      */
6524     private class ThreadSafePrintable implements Printable {
6525 
6526         /** The delegate <code>Printable</code>. */
6527         private Printable printDelegate;
6528 
6529         /**
6530          * To communicate any return value when delegating.
6531          */
6532         private int retVal;
6533 
6534         /**
6535          * To communicate any <code>Throwable</code> when delegating.
6536          */
6537         private Throwable retThrowable;
6538 
6539         /**
6540          * Construct a <code>ThreadSafePrintable</code> around the given
6541          * delegate.
6542          *
6543          * @param printDelegate the <code>Printable</code> to delegate to
6544          */
ThreadSafePrintable(Printable printDelegate)6545         public ThreadSafePrintable(Printable printDelegate) {
6546             this.printDelegate = printDelegate;
6547         }
6548 
6549         /**
6550          * Prints the specified page into the given {@link Graphics}
6551          * context, in the specified format.
6552          * <p>
6553          * Regardless of what thread this method is called on, all calls into
6554          * the delegate will be done on the event-dispatch thread.
6555          *
6556          * @param   graphics    the context into which the page is drawn
6557          * @param   pageFormat  the size and orientation of the page being drawn
6558          * @param   pageIndex   the zero based index of the page to be drawn
6559          * @return  PAGE_EXISTS if the page is rendered successfully, or
6560          *          NO_SUCH_PAGE if a non-existent page index is specified
6561          * @throws  PrinterException if an error causes printing to be aborted
6562          */
print(final Graphics graphics, final PageFormat pageFormat, final int pageIndex)6563         public int print(final Graphics graphics,
6564                          final PageFormat pageFormat,
6565                          final int pageIndex) throws PrinterException {
6566 
6567             // We'll use this Runnable
6568             Runnable runnable = new Runnable() {
6569                 public synchronized void run() {
6570                     try {
6571                         // call into the delegate and save the return value
6572                         retVal = printDelegate.print(graphics, pageFormat, pageIndex);
6573                     } catch (Throwable throwable) {
6574                         // save any Throwable to be rethrown
6575                         retThrowable = throwable;
6576                     } finally {
6577                         // notify the caller that we're done
6578                         notifyAll();
6579                     }
6580                 }
6581             };
6582 
6583             synchronized(runnable) {
6584                 // make sure these are initialized
6585                 retVal = -1;
6586                 retThrowable = null;
6587 
6588                 // call into the EDT
6589                 SwingUtilities.invokeLater(runnable);
6590 
6591                 // wait for the runnable to finish
6592                 while (retVal == -1 && retThrowable == null) {
6593                     try {
6594                         runnable.wait();
6595                     } catch (InterruptedException ie) {
6596                         // short process, safe to ignore interrupts
6597                     }
6598                 }
6599 
6600                 // if the delegate threw a throwable, rethrow it here
6601                 if (retThrowable != null) {
6602                     if (retThrowable instanceof PrinterException) {
6603                         throw (PrinterException)retThrowable;
6604                     } else if (retThrowable instanceof RuntimeException) {
6605                         throw (RuntimeException)retThrowable;
6606                     } else if (retThrowable instanceof Error) {
6607                         throw (Error)retThrowable;
6608                     }
6609 
6610                     // can not happen
6611                     throw new AssertionError(retThrowable);
6612                 }
6613 
6614                 return retVal;
6615             }
6616         }
6617     }
6618 
6619 /////////////////
6620 // Accessibility support
6621 ////////////////
6622 
6623     /**
6624      * Gets the AccessibleContext associated with this JTable.
6625      * For tables, the AccessibleContext takes the form of an
6626      * AccessibleJTable.
6627      * A new AccessibleJTable instance is created if necessary.
6628      *
6629      * @return an AccessibleJTable that serves as the
6630      *         AccessibleContext of this JTable
6631      */
6632     @BeanProperty(bound = false)
getAccessibleContext()6633     public AccessibleContext getAccessibleContext() {
6634         if (accessibleContext == null) {
6635             accessibleContext = new AccessibleJTable();
6636         }
6637         return accessibleContext;
6638     }
6639 
6640     //
6641     // *** should also implement AccessibleSelection?
6642     // *** and what's up with keyboard navigation/manipulation?
6643     //
6644     /**
6645      * This class implements accessibility support for the
6646      * <code>JTable</code> class.  It provides an implementation of the
6647      * Java Accessibility API appropriate to table user-interface elements.
6648      * <p>
6649      * <strong>Warning:</strong>
6650      * Serialized objects of this class will not be compatible with
6651      * future Swing releases. The current serialization support is
6652      * appropriate for short term storage or RMI between applications running
6653      * the same version of Swing.  As of 1.4, support for long term storage
6654      * of all JavaBeans&trade;
6655      * has been added to the <code>java.beans</code> package.
6656      * Please see {@link java.beans.XMLEncoder}.
6657      */
6658     @SuppressWarnings("serial") // Same-version serialization only
6659     protected class AccessibleJTable extends AccessibleJComponent
6660     implements AccessibleSelection, ListSelectionListener, TableModelListener,
6661     TableColumnModelListener, CellEditorListener, PropertyChangeListener,
6662     AccessibleExtendedTable {
6663 
6664         int previousFocusedRow;
6665         int previousFocusedCol;
6666 
6667         /**
6668          * AccessibleJTable constructor
6669          *
6670          * @since 1.5
6671          */
AccessibleJTable()6672         protected AccessibleJTable() {
6673             super();
6674             JTable.this.putClientProperty("JTable.forceAutoStartsEdit", true);
6675             JTable.this.addPropertyChangeListener(this);
6676             JTable.this.getSelectionModel().addListSelectionListener(this);
6677             TableColumnModel tcm = JTable.this.getColumnModel();
6678             tcm.addColumnModelListener(this);
6679             tcm.getSelectionModel().addListSelectionListener(this);
6680             JTable.this.getModel().addTableModelListener(this);
6681             previousFocusedRow = JTable.this.getSelectionModel().
6682                                         getLeadSelectionIndex();
6683             previousFocusedCol = JTable.this.getColumnModel().
6684                                         getSelectionModel().getLeadSelectionIndex();
6685         }
6686 
6687     // Listeners to track model, etc. changes to as to re-place the other
6688     // listeners
6689 
6690         /**
6691          * Track changes to selection model, column model, etc. so as to
6692          * be able to re-place listeners on those in order to pass on
6693          * information to the Accessibility PropertyChange mechanism
6694          */
propertyChange(PropertyChangeEvent e)6695         public void propertyChange(PropertyChangeEvent e) {
6696             String name = e.getPropertyName();
6697             Object oldValue = e.getOldValue();
6698             Object newValue = e.getNewValue();
6699 
6700                 // re-set tableModel listeners
6701             if (name.compareTo("model") == 0) {
6702 
6703                 if (oldValue != null && oldValue instanceof TableModel) {
6704                     ((TableModel) oldValue).removeTableModelListener(this);
6705                 }
6706                 if (newValue != null && newValue instanceof TableModel) {
6707                     ((TableModel) newValue).addTableModelListener(this);
6708                 }
6709 
6710                 // re-set selectionModel listeners
6711             } else if (name.compareTo("selectionModel") == 0) {
6712 
6713                 Object source = e.getSource();
6714                 if (source == JTable.this) {    // row selection model
6715 
6716                     if (oldValue != null &&
6717                         oldValue instanceof ListSelectionModel) {
6718                         ((ListSelectionModel) oldValue).removeListSelectionListener(this);
6719                     }
6720                     if (newValue != null &&
6721                         newValue instanceof ListSelectionModel) {
6722                         ((ListSelectionModel) newValue).addListSelectionListener(this);
6723                     }
6724 
6725                 } else if (source == JTable.this.getColumnModel()) {
6726 
6727                     if (oldValue != null &&
6728                         oldValue instanceof ListSelectionModel) {
6729                         ((ListSelectionModel) oldValue).removeListSelectionListener(this);
6730                     }
6731                     if (newValue != null &&
6732                         newValue instanceof ListSelectionModel) {
6733                         ((ListSelectionModel) newValue).addListSelectionListener(this);
6734                     }
6735 
6736                 } else {
6737                   //        System.out.println("!!! Bug in source of selectionModel propertyChangeEvent");
6738                 }
6739 
6740                 // re-set columnModel listeners
6741                 // and column's selection property listener as well
6742             } else if (name.compareTo("columnModel") == 0) {
6743 
6744                 if (oldValue != null && oldValue instanceof TableColumnModel) {
6745                     TableColumnModel tcm = (TableColumnModel) oldValue;
6746                     tcm.removeColumnModelListener(this);
6747                     tcm.getSelectionModel().removeListSelectionListener(this);
6748                 }
6749                 if (newValue != null && newValue instanceof TableColumnModel) {
6750                     TableColumnModel tcm = (TableColumnModel) newValue;
6751                     tcm.addColumnModelListener(this);
6752                     tcm.getSelectionModel().addListSelectionListener(this);
6753                 }
6754 
6755                 // re-se cellEditor listeners
6756             } else if (name.compareTo("tableCellEditor") == 0) {
6757 
6758                 if (oldValue != null && oldValue instanceof TableCellEditor) {
6759                     ((TableCellEditor) oldValue).removeCellEditorListener(this);
6760                 }
6761                 if (newValue != null && newValue instanceof TableCellEditor) {
6762                     ((TableCellEditor) newValue).addCellEditorListener(this);
6763                 }
6764             }
6765         }
6766 
6767 
6768     // Listeners to echo changes to the AccessiblePropertyChange mechanism
6769 
6770         /**
6771          * Describes a change in the accessible table model.
6772          */
6773         protected class AccessibleJTableModelChange
6774             implements AccessibleTableModelChange {
6775 
6776             /** The type */
6777             protected int type;
6778             /** The first row */
6779             protected int firstRow;
6780             /** The last row */
6781             protected int lastRow;
6782             /** The first column */
6783             protected int firstColumn;
6784             /** The last column */
6785             protected int lastColumn;
6786 
6787             /**
6788              * Constructs an {@code AccessibleJTableModelChange}.
6789              * @param type the type
6790              * @param firstRow the first row
6791              * @param lastRow the last row
6792              * @param firstColumn the first column
6793              * @param lastColumn the last column
6794              */
AccessibleJTableModelChange(int type, int firstRow, int lastRow, int firstColumn, int lastColumn)6795             protected AccessibleJTableModelChange(int type, int firstRow,
6796                                                   int lastRow, int firstColumn,
6797                                                   int lastColumn) {
6798                 this.type = type;
6799                 this.firstRow = firstRow;
6800                 this.lastRow = lastRow;
6801                 this.firstColumn = firstColumn;
6802                 this.lastColumn = lastColumn;
6803             }
6804 
6805             /**
6806              * Returns the type.
6807              * @return the type
6808              */
getType()6809             public int getType() {
6810                 return type;
6811             }
6812 
6813             /**
6814              * Returns the first row.
6815              * @return the first row
6816              */
getFirstRow()6817             public int getFirstRow() {
6818                 return firstRow;
6819             }
6820 
6821             /**
6822              * Returns the last row.
6823              * @return the last row
6824              */
getLastRow()6825             public int getLastRow() {
6826                 return lastRow;
6827             }
6828 
6829             /**
6830              * Returns the first column.
6831              * @return the first column
6832              */
getFirstColumn()6833             public int getFirstColumn() {
6834                 return firstColumn;
6835             }
6836 
6837             /**
6838              * Returns the last column.
6839              * @return the last column
6840              */
getLastColumn()6841             public int getLastColumn() {
6842                 return lastColumn;
6843             }
6844         }
6845 
6846         /**
6847          * Track changes to the table contents
6848          *
6849          * @param e a {@code TableModelEvent} describing the event
6850          */
tableChanged(TableModelEvent e)6851         public void tableChanged(TableModelEvent e) {
6852            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6853                               null, null);
6854            if (e != null) {
6855                int firstColumn = e.getColumn();
6856                int lastColumn = e.getColumn();
6857                if (firstColumn == TableModelEvent.ALL_COLUMNS) {
6858                    firstColumn = 0;
6859                    lastColumn = getColumnCount() - 1;
6860                }
6861 
6862                // Fire a property change event indicating the table model
6863                // has changed.
6864                AccessibleJTableModelChange change =
6865                    new AccessibleJTableModelChange(e.getType(),
6866                                                    e.getFirstRow(),
6867                                                    e.getLastRow(),
6868                                                    firstColumn,
6869                                                    lastColumn);
6870                firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6871                                   null, change);
6872             }
6873         }
6874 
6875         /**
6876          * Track changes to the table contents (row insertions)
6877          *
6878          * @param e a {@code TableModelEvent} describing the event
6879          */
tableRowsInserted(TableModelEvent e)6880         public void tableRowsInserted(TableModelEvent e) {
6881            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6882                               null, null);
6883 
6884            // Fire a property change event indicating the table model
6885            // has changed.
6886            int firstColumn = e.getColumn();
6887            int lastColumn = e.getColumn();
6888            if (firstColumn == TableModelEvent.ALL_COLUMNS) {
6889                firstColumn = 0;
6890                lastColumn = getColumnCount() - 1;
6891            }
6892            AccessibleJTableModelChange change =
6893                new AccessibleJTableModelChange(e.getType(),
6894                                                e.getFirstRow(),
6895                                                e.getLastRow(),
6896                                                firstColumn,
6897                                                lastColumn);
6898            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6899                               null, change);
6900         }
6901 
6902         /**
6903          * Track changes to the table contents (row deletions)
6904          *
6905          * @param e a {@code TableModelEvent} describing the event
6906          */
tableRowsDeleted(TableModelEvent e)6907         public void tableRowsDeleted(TableModelEvent e) {
6908            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6909                               null, null);
6910 
6911            // Fire a property change event indicating the table model
6912            // has changed.
6913            int firstColumn = e.getColumn();
6914            int lastColumn = e.getColumn();
6915            if (firstColumn == TableModelEvent.ALL_COLUMNS) {
6916                firstColumn = 0;
6917                lastColumn = getColumnCount() - 1;
6918            }
6919            AccessibleJTableModelChange change =
6920                new AccessibleJTableModelChange(e.getType(),
6921                                                e.getFirstRow(),
6922                                                e.getLastRow(),
6923                                                firstColumn,
6924                                                lastColumn);
6925            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6926                               null, change);
6927         }
6928 
6929         /**
6930          * Track changes to the table contents (column insertions)
6931          */
columnAdded(TableColumnModelEvent e)6932         public void columnAdded(TableColumnModelEvent e) {
6933            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6934                               null, null);
6935 
6936            // Fire a property change event indicating the table model
6937            // has changed.
6938            int type = AccessibleTableModelChange.INSERT;
6939            AccessibleJTableModelChange change =
6940                new AccessibleJTableModelChange(type,
6941                                                0,
6942                                                0,
6943                                                e.getFromIndex(),
6944                                                e.getToIndex());
6945            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6946                               null, change);
6947         }
6948 
6949         /**
6950          * Track changes to the table contents (column deletions)
6951          */
columnRemoved(TableColumnModelEvent e)6952         public void columnRemoved(TableColumnModelEvent e) {
6953            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6954                               null, null);
6955            // Fire a property change event indicating the table model
6956            // has changed.
6957            int type = AccessibleTableModelChange.DELETE;
6958            AccessibleJTableModelChange change =
6959                new AccessibleJTableModelChange(type,
6960                                                0,
6961                                                0,
6962                                                e.getFromIndex(),
6963                                                e.getToIndex());
6964            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6965                               null, change);
6966         }
6967 
6968         /**
6969          * Track changes of a column repositioning.
6970          *
6971          * @see TableColumnModelListener
6972          */
columnMoved(TableColumnModelEvent e)6973         public void columnMoved(TableColumnModelEvent e) {
6974            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6975                               null, null);
6976 
6977            // Fire property change events indicating the table model
6978            // has changed.
6979            int type = AccessibleTableModelChange.DELETE;
6980            AccessibleJTableModelChange change =
6981                new AccessibleJTableModelChange(type,
6982                                                0,
6983                                                0,
6984                                                e.getFromIndex(),
6985                                                e.getFromIndex());
6986            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6987                               null, change);
6988 
6989            int type2 = AccessibleTableModelChange.INSERT;
6990            AccessibleJTableModelChange change2 =
6991                new AccessibleJTableModelChange(type2,
6992                                                0,
6993                                                0,
6994                                                e.getToIndex(),
6995                                                e.getToIndex());
6996            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6997                               null, change2);
6998         }
6999 
7000         /**
7001          * Track changes of a column moving due to margin changes.
7002          *
7003          * @see TableColumnModelListener
7004          */
columnMarginChanged(ChangeEvent e)7005         public void columnMarginChanged(ChangeEvent e) {
7006            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
7007                               null, null);
7008         }
7009 
7010         /**
7011          * Track that the selection model of the TableColumnModel changed.
7012          *
7013          * @see TableColumnModelListener
7014          */
columnSelectionChanged(ListSelectionEvent e)7015         public void columnSelectionChanged(ListSelectionEvent e) {
7016             // we should now re-place our TableColumn listener
7017         }
7018 
7019         /**
7020          * Track changes to a cell's contents.
7021          *
7022          * Invoked when editing is finished. The changes are saved, the
7023          * editor object is discarded, and the cell is rendered once again.
7024          *
7025          * @see CellEditorListener
7026          */
editingStopped(ChangeEvent e)7027         public void editingStopped(ChangeEvent e) {
7028            // it'd be great if we could figure out which cell, and pass that
7029            // somehow as a parameter
7030            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
7031                               null, null);
7032         }
7033 
7034         /**
7035          * Invoked when editing is canceled. The editor object is discarded
7036          * and the cell is rendered once again.
7037          *
7038          * @see CellEditorListener
7039          */
editingCanceled(ChangeEvent e)7040         public void editingCanceled(ChangeEvent e) {
7041             // nothing to report, 'cause nothing changed
7042         }
7043 
7044         /**
7045          * Track changes to table cell selections
7046          */
valueChanged(ListSelectionEvent e)7047         public void valueChanged(ListSelectionEvent e) {
7048             firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
7049                             Boolean.valueOf(false), Boolean.valueOf(true));
7050 
7051             // Using lead selection index to cover both cases: node selected and node
7052             // is focused but not selected (Ctrl+up/down)
7053             int focusedRow = JTable.this.getSelectionModel().getLeadSelectionIndex();
7054             int focusedCol = JTable.this.getColumnModel().getSelectionModel().
7055                                                     getLeadSelectionIndex();
7056 
7057             if (focusedRow != previousFocusedRow ||
7058                 focusedCol != previousFocusedCol) {
7059                 Accessible oldA = getAccessibleAt(previousFocusedRow, previousFocusedCol);
7060                 Accessible newA = getAccessibleAt(focusedRow, focusedCol);
7061                 firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
7062                                     oldA, newA);
7063                 previousFocusedRow = focusedRow;
7064                 previousFocusedCol = focusedCol;
7065             }
7066         }
7067 
7068 
7069 
7070 
7071     // AccessibleContext support
7072 
7073         /**
7074          * Get the AccessibleSelection associated with this object.  In the
7075          * implementation of the Java Accessibility API for this class,
7076          * return this object, which is responsible for implementing the
7077          * AccessibleSelection interface on behalf of itself.
7078          *
7079          * @return this object
7080          */
getAccessibleSelection()7081         public AccessibleSelection getAccessibleSelection() {
7082             return this;
7083         }
7084 
7085         /**
7086          * Gets the role of this object.
7087          *
7088          * @return an instance of AccessibleRole describing the role of the
7089          * object
7090          * @see AccessibleRole
7091          */
getAccessibleRole()7092         public AccessibleRole getAccessibleRole() {
7093             return AccessibleRole.TABLE;
7094         }
7095 
7096         /**
7097          * Returns the <code>Accessible</code> child, if one exists,
7098          * contained at the local coordinate <code>Point</code>.
7099          *
7100          * @param p the point defining the top-left corner of the
7101          *    <code>Accessible</code>, given in the coordinate space
7102          *    of the object's parent
7103          * @return the <code>Accessible</code>, if it exists,
7104          *    at the specified location; else <code>null</code>
7105          */
getAccessibleAt(Point p)7106         public Accessible getAccessibleAt(Point p) {
7107             int column = columnAtPoint(p);
7108             int row = rowAtPoint(p);
7109 
7110             if ((column != -1) && (row != -1)) {
7111                 if (row == getEditingRow() && column == getEditingColumn()) {
7112                     Component editor = getEditorComponent();
7113                     if (editor instanceof Accessible) {
7114                         return (Accessible) editor;
7115                     }
7116                 }
7117                 return new AccessibleJTableCell(JTable.this, row, column,
7118                       getAccessibleIndexAt(row, column));
7119             }
7120             return null;
7121         }
7122 
7123         /**
7124          * Returns the number of accessible children in the object.  If all
7125          * of the children of this object implement <code>Accessible</code>,
7126          * then this method should return the number of children of this object.
7127          *
7128          * @return the number of accessible children in the object
7129          */
getAccessibleChildrenCount()7130         public int getAccessibleChildrenCount() {
7131             return (JTable.this.getColumnCount() * JTable.this.getRowCount());
7132         }
7133 
7134         /**
7135          * Returns the nth <code>Accessible</code> child of the object.
7136          *
7137          * @param i zero-based index of child
7138          * @return the nth Accessible child of the object
7139          */
getAccessibleChild(int i)7140         public Accessible getAccessibleChild(int i) {
7141             if (i < 0 || i >= getAccessibleChildrenCount()) {
7142                 return null;
7143             } else {
7144                 // children increase across, and then down, for tables
7145                 // (arbitrary decision)
7146                 int column = getAccessibleColumnAtIndex(i);
7147                 int row = getAccessibleRowAtIndex(i);
7148 
7149                 if (row == getEditingRow() && column == getEditingColumn()) {
7150                     Component editor = getEditorComponent();
7151                     if (editor instanceof Accessible) {
7152                         return (Accessible) editor;
7153                     }
7154                 }
7155                 return new AccessibleJTableCell(JTable.this, row, column,
7156                       getAccessibleIndexAt(row, column));
7157             }
7158         }
7159 
7160     // AccessibleSelection support
7161 
7162         /**
7163          * Returns the number of <code>Accessible</code> children
7164          * currently selected.
7165          * If no children are selected, the return value will be 0.
7166          *
7167          * @return the number of items currently selected
7168          */
getAccessibleSelectionCount()7169         public int getAccessibleSelectionCount() {
7170             int rowsSel = JTable.this.getSelectedRowCount();
7171             int colsSel = JTable.this.getSelectedColumnCount();
7172 
7173             if (JTable.this.cellSelectionEnabled) { // a contiguous block
7174                 return rowsSel * colsSel;
7175 
7176             } else {
7177                 // a column swath and a row swath, with a shared block
7178                 if (JTable.this.getRowSelectionAllowed() &&
7179                     JTable.this.getColumnSelectionAllowed()) {
7180                     return rowsSel * JTable.this.getColumnCount() +
7181                            colsSel * JTable.this.getRowCount() -
7182                            rowsSel * colsSel;
7183 
7184                 // just one or more rows in selection
7185                 } else if (JTable.this.getRowSelectionAllowed()) {
7186                     return rowsSel * JTable.this.getColumnCount();
7187 
7188                 // just one or more rows in selection
7189                 } else if (JTable.this.getColumnSelectionAllowed()) {
7190                     return colsSel * JTable.this.getRowCount();
7191 
7192                 } else {
7193                     return 0;    // JTable doesn't allow selections
7194                 }
7195             }
7196         }
7197 
7198         /**
7199          * Returns an <code>Accessible</code> representing the
7200          * specified selected child in the object.  If there
7201          * isn't a selection, or there are fewer children selected
7202          * than the integer passed in, the return
7203          * value will be <code>null</code>.
7204          * <p>Note that the index represents the i-th selected child, which
7205          * is different from the i-th child.
7206          *
7207          * @param i the zero-based index of selected children
7208          * @return the i-th selected child
7209          * @see #getAccessibleSelectionCount
7210          */
getAccessibleSelection(int i)7211         public Accessible getAccessibleSelection(int i) {
7212             if (i < 0 || i > getAccessibleSelectionCount()) {
7213                 return null;
7214             }
7215 
7216             int rowsSel = JTable.this.getSelectedRowCount();
7217             int colsSel = JTable.this.getSelectedColumnCount();
7218             int[] rowIndicies = getSelectedRows();
7219             int[] colIndicies = getSelectedColumns();
7220             int ttlCols = JTable.this.getColumnCount();
7221             int ttlRows = JTable.this.getRowCount();
7222             int r;
7223             int c;
7224 
7225             if (JTable.this.cellSelectionEnabled) { // a contiguous block
7226                 r = rowIndicies[i / colsSel];
7227                 c = colIndicies[i % colsSel];
7228                 return getAccessibleChild((r * ttlCols) + c);
7229             } else {
7230 
7231                 // a column swath and a row swath, with a shared block
7232                 if (JTable.this.getRowSelectionAllowed() &&
7233                     JTable.this.getColumnSelectionAllowed()) {
7234 
7235                     // Situation:
7236                     //   We have a table, like the 6x3 table below,
7237                     //   wherein three colums and one row selected
7238                     //   (selected cells marked with "*", unselected "0"):
7239                     //
7240                     //            0 * 0 * * 0
7241                     //            * * * * * *
7242                     //            0 * 0 * * 0
7243                     //
7244 
7245                     // State machine below walks through the array of
7246                     // selected rows in two states: in a selected row,
7247                     // and not in one; continuing until we are in a row
7248                     // in which the ith selection exists.  Then we return
7249                     // the appropriate cell.  In the state machine, we
7250                     // always do rows above the "current" selected row first,
7251                     // then the cells in the selected row.  If we're done
7252                     // with the state machine before finding the requested
7253                     // selected child, we handle the rows below the last
7254                     // selected row at the end.
7255                     //
7256                     int curIndex = i;
7257                     final int IN_ROW = 0;
7258                     final int NOT_IN_ROW = 1;
7259                     int state = (rowIndicies[0] == 0 ? IN_ROW : NOT_IN_ROW);
7260                     int j = 0;
7261                     int prevRow = -1;
7262                     while (j < rowIndicies.length) {
7263                         switch (state) {
7264 
7265                         case IN_ROW:   // on individual row full of selections
7266                             if (curIndex < ttlCols) { // it's here!
7267                                 c = curIndex % ttlCols;
7268                                 r = rowIndicies[j];
7269                                 return getAccessibleChild((r * ttlCols) + c);
7270                             } else {                               // not here
7271                                 curIndex -= ttlCols;
7272                             }
7273                             // is the next row in table selected or not?
7274                             if (j + 1 == rowIndicies.length ||
7275                                 rowIndicies[j] != rowIndicies[j+1] - 1) {
7276                                 state = NOT_IN_ROW;
7277                                 prevRow = rowIndicies[j];
7278                             }
7279                             j++;  // we didn't return earlier, so go to next row
7280                             break;
7281 
7282                         case NOT_IN_ROW:  // sparse bunch of rows of selections
7283                             if (curIndex <
7284                                 (colsSel * (rowIndicies[j] -
7285                                 (prevRow == -1 ? 0 : (prevRow + 1))))) {
7286 
7287                                 // it's here!
7288                                 c = colIndicies[curIndex % colsSel];
7289                                 r = (j > 0 ? rowIndicies[j-1] + 1 : 0)
7290                                     + curIndex / colsSel;
7291                                 return getAccessibleChild((r * ttlCols) + c);
7292                             } else {                               // not here
7293                                 curIndex -= colsSel * (rowIndicies[j] -
7294                                 (prevRow == -1 ? 0 : (prevRow + 1)));
7295                             }
7296                             state = IN_ROW;
7297                             break;
7298                         }
7299                     }
7300                     // we got here, so we didn't find it yet; find it in
7301                     // the last sparse bunch of rows
7302                     if (curIndex <
7303                         (colsSel * (ttlRows -
7304                         (prevRow == -1 ? 0 : (prevRow + 1))))) { // it's here!
7305                         c = colIndicies[curIndex % colsSel];
7306                         r = rowIndicies[j-1] + curIndex / colsSel + 1;
7307                         return getAccessibleChild((r * ttlCols) + c);
7308                     } else {                               // not here
7309                         // we shouldn't get to this spot in the code!
7310 //                      System.out.println("Bug in AccessibleJTable.getAccessibleSelection()");
7311                     }
7312 
7313                 // one or more rows selected
7314                 } else if (JTable.this.getRowSelectionAllowed()) {
7315                     c = i % ttlCols;
7316                     r = rowIndicies[i / ttlCols];
7317                     return getAccessibleChild((r * ttlCols) + c);
7318 
7319                 // one or more columns selected
7320                 } else if (JTable.this.getColumnSelectionAllowed()) {
7321                     c = colIndicies[i % colsSel];
7322                     r = i / colsSel;
7323                     return getAccessibleChild((r * ttlCols) + c);
7324                 }
7325             }
7326             return null;
7327         }
7328 
7329         /**
7330          * Determines if the current child of this object is selected.
7331          *
7332          * @param i the zero-based index of the child in this
7333          *    <code>Accessible</code> object
7334          * @return true if the current child of this object is selected
7335          * @see AccessibleContext#getAccessibleChild
7336          */
isAccessibleChildSelected(int i)7337         public boolean isAccessibleChildSelected(int i) {
7338             int column = getAccessibleColumnAtIndex(i);
7339             int row = getAccessibleRowAtIndex(i);
7340             return JTable.this.isCellSelected(row, column);
7341         }
7342 
7343         /**
7344          * Adds the specified <code>Accessible</code> child of the
7345          * object to the object's selection.  If the object supports
7346          * multiple selections, the specified child is added to
7347          * any existing selection, otherwise
7348          * it replaces any existing selection in the object.  If the
7349          * specified child is already selected, this method has no effect.
7350          * <p>
7351          * This method only works on <code>JTable</code>s which have
7352          * individual cell selection enabled.
7353          *
7354          * @param i the zero-based index of the child
7355          * @see AccessibleContext#getAccessibleChild
7356          */
addAccessibleSelection(int i)7357         public void addAccessibleSelection(int i) {
7358             // TIGER - 4495286
7359             int column = getAccessibleColumnAtIndex(i);
7360             int row = getAccessibleRowAtIndex(i);
7361             JTable.this.changeSelection(row, column, true, false);
7362         }
7363 
7364         /**
7365          * Removes the specified child of the object from the object's
7366          * selection.  If the specified item isn't currently selected, this
7367          * method has no effect.
7368          * <p>
7369          * This method only works on <code>JTables</code> which have
7370          * individual cell selection enabled.
7371          *
7372          * @param i the zero-based index of the child
7373          * @see AccessibleContext#getAccessibleChild
7374          */
removeAccessibleSelection(int i)7375         public void removeAccessibleSelection(int i) {
7376             if (JTable.this.cellSelectionEnabled) {
7377                 int column = getAccessibleColumnAtIndex(i);
7378                 int row = getAccessibleRowAtIndex(i);
7379                 JTable.this.removeRowSelectionInterval(row, row);
7380                 JTable.this.removeColumnSelectionInterval(column, column);
7381             }
7382         }
7383 
7384         /**
7385          * Clears the selection in the object, so that no children in the
7386          * object are selected.
7387          */
clearAccessibleSelection()7388         public void clearAccessibleSelection() {
7389             JTable.this.clearSelection();
7390         }
7391 
7392         /**
7393          * Causes every child of the object to be selected, but only
7394          * if the <code>JTable</code> supports multiple selections,
7395          * and if individual cell selection is enabled.
7396          */
selectAllAccessibleSelection()7397         public void selectAllAccessibleSelection() {
7398             if (JTable.this.cellSelectionEnabled) {
7399                 JTable.this.selectAll();
7400             }
7401         }
7402 
7403         // begin AccessibleExtendedTable implementation -------------
7404 
7405         /**
7406          * Returns the row number of an index in the table.
7407          *
7408          * @param index the zero-based index in the table
7409          * @return the zero-based row of the table if one exists;
7410          * otherwise -1.
7411          * @since 1.4
7412          */
getAccessibleRow(int index)7413         public int getAccessibleRow(int index) {
7414             return getAccessibleRowAtIndex(index);
7415         }
7416 
7417         /**
7418          * Returns the column number of an index in the table.
7419          *
7420          * @param index the zero-based index in the table
7421          * @return the zero-based column of the table if one exists;
7422          * otherwise -1.
7423          * @since 1.4
7424          */
getAccessibleColumn(int index)7425         public int getAccessibleColumn(int index) {
7426             return getAccessibleColumnAtIndex(index);
7427         }
7428 
7429         /**
7430          * Returns the index at a row and column in the table.
7431          *
7432          * @param r zero-based row of the table
7433          * @param c zero-based column of the table
7434          * @return the zero-based index in the table if one exists;
7435          * otherwise -1.
7436          * @since 1.4
7437          */
getAccessibleIndex(int r, int c)7438         public int getAccessibleIndex(int r, int c) {
7439             return getAccessibleIndexAt(r, c);
7440         }
7441 
7442         // end of AccessibleExtendedTable implementation ------------
7443 
7444         // start of AccessibleTable implementation ------------------
7445 
7446         private Accessible caption;
7447         private Accessible summary;
7448         private Accessible [] rowDescription;
7449         private Accessible [] columnDescription;
7450 
7451         /**
7452          * Gets the <code>AccessibleTable</code> associated with this
7453          * object.  In the implementation of the Java Accessibility
7454          * API for this class, return this object, which is responsible
7455          * for implementing the <code>AccessibleTables</code> interface
7456          * on behalf of itself.
7457          *
7458          * @return this object
7459          * @since 1.3
7460          */
getAccessibleTable()7461         public AccessibleTable getAccessibleTable() {
7462             return this;
7463         }
7464 
7465         /**
7466          * Returns the caption for the table.
7467          *
7468          * @return the caption for the table
7469          * @since 1.3
7470          */
getAccessibleCaption()7471         public Accessible getAccessibleCaption() {
7472             return this.caption;
7473         }
7474 
7475         /**
7476          * Sets the caption for the table.
7477          *
7478          * @param a the caption for the table
7479          * @since 1.3
7480          */
setAccessibleCaption(Accessible a)7481         public void setAccessibleCaption(Accessible a) {
7482             Accessible oldCaption = caption;
7483             this.caption = a;
7484             firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_CAPTION_CHANGED,
7485                                oldCaption, this.caption);
7486         }
7487 
7488         /**
7489          * Returns the summary description of the table.
7490          *
7491          * @return the summary description of the table
7492          * @since 1.3
7493          */
getAccessibleSummary()7494         public Accessible getAccessibleSummary() {
7495             return this.summary;
7496         }
7497 
7498         /**
7499          * Sets the summary description of the table.
7500          *
7501          * @param a the summary description of the table
7502          * @since 1.3
7503          */
setAccessibleSummary(Accessible a)7504         public void setAccessibleSummary(Accessible a) {
7505             Accessible oldSummary = summary;
7506             this.summary = a;
7507             firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_SUMMARY_CHANGED,
7508                                oldSummary, this.summary);
7509         }
7510 
7511         /*
7512          * Returns the total number of rows in this table.
7513          *
7514          * @return the total number of rows in this table
7515          */
getAccessibleRowCount()7516         public int getAccessibleRowCount() {
7517             return JTable.this.getRowCount();
7518         }
7519 
7520         /*
7521          * Returns the total number of columns in the table.
7522          *
7523          * @return the total number of columns in the table
7524          */
getAccessibleColumnCount()7525         public int getAccessibleColumnCount() {
7526             return JTable.this.getColumnCount();
7527         }
7528 
7529         /*
7530          * Returns the <code>Accessible</code> at a specified row
7531          * and column in the table.
7532          *
7533          * @param r zero-based row of the table
7534          * @param c zero-based column of the table
7535          * @return the <code>Accessible</code> at the specified row and column
7536          * in the table
7537          */
getAccessibleAt(int r, int c)7538         public Accessible getAccessibleAt(int r, int c) {
7539             return getAccessibleChild((r * getAccessibleColumnCount()) + c);
7540         }
7541 
7542         /**
7543          * Returns the number of rows occupied by the <code>Accessible</code>
7544          * at a specified row and column in the table.
7545          *
7546          * @return the number of rows occupied by the <code>Accessible</code>
7547          *     at a specified row and column in the table
7548          * @since 1.3
7549          */
getAccessibleRowExtentAt(int r, int c)7550         public int getAccessibleRowExtentAt(int r, int c) {
7551             return 1;
7552         }
7553 
7554         /**
7555          * Returns the number of columns occupied by the
7556          * <code>Accessible</code> at a given (row, column).
7557          *
7558          * @return the number of columns occupied by the <code>Accessible</code>
7559          *     at a specified row and column in the table
7560          * @since 1.3
7561          */
getAccessibleColumnExtentAt(int r, int c)7562         public int getAccessibleColumnExtentAt(int r, int c) {
7563             return 1;
7564         }
7565 
7566         /**
7567          * Returns the row headers as an <code>AccessibleTable</code>.
7568          *
7569          * @return an <code>AccessibleTable</code> representing the row
7570          * headers
7571          * @since 1.3
7572          */
getAccessibleRowHeader()7573         public AccessibleTable getAccessibleRowHeader() {
7574             // row headers are not supported
7575             return null;
7576         }
7577 
7578         /**
7579          * Sets the row headers as an <code>AccessibleTable</code>.
7580          *
7581          * @param a an <code>AccessibleTable</code> representing the row
7582          *  headers
7583          * @since 1.3
7584          */
setAccessibleRowHeader(AccessibleTable a)7585         public void setAccessibleRowHeader(AccessibleTable a) {
7586             // row headers are not supported
7587         }
7588 
7589         /**
7590          * Returns the column headers as an <code>AccessibleTable</code>.
7591          *
7592          *  @return an <code>AccessibleTable</code> representing the column
7593          *          headers, or <code>null</code> if the table header is
7594          *          <code>null</code>
7595          * @since 1.3
7596          */
getAccessibleColumnHeader()7597         public AccessibleTable getAccessibleColumnHeader() {
7598             JTableHeader header = JTable.this.getTableHeader();
7599             return header == null ? null : new AccessibleTableHeader(header);
7600         }
7601 
7602         /*
7603          * Private class representing a table column header
7604          */
7605         private class AccessibleTableHeader implements AccessibleTable {
7606             private JTableHeader header;
7607             private TableColumnModel headerModel;
7608 
AccessibleTableHeader(JTableHeader header)7609             AccessibleTableHeader(JTableHeader header) {
7610                 this.header = header;
7611                 this.headerModel = header.getColumnModel();
7612             }
7613 
7614             /**
7615              * Returns the caption for the table.
7616              *
7617              * @return the caption for the table
7618              */
getAccessibleCaption()7619             public Accessible getAccessibleCaption() { return null; }
7620 
7621 
7622             /**
7623              * Sets the caption for the table.
7624              *
7625              * @param a the caption for the table
7626              */
setAccessibleCaption(Accessible a)7627             public void setAccessibleCaption(Accessible a) {}
7628 
7629             /**
7630              * Returns the summary description of the table.
7631              *
7632              * @return the summary description of the table
7633              */
getAccessibleSummary()7634             public Accessible getAccessibleSummary() { return null; }
7635 
7636             /**
7637              * Sets the summary description of the table
7638              *
7639              * @param a the summary description of the table
7640              */
setAccessibleSummary(Accessible a)7641             public void setAccessibleSummary(Accessible a) {}
7642 
7643             /**
7644              * Returns the number of rows in the table.
7645              *
7646              * @return the number of rows in the table
7647              */
getAccessibleRowCount()7648             public int getAccessibleRowCount() { return 1; }
7649 
7650             /**
7651              * Returns the number of columns in the table.
7652              *
7653              * @return the number of columns in the table
7654              */
getAccessibleColumnCount()7655             public int getAccessibleColumnCount() {
7656                 return headerModel.getColumnCount();
7657             }
7658 
7659             /**
7660              * Returns the Accessible at a specified row and column
7661              * in the table.
7662              *
7663              * @param row zero-based row of the table
7664              * @param column zero-based column of the table
7665              * @return the Accessible at the specified row and column
7666              */
getAccessibleAt(int row, int column)7667             public Accessible getAccessibleAt(int row, int column) {
7668 
7669 
7670                 // TIGER - 4715503
7671                 TableColumn aColumn = headerModel.getColumn(column);
7672                 TableCellRenderer renderer = aColumn.getHeaderRenderer();
7673                 if (renderer == null) {
7674                     renderer = header.getDefaultRenderer();
7675                 }
7676                 Component component = renderer.getTableCellRendererComponent(
7677                                   header.getTable(),
7678                                   aColumn.getHeaderValue(), false, false,
7679                                   -1, column);
7680 
7681                 return new AccessibleJTableHeaderCell(row, column,
7682                                                       JTable.this.getTableHeader(),
7683                                                       component);
7684             }
7685 
7686             /**
7687              * Returns the number of rows occupied by the Accessible at
7688              * a specified row and column in the table.
7689              *
7690              * @return the number of rows occupied by the Accessible at a
7691              * given specified (row, column)
7692              */
getAccessibleRowExtentAt(int r, int c)7693             public int getAccessibleRowExtentAt(int r, int c) { return 1; }
7694 
7695             /**
7696              * Returns the number of columns occupied by the Accessible at
7697              * a specified row and column in the table.
7698              *
7699              * @return the number of columns occupied by the Accessible at a
7700              * given specified row and column
7701              */
getAccessibleColumnExtentAt(int r, int c)7702             public int getAccessibleColumnExtentAt(int r, int c) { return 1; }
7703 
7704             /**
7705              * Returns the row headers as an AccessibleTable.
7706              *
7707              * @return an AccessibleTable representing the row
7708              * headers
7709              */
getAccessibleRowHeader()7710             public AccessibleTable getAccessibleRowHeader() { return null; }
7711 
7712             /**
7713              * Sets the row headers.
7714              *
7715              * @param table an AccessibleTable representing the
7716              * row headers
7717              */
setAccessibleRowHeader(AccessibleTable table)7718             public void setAccessibleRowHeader(AccessibleTable table) {}
7719 
7720             /**
7721              * Returns the column headers as an AccessibleTable.
7722              *
7723              * @return an AccessibleTable representing the column
7724              * headers
7725              */
getAccessibleColumnHeader()7726             public AccessibleTable getAccessibleColumnHeader() { return null; }
7727 
7728             /**
7729              * Sets the column headers.
7730              *
7731              * @param table an AccessibleTable representing the
7732              * column headers
7733              * @since 1.3
7734              */
setAccessibleColumnHeader(AccessibleTable table)7735             public void setAccessibleColumnHeader(AccessibleTable table) {}
7736 
7737             /**
7738              * Returns the description of the specified row in the table.
7739              *
7740              * @param r zero-based row of the table
7741              * @return the description of the row
7742              * @since 1.3
7743              */
getAccessibleRowDescription(int r)7744             public Accessible getAccessibleRowDescription(int r) { return null; }
7745 
7746             /**
7747              * Sets the description text of the specified row of the table.
7748              *
7749              * @param r zero-based row of the table
7750              * @param a the description of the row
7751              * @since 1.3
7752              */
setAccessibleRowDescription(int r, Accessible a)7753             public void setAccessibleRowDescription(int r, Accessible a) {}
7754 
7755             /**
7756              * Returns the description text of the specified column in the table.
7757              *
7758              * @param c zero-based column of the table
7759              * @return the text description of the column
7760              * @since 1.3
7761              */
getAccessibleColumnDescription(int c)7762             public Accessible getAccessibleColumnDescription(int c) { return null; }
7763 
7764             /**
7765              * Sets the description text of the specified column in the table.
7766              *
7767              * @param c zero-based column of the table
7768              * @param a the text description of the column
7769              * @since 1.3
7770              */
setAccessibleColumnDescription(int c, Accessible a)7771             public void setAccessibleColumnDescription(int c, Accessible a) {}
7772 
7773             /**
7774              * Returns a boolean value indicating whether the accessible at
7775              * a specified row and column is selected.
7776              *
7777              * @param r zero-based row of the table
7778              * @param c zero-based column of the table
7779              * @return the boolean value true if the accessible at the
7780              * row and column is selected. Otherwise, the boolean value
7781              * false
7782              * @since 1.3
7783              */
isAccessibleSelected(int r, int c)7784             public boolean isAccessibleSelected(int r, int c) { return false; }
7785 
7786             /**
7787              * Returns a boolean value indicating whether the specified row
7788              * is selected.
7789              *
7790              * @param r zero-based row of the table
7791              * @return the boolean value true if the specified row is selected.
7792              * Otherwise, false.
7793              * @since 1.3
7794              */
isAccessibleRowSelected(int r)7795             public boolean isAccessibleRowSelected(int r) { return false; }
7796 
7797             /**
7798              * Returns a boolean value indicating whether the specified column
7799              * is selected.
7800              *
7801              * @param c zero-based column of the table
7802              * @return the boolean value true if the specified column is selected.
7803              * Otherwise, false.
7804              * @since 1.3
7805              */
isAccessibleColumnSelected(int c)7806             public boolean isAccessibleColumnSelected(int c) { return false; }
7807 
7808             /**
7809              * Returns the selected rows in a table.
7810              *
7811              * @return an array of selected rows where each element is a
7812              * zero-based row of the table
7813              * @since 1.3
7814              */
getSelectedAccessibleRows()7815             public int [] getSelectedAccessibleRows() { return new int[0]; }
7816 
7817             /**
7818              * Returns the selected columns in a table.
7819              *
7820              * @return an array of selected columns where each element is a
7821              * zero-based column of the table
7822              * @since 1.3
7823              */
getSelectedAccessibleColumns()7824             public int [] getSelectedAccessibleColumns() { return new int[0]; }
7825         }
7826 
7827 
7828         /**
7829          * Sets the column headers as an <code>AccessibleTable</code>.
7830          *
7831          * @param a an <code>AccessibleTable</code> representing the
7832          * column headers
7833          * @since 1.3
7834          */
setAccessibleColumnHeader(AccessibleTable a)7835         public void setAccessibleColumnHeader(AccessibleTable a) {
7836             // XXX not implemented
7837         }
7838 
7839         /**
7840          * Returns the description of the specified row in the table.
7841          *
7842          * @param r zero-based row of the table
7843          * @return the description of the row
7844          * @since 1.3
7845          */
getAccessibleRowDescription(int r)7846         public Accessible getAccessibleRowDescription(int r) {
7847             if (r < 0 || r >= getAccessibleRowCount()) {
7848                 throw new IllegalArgumentException(Integer.toString(r));
7849             }
7850             if (rowDescription == null) {
7851                 return null;
7852             } else {
7853                 return rowDescription[r];
7854             }
7855         }
7856 
7857         /**
7858          * Sets the description text of the specified row of the table.
7859          *
7860          * @param r zero-based row of the table
7861          * @param a the description of the row
7862          * @since 1.3
7863          */
setAccessibleRowDescription(int r, Accessible a)7864         public void setAccessibleRowDescription(int r, Accessible a) {
7865             if (r < 0 || r >= getAccessibleRowCount()) {
7866                 throw new IllegalArgumentException(Integer.toString(r));
7867             }
7868             if (rowDescription == null) {
7869                 int numRows = getAccessibleRowCount();
7870                 rowDescription = new Accessible[numRows];
7871             }
7872             rowDescription[r] = a;
7873         }
7874 
7875         /**
7876          * Returns the description of the specified column in the table.
7877          *
7878          * @param c zero-based column of the table
7879          * @return the description of the column
7880          * @since 1.3
7881          */
getAccessibleColumnDescription(int c)7882         public Accessible getAccessibleColumnDescription(int c) {
7883             if (c < 0 || c >= getAccessibleColumnCount()) {
7884                 throw new IllegalArgumentException(Integer.toString(c));
7885             }
7886             if (columnDescription == null) {
7887                 return null;
7888             } else {
7889                 return columnDescription[c];
7890             }
7891         }
7892 
7893         /**
7894          * Sets the description text of the specified column of the table.
7895          *
7896          * @param c zero-based column of the table
7897          * @param a the description of the column
7898          * @since 1.3
7899          */
setAccessibleColumnDescription(int c, Accessible a)7900         public void setAccessibleColumnDescription(int c, Accessible a) {
7901             if (c < 0 || c >= getAccessibleColumnCount()) {
7902                 throw new IllegalArgumentException(Integer.toString(c));
7903             }
7904             if (columnDescription == null) {
7905                 int numColumns = getAccessibleColumnCount();
7906                 columnDescription = new Accessible[numColumns];
7907             }
7908             columnDescription[c] = a;
7909         }
7910 
7911         /**
7912          * Returns a boolean value indicating whether the accessible at a
7913          * given (row, column) is selected.
7914          *
7915          * @param r zero-based row of the table
7916          * @param c zero-based column of the table
7917          * @return the boolean value true if the accessible at (row, column)
7918          *     is selected; otherwise, the boolean value false
7919          * @since 1.3
7920          */
isAccessibleSelected(int r, int c)7921         public boolean isAccessibleSelected(int r, int c) {
7922             return JTable.this.isCellSelected(r, c);
7923         }
7924 
7925         /**
7926          * Returns a boolean value indicating whether the specified row
7927          * is selected.
7928          *
7929          * @param r zero-based row of the table
7930          * @return the boolean value true if the specified row is selected;
7931          *     otherwise, false
7932          * @since 1.3
7933          */
isAccessibleRowSelected(int r)7934         public boolean isAccessibleRowSelected(int r) {
7935             return JTable.this.isRowSelected(r);
7936         }
7937 
7938         /**
7939          * Returns a boolean value indicating whether the specified column
7940          * is selected.
7941          *
7942          * @param c zero-based column of the table
7943          * @return the boolean value true if the specified column is selected;
7944          *     otherwise, false
7945          * @since 1.3
7946          */
isAccessibleColumnSelected(int c)7947         public boolean isAccessibleColumnSelected(int c) {
7948             return JTable.this.isColumnSelected(c);
7949         }
7950 
7951         /**
7952          * Returns the selected rows in a table.
7953          *
7954          * @return an array of selected rows where each element is a
7955          *     zero-based row of the table
7956          * @since 1.3
7957          */
getSelectedAccessibleRows()7958         public int [] getSelectedAccessibleRows() {
7959             return JTable.this.getSelectedRows();
7960         }
7961 
7962         /**
7963          * Returns the selected columns in a table.
7964          *
7965          * @return an array of selected columns where each element is a
7966          *     zero-based column of the table
7967          * @since 1.3
7968          */
getSelectedAccessibleColumns()7969         public int [] getSelectedAccessibleColumns() {
7970             return JTable.this.getSelectedColumns();
7971         }
7972 
7973         /**
7974          * Returns the row at a given index into the table.
7975          *
7976          * @param i zero-based index into the table
7977          * @return the row at a given index
7978          * @since 1.3
7979          */
getAccessibleRowAtIndex(int i)7980         public int getAccessibleRowAtIndex(int i) {
7981             int columnCount = getAccessibleColumnCount();
7982             if (columnCount == 0) {
7983                 return -1;
7984             } else {
7985                 return (i / columnCount);
7986             }
7987         }
7988 
7989         /**
7990          * Returns the column at a given index into the table.
7991          *
7992          * @param i zero-based index into the table
7993          * @return the column at a given index
7994          * @since 1.3
7995          */
getAccessibleColumnAtIndex(int i)7996         public int getAccessibleColumnAtIndex(int i) {
7997             int columnCount = getAccessibleColumnCount();
7998             if (columnCount == 0) {
7999                 return -1;
8000             } else {
8001                 return (i % columnCount);
8002             }
8003         }
8004 
8005         /**
8006          * Returns the index at a given (row, column) in the table.
8007          *
8008          * @param r zero-based row of the table
8009          * @param c zero-based column of the table
8010          * @return the index into the table
8011          * @since 1.3
8012          */
getAccessibleIndexAt(int r, int c)8013         public int getAccessibleIndexAt(int r, int c) {
8014             return ((r * getAccessibleColumnCount()) + c);
8015         }
8016 
8017         // end of AccessibleTable implementation --------------------
8018 
8019         /**
8020          * The class provides an implementation of the Java Accessibility
8021          * API appropriate to table cells.
8022          */
8023         protected class AccessibleJTableCell extends AccessibleContext
8024             implements Accessible, AccessibleComponent {
8025 
8026             private JTable parent;
8027             private int row;
8028             private int column;
8029             private int index;
8030 
8031             /**
8032              *  Constructs an <code>AccessibleJTableHeaderEntry</code>.
8033              *
8034              * @param t a {@code JTable}
8035              * @param r an {@code int} specifying a row
8036              * @param c an {@code int} specifying a column
8037              * @param i an {@code int} specifying the index to this cell
8038              * @since 1.4
8039              */
AccessibleJTableCell(JTable t, int r, int c, int i)8040             public AccessibleJTableCell(JTable t, int r, int c, int i) {
8041                 parent = t;
8042                 row = r;
8043                 column = c;
8044                 index = i;
8045                 this.setAccessibleParent(parent);
8046             }
8047 
8048             /**
8049              * Gets the <code>AccessibleContext</code> associated with this
8050              * component. In the implementation of the Java Accessibility
8051              * API for this class, return this object, which is its own
8052              * <code>AccessibleContext</code>.
8053              *
8054              * @return this object
8055              */
getAccessibleContext()8056             public AccessibleContext getAccessibleContext() {
8057                 return this;
8058             }
8059 
8060             /**
8061              * Gets the AccessibleContext for the table cell renderer.
8062              *
8063              * @return the <code>AccessibleContext</code> for the table
8064              * cell renderer if one exists;
8065              * otherwise, returns <code>null</code>.
8066              * @since 1.6
8067              */
getCurrentAccessibleContext()8068             protected AccessibleContext getCurrentAccessibleContext() {
8069                 TableColumn aColumn = getColumnModel().getColumn(column);
8070                 TableCellRenderer renderer = aColumn.getCellRenderer();
8071                 if (renderer == null) {
8072                     Class<?> columnClass = getColumnClass(column);
8073                     renderer = getDefaultRenderer(columnClass);
8074                 }
8075                 Component component = renderer.getTableCellRendererComponent(
8076                                   JTable.this, getValueAt(row, column),
8077                                   false, false, row, column);
8078                 if (component instanceof Accessible) {
8079                     return component.getAccessibleContext();
8080                 } else {
8081                     return null;
8082                 }
8083             }
8084 
8085             /**
8086              * Gets the table cell renderer component.
8087              *
8088              * @return the table cell renderer component if one exists;
8089              * otherwise, returns <code>null</code>.
8090              * @since 1.6
8091              */
getCurrentComponent()8092             protected Component getCurrentComponent() {
8093                 TableColumn aColumn = getColumnModel().getColumn(column);
8094                 TableCellRenderer renderer = aColumn.getCellRenderer();
8095                 if (renderer == null) {
8096                     Class<?> columnClass = getColumnClass(column);
8097                     renderer = getDefaultRenderer(columnClass);
8098                 }
8099                 return renderer.getTableCellRendererComponent(
8100                                   JTable.this, null, false, false,
8101                                   row, column);
8102             }
8103 
8104         // AccessibleContext methods
8105 
8106             /**
8107              * Gets the accessible name of this object.
8108              *
8109              * @return the localized name of the object; <code>null</code>
8110              *     if this object does not have a name
8111              */
getAccessibleName()8112             public String getAccessibleName() {
8113                 AccessibleContext ac = getCurrentAccessibleContext();
8114                 if (ac != null) {
8115                     String name = ac.getAccessibleName();
8116                     if ((name != null) && (name != "")) {
8117                         // return the cell renderer's AccessibleName
8118                         return name;
8119                     }
8120                 }
8121                 if ((accessibleName != null) && (accessibleName != "")) {
8122                     return accessibleName;
8123                 } else {
8124                     // fall back to the client property
8125                     return (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
8126                 }
8127             }
8128 
8129             /**
8130              * Sets the localized accessible name of this object.
8131              *
8132              * @param s the new localized name of the object
8133              */
setAccessibleName(String s)8134             public void setAccessibleName(String s) {
8135                 AccessibleContext ac = getCurrentAccessibleContext();
8136                 if (ac != null) {
8137                     ac.setAccessibleName(s);
8138                 } else {
8139                     super.setAccessibleName(s);
8140                 }
8141             }
8142 
8143             //
8144             // *** should check toolTip text for desc. (needs MouseEvent)
8145             //
8146             /**
8147              * Gets the accessible description of this object.
8148              *
8149              * @return the localized description of the object;
8150              *     <code>null</code> if this object does not have
8151              *     a description
8152              */
getAccessibleDescription()8153             public String getAccessibleDescription() {
8154                 AccessibleContext ac = getCurrentAccessibleContext();
8155                 if (ac != null) {
8156                     return ac.getAccessibleDescription();
8157                 } else {
8158                     return super.getAccessibleDescription();
8159                 }
8160             }
8161 
8162             /**
8163              * Sets the accessible description of this object.
8164              *
8165              * @param s the new localized description of the object
8166              */
setAccessibleDescription(String s)8167             public void setAccessibleDescription(String s) {
8168                 AccessibleContext ac = getCurrentAccessibleContext();
8169                 if (ac != null) {
8170                     ac.setAccessibleDescription(s);
8171                 } else {
8172                     super.setAccessibleDescription(s);
8173                 }
8174             }
8175 
8176             /**
8177              * Gets the role of this object.
8178              *
8179              * @return an instance of <code>AccessibleRole</code>
8180              *      describing the role of the object
8181              * @see AccessibleRole
8182              */
getAccessibleRole()8183             public AccessibleRole getAccessibleRole() {
8184                 AccessibleContext ac = getCurrentAccessibleContext();
8185                 if (ac != null) {
8186                     return ac.getAccessibleRole();
8187                 } else {
8188                     return AccessibleRole.UNKNOWN;
8189                 }
8190             }
8191 
8192             /**
8193              * Gets the state set of this object.
8194              *
8195              * @return an instance of <code>AccessibleStateSet</code>
8196              *     containing the current state set of the object
8197              * @see AccessibleState
8198              */
getAccessibleStateSet()8199             public AccessibleStateSet getAccessibleStateSet() {
8200                 AccessibleContext ac = getCurrentAccessibleContext();
8201                 AccessibleStateSet as = null;
8202 
8203                 if (ac != null) {
8204                     as = ac.getAccessibleStateSet();
8205                 }
8206                 if (as == null) {
8207                     as = new AccessibleStateSet();
8208                 }
8209                 Rectangle rjt = JTable.this.getVisibleRect();
8210                 Rectangle rcell = JTable.this.getCellRect(row, column, false);
8211                 if (rjt.intersects(rcell)) {
8212                     as.add(AccessibleState.SHOWING);
8213                 } else {
8214                     if (as.contains(AccessibleState.SHOWING)) {
8215                          as.remove(AccessibleState.SHOWING);
8216                     }
8217                 }
8218                 if (parent.isCellSelected(row, column)) {
8219                     as.add(AccessibleState.SELECTED);
8220                 } else if (as.contains(AccessibleState.SELECTED)) {
8221                     as.remove(AccessibleState.SELECTED);
8222                 }
8223                 if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
8224                     as.add(AccessibleState.ACTIVE);
8225                 }
8226                 as.add(AccessibleState.TRANSIENT);
8227                 return as;
8228             }
8229 
8230             /**
8231              * Gets the <code>Accessible</code> parent of this object.
8232              *
8233              * @return the Accessible parent of this object;
8234              *     <code>null</code> if this object does not
8235              *     have an <code>Accessible</code> parent
8236              */
getAccessibleParent()8237             public Accessible getAccessibleParent() {
8238                 return parent;
8239             }
8240 
8241             /**
8242              * Gets the index of this object in its accessible parent.
8243              *
8244              * @return the index of this object in its parent; -1 if this
8245              *     object does not have an accessible parent
8246              * @see #getAccessibleParent
8247              */
getAccessibleIndexInParent()8248             public int getAccessibleIndexInParent() {
8249                 return index;
8250             }
8251 
8252             /**
8253              * Returns the number of accessible children in the object.
8254              *
8255              * @return the number of accessible children in the object
8256              */
getAccessibleChildrenCount()8257             public int getAccessibleChildrenCount() {
8258                 AccessibleContext ac = getCurrentAccessibleContext();
8259                 if (ac != null) {
8260                     return ac.getAccessibleChildrenCount();
8261                 } else {
8262                     return 0;
8263                 }
8264             }
8265 
8266             /**
8267              * Returns the specified <code>Accessible</code> child of the
8268              * object.
8269              *
8270              * @param i zero-based index of child
8271              * @return the <code>Accessible</code> child of the object
8272              */
getAccessibleChild(int i)8273             public Accessible getAccessibleChild(int i) {
8274                 AccessibleContext ac = getCurrentAccessibleContext();
8275                 if (ac != null) {
8276                     Accessible accessibleChild = ac.getAccessibleChild(i);
8277                     ac.setAccessibleParent(this);
8278                     return accessibleChild;
8279                 } else {
8280                     return null;
8281                 }
8282             }
8283 
8284             /**
8285              * Gets the locale of the component. If the component
8286              * does not have a locale, then the locale of its parent
8287              * is returned.
8288              *
8289              * @return this component's locale; if this component does
8290              *    not have a locale, the locale of its parent is returned
8291              * @exception IllegalComponentStateException if the
8292              *    <code>Component</code> does not have its own locale
8293              *    and has not yet been added to a containment hierarchy
8294              *    such that the locale can be determined from the
8295              *    containing parent
8296              * @see #setLocale
8297              */
getLocale()8298             public Locale getLocale() {
8299                 AccessibleContext ac = getCurrentAccessibleContext();
8300                 if (ac != null) {
8301                     return ac.getLocale();
8302                 } else {
8303                     return null;
8304                 }
8305             }
8306 
8307             /**
8308              * Adds a <code>PropertyChangeListener</code> to the listener list.
8309              * The listener is registered for all properties.
8310              *
8311              * @param l  the <code>PropertyChangeListener</code>
8312              *     to be added
8313              */
addPropertyChangeListener(PropertyChangeListener l)8314             public void addPropertyChangeListener(PropertyChangeListener l) {
8315                 AccessibleContext ac = getCurrentAccessibleContext();
8316                 if (ac != null) {
8317                     ac.addPropertyChangeListener(l);
8318                 } else {
8319                     super.addPropertyChangeListener(l);
8320                 }
8321             }
8322 
8323             /**
8324              * Removes a <code>PropertyChangeListener</code> from the
8325              * listener list. This removes a <code>PropertyChangeListener</code>
8326              * that was registered for all properties.
8327              *
8328              * @param l  the <code>PropertyChangeListener</code>
8329              *    to be removed
8330              */
removePropertyChangeListener(PropertyChangeListener l)8331             public void removePropertyChangeListener(PropertyChangeListener l) {
8332                 AccessibleContext ac = getCurrentAccessibleContext();
8333                 if (ac != null) {
8334                     ac.removePropertyChangeListener(l);
8335                 } else {
8336                     super.removePropertyChangeListener(l);
8337                 }
8338             }
8339 
8340             /**
8341              * Gets the <code>AccessibleAction</code> associated with this
8342              * object if one exists.  Otherwise returns <code>null</code>.
8343              *
8344              * @return the <code>AccessibleAction</code>, or <code>null</code>
8345              */
getAccessibleAction()8346             public AccessibleAction getAccessibleAction() {
8347                 return getCurrentAccessibleContext().getAccessibleAction();
8348             }
8349 
8350             /**
8351              * Gets the <code>AccessibleComponent</code> associated with
8352              * this object if one exists.  Otherwise returns <code>null</code>.
8353              *
8354              * @return the <code>AccessibleComponent</code>, or
8355              *    <code>null</code>
8356              */
getAccessibleComponent()8357             public AccessibleComponent getAccessibleComponent() {
8358                 return this; // to override getBounds()
8359             }
8360 
8361             /**
8362              * Gets the <code>AccessibleSelection</code> associated with
8363              * this object if one exists.  Otherwise returns <code>null</code>.
8364              *
8365              * @return the <code>AccessibleSelection</code>, or
8366              *    <code>null</code>
8367              */
getAccessibleSelection()8368             public AccessibleSelection getAccessibleSelection() {
8369                 return getCurrentAccessibleContext().getAccessibleSelection();
8370             }
8371 
8372             /**
8373              * Gets the <code>AccessibleText</code> associated with this
8374              * object if one exists.  Otherwise returns <code>null</code>.
8375              *
8376              * @return the <code>AccessibleText</code>, or <code>null</code>
8377              */
getAccessibleText()8378             public AccessibleText getAccessibleText() {
8379                 return getCurrentAccessibleContext().getAccessibleText();
8380             }
8381 
8382             /**
8383              * Gets the <code>AccessibleValue</code> associated with
8384              * this object if one exists.  Otherwise returns <code>null</code>.
8385              *
8386              * @return the <code>AccessibleValue</code>, or <code>null</code>
8387              */
getAccessibleValue()8388             public AccessibleValue getAccessibleValue() {
8389                 return getCurrentAccessibleContext().getAccessibleValue();
8390             }
8391 
8392 
8393         // AccessibleComponent methods
8394 
8395             /**
8396              * Gets the background color of this object.
8397              *
8398              * @return the background color, if supported, of the object;
8399              *     otherwise, <code>null</code>
8400              */
getBackground()8401             public Color getBackground() {
8402                 AccessibleContext ac = getCurrentAccessibleContext();
8403                 if (ac instanceof AccessibleComponent) {
8404                     return ((AccessibleComponent) ac).getBackground();
8405                 } else {
8406                     Component c = getCurrentComponent();
8407                     if (c != null) {
8408                         return c.getBackground();
8409                     } else {
8410                         return null;
8411                     }
8412                 }
8413             }
8414 
8415             /**
8416              * Sets the background color of this object.
8417              *
8418              * @param c the new <code>Color</code> for the background
8419              */
setBackground(Color c)8420             public void setBackground(Color c) {
8421                 AccessibleContext ac = getCurrentAccessibleContext();
8422                 if (ac instanceof AccessibleComponent) {
8423                     ((AccessibleComponent) ac).setBackground(c);
8424                 } else {
8425                     Component cp = getCurrentComponent();
8426                     if (cp != null) {
8427                         cp.setBackground(c);
8428                     }
8429                 }
8430             }
8431 
8432             /**
8433              * Gets the foreground color of this object.
8434              *
8435              * @return the foreground color, if supported, of the object;
8436              *     otherwise, <code>null</code>
8437              */
getForeground()8438             public Color getForeground() {
8439                 AccessibleContext ac = getCurrentAccessibleContext();
8440                 if (ac instanceof AccessibleComponent) {
8441                     return ((AccessibleComponent) ac).getForeground();
8442                 } else {
8443                     Component c = getCurrentComponent();
8444                     if (c != null) {
8445                         return c.getForeground();
8446                     } else {
8447                         return null;
8448                     }
8449                 }
8450             }
8451 
8452             /**
8453              * Sets the foreground color of this object.
8454              *
8455              * @param c the new <code>Color</code> for the foreground
8456              */
setForeground(Color c)8457             public void setForeground(Color c) {
8458                 AccessibleContext ac = getCurrentAccessibleContext();
8459                 if (ac instanceof AccessibleComponent) {
8460                     ((AccessibleComponent) ac).setForeground(c);
8461                 } else {
8462                     Component cp = getCurrentComponent();
8463                     if (cp != null) {
8464                         cp.setForeground(c);
8465                     }
8466                 }
8467             }
8468 
8469             /**
8470              * Gets the <code>Cursor</code> of this object.
8471              *
8472              * @return the <code>Cursor</code>, if supported,
8473              *    of the object; otherwise, <code>null</code>
8474              */
getCursor()8475             public Cursor getCursor() {
8476                 AccessibleContext ac = getCurrentAccessibleContext();
8477                 if (ac instanceof AccessibleComponent) {
8478                     return ((AccessibleComponent) ac).getCursor();
8479                 } else {
8480                     Component c = getCurrentComponent();
8481                     if (c != null) {
8482                         return c.getCursor();
8483                     } else {
8484                         Accessible ap = getAccessibleParent();
8485                         if (ap instanceof AccessibleComponent) {
8486                             return ((AccessibleComponent) ap).getCursor();
8487                         } else {
8488                             return null;
8489                         }
8490                     }
8491                 }
8492             }
8493 
8494             /**
8495              * Sets the <code>Cursor</code> of this object.
8496              *
8497              * @param c the new <code>Cursor</code> for the object
8498              */
setCursor(Cursor c)8499             public void setCursor(Cursor c) {
8500                 AccessibleContext ac = getCurrentAccessibleContext();
8501                 if (ac instanceof AccessibleComponent) {
8502                     ((AccessibleComponent) ac).setCursor(c);
8503                 } else {
8504                     Component cp = getCurrentComponent();
8505                     if (cp != null) {
8506                         cp.setCursor(c);
8507                     }
8508                 }
8509             }
8510 
8511             /**
8512              * Gets the <code>Font</code> of this object.
8513              *
8514              * @return the <code>Font</code>,if supported,
8515              *   for the object; otherwise, <code>null</code>
8516              */
getFont()8517             public Font getFont() {
8518                 AccessibleContext ac = getCurrentAccessibleContext();
8519                 if (ac instanceof AccessibleComponent) {
8520                     return ((AccessibleComponent) ac).getFont();
8521                 } else {
8522                     Component c = getCurrentComponent();
8523                     if (c != null) {
8524                         return c.getFont();
8525                     } else {
8526                         return null;
8527                     }
8528                 }
8529             }
8530 
8531             /**
8532              * Sets the <code>Font</code> of this object.
8533              *
8534              * @param f the new <code>Font</code> for the object
8535              */
setFont(Font f)8536             public void setFont(Font f) {
8537                 AccessibleContext ac = getCurrentAccessibleContext();
8538                 if (ac instanceof AccessibleComponent) {
8539                     ((AccessibleComponent) ac).setFont(f);
8540                 } else {
8541                     Component c = getCurrentComponent();
8542                     if (c != null) {
8543                         c.setFont(f);
8544                     }
8545                 }
8546             }
8547 
8548             /**
8549              * Gets the <code>FontMetrics</code> of this object.
8550              *
8551              * @param f the <code>Font</code>
8552              * @return the <code>FontMetrics</code> object, if supported;
8553              *    otherwise <code>null</code>
8554              * @see #getFont
8555              */
getFontMetrics(Font f)8556             public FontMetrics getFontMetrics(Font f) {
8557                 AccessibleContext ac = getCurrentAccessibleContext();
8558                 if (ac instanceof AccessibleComponent) {
8559                     return ((AccessibleComponent) ac).getFontMetrics(f);
8560                 } else {
8561                     Component c = getCurrentComponent();
8562                     if (c != null) {
8563                         return c.getFontMetrics(f);
8564                     } else {
8565                         return null;
8566                     }
8567                 }
8568             }
8569 
8570             /**
8571              * Determines if the object is enabled.
8572              *
8573              * @return true if object is enabled; otherwise, false
8574              */
isEnabled()8575             public boolean isEnabled() {
8576                 AccessibleContext ac = getCurrentAccessibleContext();
8577                 if (ac instanceof AccessibleComponent) {
8578                     return ((AccessibleComponent) ac).isEnabled();
8579                 } else {
8580                     Component c = getCurrentComponent();
8581                     if (c != null) {
8582                         return c.isEnabled();
8583                     } else {
8584                         return false;
8585                     }
8586                 }
8587             }
8588 
8589             /**
8590              * Sets the enabled state of the object.
8591              *
8592              * @param b if true, enables this object; otherwise, disables it
8593              */
setEnabled(boolean b)8594             public void setEnabled(boolean b) {
8595                 AccessibleContext ac = getCurrentAccessibleContext();
8596                 if (ac instanceof AccessibleComponent) {
8597                     ((AccessibleComponent) ac).setEnabled(b);
8598                 } else {
8599                     Component c = getCurrentComponent();
8600                     if (c != null) {
8601                         c.setEnabled(b);
8602                     }
8603                 }
8604             }
8605 
8606             /**
8607              * Determines if this object is visible.  Note: this means that the
8608              * object intends to be visible; however, it may not in fact be
8609              * showing on the screen because one of the objects that this object
8610              * is contained by is not visible.  To determine if an object is
8611              * showing on the screen, use <code>isShowing</code>.
8612              *
8613              * @return true if object is visible; otherwise, false
8614              */
isVisible()8615             public boolean isVisible() {
8616                 AccessibleContext ac = getCurrentAccessibleContext();
8617                 if (ac instanceof AccessibleComponent) {
8618                     return ((AccessibleComponent) ac).isVisible();
8619                 } else {
8620                     Component c = getCurrentComponent();
8621                     if (c != null) {
8622                         return c.isVisible();
8623                     } else {
8624                         return false;
8625                     }
8626                 }
8627             }
8628 
8629             /**
8630              * Sets the visible state of the object.
8631              *
8632              * @param b if true, shows this object; otherwise, hides it
8633              */
setVisible(boolean b)8634             public void setVisible(boolean b) {
8635                 AccessibleContext ac = getCurrentAccessibleContext();
8636                 if (ac instanceof AccessibleComponent) {
8637                     ((AccessibleComponent) ac).setVisible(b);
8638                 } else {
8639                     Component c = getCurrentComponent();
8640                     if (c != null) {
8641                         c.setVisible(b);
8642                     }
8643                 }
8644             }
8645 
8646             /**
8647              * Determines if the object is showing.  This is determined
8648              * by checking the visibility of the object and ancestors
8649              * of the object.  Note: this will return true even if the
8650              * object is obscured by another (for example,
8651              * it happens to be underneath a menu that was pulled down).
8652              *
8653              * @return true if the object is showing; otherwise, false
8654              */
isShowing()8655             public boolean isShowing() {
8656                 AccessibleContext ac = getCurrentAccessibleContext();
8657                 if (ac instanceof AccessibleComponent) {
8658                     if (ac.getAccessibleParent() != null) {
8659                         return ((AccessibleComponent) ac).isShowing();
8660                     } else {
8661                         // Fixes 4529616 - AccessibleJTableCell.isShowing()
8662                         // returns false when the cell on the screen
8663                         // if no parent
8664                         return isVisible();
8665                     }
8666                 } else {
8667                     Component c = getCurrentComponent();
8668                     if (c != null) {
8669                         return c.isShowing();
8670                     } else {
8671                         return false;
8672                     }
8673                 }
8674             }
8675 
8676             /**
8677              * Checks whether the specified point is within this
8678              * object's bounds, where the point's x and y coordinates
8679              * are defined to be relative to the coordinate system of
8680              * the object.
8681              *
8682              * @param p the <code>Point</code> relative to the
8683              *    coordinate system of the object
8684              * @return true if object contains <code>Point</code>;
8685              *    otherwise false
8686              */
contains(Point p)8687             public boolean contains(Point p) {
8688                 AccessibleContext ac = getCurrentAccessibleContext();
8689                 if (ac instanceof AccessibleComponent) {
8690                     Rectangle r = ((AccessibleComponent) ac).getBounds();
8691                     return r.contains(p);
8692                 } else {
8693                     Component c = getCurrentComponent();
8694                     if (c != null) {
8695                         Rectangle r = c.getBounds();
8696                         return r.contains(p);
8697                     } else {
8698                         return getBounds().contains(p);
8699                     }
8700                 }
8701             }
8702 
8703             /**
8704              * Returns the location of the object on the screen.
8705              *
8706              * @return location of object on screen -- can be
8707              *    <code>null</code> if this object is not on the screen
8708              */
getLocationOnScreen()8709             public Point getLocationOnScreen() {
8710                 if (parent != null && parent.isShowing()) {
8711                     Point parentLocation = parent.getLocationOnScreen();
8712                     Point componentLocation = getLocation();
8713                     componentLocation.translate(parentLocation.x, parentLocation.y);
8714                     return componentLocation;
8715                 } else {
8716                     return null;
8717                 }
8718             }
8719 
8720             /**
8721              * Gets the location of the object relative to the parent
8722              * in the form of a point specifying the object's
8723              * top-left corner in the screen's coordinate space.
8724              *
8725              * @return an instance of <code>Point</code> representing
8726              *    the top-left corner of the object's bounds in the
8727              *    coordinate space of the screen; <code>null</code> if
8728              *    this object or its parent are not on the screen
8729              */
getLocation()8730             public Point getLocation() {
8731                 if (parent != null) {
8732                     Rectangle r = parent.getCellRect(row, column, false);
8733                     if (r != null) {
8734                         return r.getLocation();
8735                     }
8736                 }
8737                 return null;
8738             }
8739 
8740             /**
8741              * Sets the location of the object relative to the parent.
8742              */
setLocation(Point p)8743             public void setLocation(Point p) {
8744 //              if ((parent != null)  && (parent.contains(p))) {
8745 //                  ensureIndexIsVisible(indexInParent);
8746 //              }
8747             }
8748 
getBounds()8749             public Rectangle getBounds() {
8750                 if (parent != null) {
8751                     return parent.getCellRect(row, column, false);
8752                 } else {
8753                     return null;
8754                 }
8755             }
8756 
setBounds(Rectangle r)8757             public void setBounds(Rectangle r) {
8758                 AccessibleContext ac = getCurrentAccessibleContext();
8759                 if (ac instanceof AccessibleComponent) {
8760                     ((AccessibleComponent) ac).setBounds(r);
8761                 } else {
8762                     Component c = getCurrentComponent();
8763                     if (c != null) {
8764                         c.setBounds(r);
8765                     }
8766                 }
8767             }
8768 
getSize()8769             public Dimension getSize() {
8770                 if (parent != null) {
8771                     Rectangle r = parent.getCellRect(row, column, false);
8772                     if (r != null) {
8773                         return r.getSize();
8774                     }
8775                 }
8776                 return null;
8777             }
8778 
setSize(Dimension d)8779             public void setSize (Dimension d) {
8780                 AccessibleContext ac = getCurrentAccessibleContext();
8781                 if (ac instanceof AccessibleComponent) {
8782                     ((AccessibleComponent) ac).setSize(d);
8783                 } else {
8784                     Component c = getCurrentComponent();
8785                     if (c != null) {
8786                         c.setSize(d);
8787                     }
8788                 }
8789             }
8790 
getAccessibleAt(Point p)8791             public Accessible getAccessibleAt(Point p) {
8792                 AccessibleContext ac = getCurrentAccessibleContext();
8793                 if (ac instanceof AccessibleComponent) {
8794                     return ((AccessibleComponent) ac).getAccessibleAt(p);
8795                 } else {
8796                     return null;
8797                 }
8798             }
8799 
8800             @SuppressWarnings("deprecation")
isFocusTraversable()8801             public boolean isFocusTraversable() {
8802                 AccessibleContext ac = getCurrentAccessibleContext();
8803                 if (ac instanceof AccessibleComponent) {
8804                     return ((AccessibleComponent) ac).isFocusTraversable();
8805                 } else {
8806                     Component c = getCurrentComponent();
8807                     if (c != null) {
8808                         return c.isFocusTraversable();
8809                     } else {
8810                         return false;
8811                     }
8812                 }
8813             }
8814 
requestFocus()8815             public void requestFocus() {
8816                 AccessibleContext ac = getCurrentAccessibleContext();
8817                 if (ac instanceof AccessibleComponent) {
8818                     ((AccessibleComponent) ac).requestFocus();
8819                 } else {
8820                     Component c = getCurrentComponent();
8821                     if (c != null) {
8822                         c.requestFocus();
8823                     }
8824                 }
8825             }
8826 
addFocusListener(FocusListener l)8827             public void addFocusListener(FocusListener l) {
8828                 AccessibleContext ac = getCurrentAccessibleContext();
8829                 if (ac instanceof AccessibleComponent) {
8830                     ((AccessibleComponent) ac).addFocusListener(l);
8831                 } else {
8832                     Component c = getCurrentComponent();
8833                     if (c != null) {
8834                         c.addFocusListener(l);
8835                     }
8836                 }
8837             }
8838 
removeFocusListener(FocusListener l)8839             public void removeFocusListener(FocusListener l) {
8840                 AccessibleContext ac = getCurrentAccessibleContext();
8841                 if (ac instanceof AccessibleComponent) {
8842                     ((AccessibleComponent) ac).removeFocusListener(l);
8843                 } else {
8844                     Component c = getCurrentComponent();
8845                     if (c != null) {
8846                         c.removeFocusListener(l);
8847                     }
8848                 }
8849             }
8850 
8851         } // inner class AccessibleJTableCell
8852 
8853         // Begin AccessibleJTableHeader ========== // TIGER - 4715503
8854 
8855         /**
8856          * This class implements accessibility for JTable header cells.
8857          */
8858         private class AccessibleJTableHeaderCell extends AccessibleContext
8859             implements Accessible, AccessibleComponent {
8860 
8861             private int row;
8862             private int column;
8863             private JTableHeader parent;
8864             private Component rendererComponent;
8865 
8866             /**
8867              * Constructs an <code>AccessibleJTableHeaderEntry</code> instance.
8868              *
8869              * @param row header cell row index
8870              * @param column header cell column index
8871              * @param parent header cell parent
8872              * @param rendererComponent component that renders the header cell
8873              */
AccessibleJTableHeaderCell(int row, int column, JTableHeader parent, Component rendererComponent)8874             public AccessibleJTableHeaderCell(int row, int column,
8875                                               JTableHeader parent,
8876                                               Component rendererComponent) {
8877                 this.row = row;
8878                 this.column = column;
8879                 this.parent = parent;
8880                 this.rendererComponent = rendererComponent;
8881                 this.setAccessibleParent(parent);
8882             }
8883 
8884             /**
8885              * Gets the <code>AccessibleContext</code> associated with this
8886              * component. In the implementation of the Java Accessibility
8887              * API for this class, return this object, which is its own
8888              * <code>AccessibleContext</code>.
8889              *
8890              * @return this object
8891              */
getAccessibleContext()8892             public AccessibleContext getAccessibleContext() {
8893                 return this;
8894             }
8895 
8896             /*
8897              * Returns the AccessibleContext for the header cell
8898              * renderer.
8899              */
getCurrentAccessibleContext()8900             private AccessibleContext getCurrentAccessibleContext() {
8901                 return rendererComponent.getAccessibleContext();
8902             }
8903 
8904             /*
8905              * Returns the component that renders the header cell.
8906              */
getCurrentComponent()8907             private Component getCurrentComponent() {
8908                 return rendererComponent;
8909             }
8910 
8911             // AccessibleContext methods ==========
8912 
8913             /**
8914              * Gets the accessible name of this object.
8915              *
8916              * @return the localized name of the object; <code>null</code>
8917              *     if this object does not have a name
8918              */
getAccessibleName()8919             public String getAccessibleName() {
8920                 AccessibleContext ac = getCurrentAccessibleContext();
8921                 if (ac != null) {
8922                     String name = ac.getAccessibleName();
8923                     if ((name != null) && (name != "")) {
8924                         return ac.getAccessibleName();
8925                     }
8926                 }
8927                 if ((accessibleName != null) && (accessibleName != "")) {
8928                     return accessibleName;
8929                 } else {
8930                     return null;
8931                 }
8932             }
8933 
8934             /**
8935              * Sets the localized accessible name of this object.
8936              *
8937              * @param s the new localized name of the object
8938              */
setAccessibleName(String s)8939             public void setAccessibleName(String s) {
8940                 AccessibleContext ac = getCurrentAccessibleContext();
8941                 if (ac != null) {
8942                     ac.setAccessibleName(s);
8943                 } else {
8944                     super.setAccessibleName(s);
8945                 }
8946             }
8947 
8948             /**
8949              * Gets the accessible description of this object.
8950              *
8951              * @return the localized description of the object;
8952              *     <code>null</code> if this object does not have
8953              *     a description
8954              */
getAccessibleDescription()8955             public String getAccessibleDescription() {
8956                 AccessibleContext ac = getCurrentAccessibleContext();
8957                 if (ac != null) {
8958                     return ac.getAccessibleDescription();
8959                 } else {
8960                     return super.getAccessibleDescription();
8961                 }
8962             }
8963 
8964             /**
8965              * Sets the accessible description of this object.
8966              *
8967              * @param s the new localized description of the object
8968              */
setAccessibleDescription(String s)8969             public void setAccessibleDescription(String s) {
8970                 AccessibleContext ac = getCurrentAccessibleContext();
8971                 if (ac != null) {
8972                     ac.setAccessibleDescription(s);
8973                 } else {
8974                     super.setAccessibleDescription(s);
8975                 }
8976             }
8977 
8978             /**
8979              * Gets the role of this object.
8980              *
8981              * @return an instance of <code>AccessibleRole</code>
8982              *      describing the role of the object
8983              * @see AccessibleRole
8984              */
getAccessibleRole()8985             public AccessibleRole getAccessibleRole() {
8986                 AccessibleContext ac = getCurrentAccessibleContext();
8987                 if (ac != null) {
8988                     return ac.getAccessibleRole();
8989                 } else {
8990                     return AccessibleRole.UNKNOWN;
8991                 }
8992             }
8993 
8994             /**
8995              * Gets the state set of this object.
8996              *
8997              * @return an instance of <code>AccessibleStateSet</code>
8998              *     containing the current state set of the object
8999              * @see AccessibleState
9000              */
getAccessibleStateSet()9001             public AccessibleStateSet getAccessibleStateSet() {
9002                 AccessibleContext ac = getCurrentAccessibleContext();
9003                 AccessibleStateSet as = null;
9004 
9005                 if (ac != null) {
9006                     as = ac.getAccessibleStateSet();
9007                 }
9008                 if (as == null) {
9009                     as = new AccessibleStateSet();
9010                 }
9011                 Rectangle rjt = JTable.this.getVisibleRect();
9012                 Rectangle rcell = JTable.this.getCellRect(row, column, false);
9013                 if (rjt.intersects(rcell)) {
9014                     as.add(AccessibleState.SHOWING);
9015                 } else {
9016                     if (as.contains(AccessibleState.SHOWING)) {
9017                          as.remove(AccessibleState.SHOWING);
9018                     }
9019                 }
9020                 if (JTable.this.isCellSelected(row, column)) {
9021                     as.add(AccessibleState.SELECTED);
9022                 } else if (as.contains(AccessibleState.SELECTED)) {
9023                     as.remove(AccessibleState.SELECTED);
9024                 }
9025                 if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
9026                     as.add(AccessibleState.ACTIVE);
9027                 }
9028                 as.add(AccessibleState.TRANSIENT);
9029                 return as;
9030             }
9031 
9032             /**
9033              * Gets the <code>Accessible</code> parent of this object.
9034              *
9035              * @return the Accessible parent of this object;
9036              *     <code>null</code> if this object does not
9037              *     have an <code>Accessible</code> parent
9038              */
getAccessibleParent()9039             public Accessible getAccessibleParent() {
9040                 return parent;
9041             }
9042 
9043             /**
9044              * Gets the index of this object in its accessible parent.
9045              *
9046              * @return the index of this object in its parent; -1 if this
9047              *     object does not have an accessible parent
9048              * @see #getAccessibleParent
9049              */
getAccessibleIndexInParent()9050             public int getAccessibleIndexInParent() {
9051                 return column;
9052             }
9053 
9054             /**
9055              * Returns the number of accessible children in the object.
9056              *
9057              * @return the number of accessible children in the object
9058              */
getAccessibleChildrenCount()9059             public int getAccessibleChildrenCount() {
9060                 AccessibleContext ac = getCurrentAccessibleContext();
9061                 if (ac != null) {
9062                     return ac.getAccessibleChildrenCount();
9063                 } else {
9064                     return 0;
9065                 }
9066             }
9067 
9068             /**
9069              * Returns the specified <code>Accessible</code> child of the
9070              * object.
9071              *
9072              * @param i zero-based index of child
9073              * @return the <code>Accessible</code> child of the object
9074              */
getAccessibleChild(int i)9075             public Accessible getAccessibleChild(int i) {
9076                 AccessibleContext ac = getCurrentAccessibleContext();
9077                 if (ac != null) {
9078                     Accessible accessibleChild = ac.getAccessibleChild(i);
9079                     ac.setAccessibleParent(this);
9080                     return accessibleChild;
9081                 } else {
9082                     return null;
9083                 }
9084             }
9085 
9086             /**
9087              * Gets the locale of the component. If the component
9088              * does not have a locale, then the locale of its parent
9089              * is returned.
9090              *
9091              * @return this component's locale; if this component does
9092              *    not have a locale, the locale of its parent is returned
9093              * @exception IllegalComponentStateException if the
9094              *    <code>Component</code> does not have its own locale
9095              *    and has not yet been added to a containment hierarchy
9096              *    such that the locale can be determined from the
9097              *    containing parent
9098              * @see #setLocale
9099              */
getLocale()9100             public Locale getLocale() {
9101                 AccessibleContext ac = getCurrentAccessibleContext();
9102                 if (ac != null) {
9103                     return ac.getLocale();
9104                 } else {
9105                     return null;
9106                 }
9107             }
9108 
9109             /**
9110              * Adds a <code>PropertyChangeListener</code> to the listener list.
9111              * The listener is registered for all properties.
9112              *
9113              * @param l  the <code>PropertyChangeListener</code>
9114              *     to be added
9115              */
addPropertyChangeListener(PropertyChangeListener l)9116             public void addPropertyChangeListener(PropertyChangeListener l) {
9117                 AccessibleContext ac = getCurrentAccessibleContext();
9118                 if (ac != null) {
9119                     ac.addPropertyChangeListener(l);
9120                 } else {
9121                     super.addPropertyChangeListener(l);
9122                 }
9123             }
9124 
9125             /**
9126              * Removes a <code>PropertyChangeListener</code> from the
9127              * listener list. This removes a <code>PropertyChangeListener</code>
9128              * that was registered for all properties.
9129              *
9130              * @param l  the <code>PropertyChangeListener</code>
9131              *    to be removed
9132              */
removePropertyChangeListener(PropertyChangeListener l)9133             public void removePropertyChangeListener(PropertyChangeListener l) {
9134                 AccessibleContext ac = getCurrentAccessibleContext();
9135                 if (ac != null) {
9136                     ac.removePropertyChangeListener(l);
9137                 } else {
9138                     super.removePropertyChangeListener(l);
9139                 }
9140             }
9141 
9142             /**
9143              * Gets the <code>AccessibleAction</code> associated with this
9144              * object if one exists.  Otherwise returns <code>null</code>.
9145              *
9146              * @return the <code>AccessibleAction</code>, or <code>null</code>
9147              */
getAccessibleAction()9148             public AccessibleAction getAccessibleAction() {
9149                 return getCurrentAccessibleContext().getAccessibleAction();
9150             }
9151 
9152             /**
9153              * Gets the <code>AccessibleComponent</code> associated with
9154              * this object if one exists.  Otherwise returns <code>null</code>.
9155              *
9156              * @return the <code>AccessibleComponent</code>, or
9157              *    <code>null</code>
9158              */
getAccessibleComponent()9159             public AccessibleComponent getAccessibleComponent() {
9160                 return this; // to override getBounds()
9161             }
9162 
9163             /**
9164              * Gets the <code>AccessibleSelection</code> associated with
9165              * this object if one exists.  Otherwise returns <code>null</code>.
9166              *
9167              * @return the <code>AccessibleSelection</code>, or
9168              *    <code>null</code>
9169              */
getAccessibleSelection()9170             public AccessibleSelection getAccessibleSelection() {
9171                 return getCurrentAccessibleContext().getAccessibleSelection();
9172             }
9173 
9174             /**
9175              * Gets the <code>AccessibleText</code> associated with this
9176              * object if one exists.  Otherwise returns <code>null</code>.
9177              *
9178              * @return the <code>AccessibleText</code>, or <code>null</code>
9179              */
getAccessibleText()9180             public AccessibleText getAccessibleText() {
9181                 return getCurrentAccessibleContext().getAccessibleText();
9182             }
9183 
9184             /**
9185              * Gets the <code>AccessibleValue</code> associated with
9186              * this object if one exists.  Otherwise returns <code>null</code>.
9187              *
9188              * @return the <code>AccessibleValue</code>, or <code>null</code>
9189              */
getAccessibleValue()9190             public AccessibleValue getAccessibleValue() {
9191                 return getCurrentAccessibleContext().getAccessibleValue();
9192             }
9193 
9194 
9195             // AccessibleComponent methods ==========
9196 
9197             /**
9198              * Gets the background color of this object.
9199              *
9200              * @return the background color, if supported, of the object;
9201              *     otherwise, <code>null</code>
9202              */
getBackground()9203             public Color getBackground() {
9204                 AccessibleContext ac = getCurrentAccessibleContext();
9205                 if (ac instanceof AccessibleComponent) {
9206                     return ((AccessibleComponent) ac).getBackground();
9207                 } else {
9208                     Component c = getCurrentComponent();
9209                     if (c != null) {
9210                         return c.getBackground();
9211                     } else {
9212                         return null;
9213                     }
9214                 }
9215             }
9216 
9217             /**
9218              * Sets the background color of this object.
9219              *
9220              * @param c the new <code>Color</code> for the background
9221              */
setBackground(Color c)9222             public void setBackground(Color c) {
9223                 AccessibleContext ac = getCurrentAccessibleContext();
9224                 if (ac instanceof AccessibleComponent) {
9225                     ((AccessibleComponent) ac).setBackground(c);
9226                 } else {
9227                     Component cp = getCurrentComponent();
9228                     if (cp != null) {
9229                         cp.setBackground(c);
9230                     }
9231                 }
9232             }
9233 
9234             /**
9235              * Gets the foreground color of this object.
9236              *
9237              * @return the foreground color, if supported, of the object;
9238              *     otherwise, <code>null</code>
9239              */
getForeground()9240             public Color getForeground() {
9241                 AccessibleContext ac = getCurrentAccessibleContext();
9242                 if (ac instanceof AccessibleComponent) {
9243                     return ((AccessibleComponent) ac).getForeground();
9244                 } else {
9245                     Component c = getCurrentComponent();
9246                     if (c != null) {
9247                         return c.getForeground();
9248                     } else {
9249                         return null;
9250                     }
9251                 }
9252             }
9253 
9254             /**
9255              * Sets the foreground color of this object.
9256              *
9257              * @param c the new <code>Color</code> for the foreground
9258              */
setForeground(Color c)9259             public void setForeground(Color c) {
9260                 AccessibleContext ac = getCurrentAccessibleContext();
9261                 if (ac instanceof AccessibleComponent) {
9262                     ((AccessibleComponent) ac).setForeground(c);
9263                 } else {
9264                     Component cp = getCurrentComponent();
9265                     if (cp != null) {
9266                         cp.setForeground(c);
9267                     }
9268                 }
9269             }
9270 
9271             /**
9272              * Gets the <code>Cursor</code> of this object.
9273              *
9274              * @return the <code>Cursor</code>, if supported,
9275              *    of the object; otherwise, <code>null</code>
9276              */
getCursor()9277             public Cursor getCursor() {
9278                 AccessibleContext ac = getCurrentAccessibleContext();
9279                 if (ac instanceof AccessibleComponent) {
9280                     return ((AccessibleComponent) ac).getCursor();
9281                 } else {
9282                     Component c = getCurrentComponent();
9283                     if (c != null) {
9284                         return c.getCursor();
9285                     } else {
9286                         Accessible ap = getAccessibleParent();
9287                         if (ap instanceof AccessibleComponent) {
9288                             return ((AccessibleComponent) ap).getCursor();
9289                         } else {
9290                             return null;
9291                         }
9292                     }
9293                 }
9294             }
9295 
9296             /**
9297              * Sets the <code>Cursor</code> of this object.
9298              *
9299              * @param c the new <code>Cursor</code> for the object
9300              */
setCursor(Cursor c)9301             public void setCursor(Cursor c) {
9302                 AccessibleContext ac = getCurrentAccessibleContext();
9303                 if (ac instanceof AccessibleComponent) {
9304                     ((AccessibleComponent) ac).setCursor(c);
9305                 } else {
9306                     Component cp = getCurrentComponent();
9307                     if (cp != null) {
9308                         cp.setCursor(c);
9309                     }
9310                 }
9311             }
9312 
9313             /**
9314              * Gets the <code>Font</code> of this object.
9315              *
9316              * @return the <code>Font</code>,if supported,
9317              *   for the object; otherwise, <code>null</code>
9318              */
getFont()9319             public Font getFont() {
9320                 AccessibleContext ac = getCurrentAccessibleContext();
9321                 if (ac instanceof AccessibleComponent) {
9322                     return ((AccessibleComponent) ac).getFont();
9323                 } else {
9324                     Component c = getCurrentComponent();
9325                     if (c != null) {
9326                         return c.getFont();
9327                     } else {
9328                         return null;
9329                     }
9330                 }
9331             }
9332 
9333             /**
9334              * Sets the <code>Font</code> of this object.
9335              *
9336              * @param f the new <code>Font</code> for the object
9337              */
setFont(Font f)9338             public void setFont(Font f) {
9339                 AccessibleContext ac = getCurrentAccessibleContext();
9340                 if (ac instanceof AccessibleComponent) {
9341                     ((AccessibleComponent) ac).setFont(f);
9342                 } else {
9343                     Component c = getCurrentComponent();
9344                     if (c != null) {
9345                         c.setFont(f);
9346                     }
9347                 }
9348             }
9349 
9350             /**
9351              * Gets the <code>FontMetrics</code> of this object.
9352              *
9353              * @param f the <code>Font</code>
9354              * @return the <code>FontMetrics</code> object, if supported;
9355              *    otherwise <code>null</code>
9356              * @see #getFont
9357              */
getFontMetrics(Font f)9358             public FontMetrics getFontMetrics(Font f) {
9359                 AccessibleContext ac = getCurrentAccessibleContext();
9360                 if (ac instanceof AccessibleComponent) {
9361                     return ((AccessibleComponent) ac).getFontMetrics(f);
9362                 } else {
9363                     Component c = getCurrentComponent();
9364                     if (c != null) {
9365                         return c.getFontMetrics(f);
9366                     } else {
9367                         return null;
9368                     }
9369                 }
9370             }
9371 
9372             /**
9373              * Determines if the object is enabled.
9374              *
9375              * @return true if object is enabled; otherwise, false
9376              */
isEnabled()9377             public boolean isEnabled() {
9378                 AccessibleContext ac = getCurrentAccessibleContext();
9379                 if (ac instanceof AccessibleComponent) {
9380                     return ((AccessibleComponent) ac).isEnabled();
9381                 } else {
9382                     Component c = getCurrentComponent();
9383                     if (c != null) {
9384                         return c.isEnabled();
9385                     } else {
9386                         return false;
9387                     }
9388                 }
9389             }
9390 
9391             /**
9392              * Sets the enabled state of the object.
9393              *
9394              * @param b if true, enables this object; otherwise, disables it
9395              */
setEnabled(boolean b)9396             public void setEnabled(boolean b) {
9397                 AccessibleContext ac = getCurrentAccessibleContext();
9398                 if (ac instanceof AccessibleComponent) {
9399                     ((AccessibleComponent) ac).setEnabled(b);
9400                 } else {
9401                     Component c = getCurrentComponent();
9402                     if (c != null) {
9403                         c.setEnabled(b);
9404                     }
9405                 }
9406             }
9407 
9408             /**
9409              * Determines if this object is visible.  Note: this means that the
9410              * object intends to be visible; however, it may not in fact be
9411              * showing on the screen because one of the objects that this object
9412              * is contained by is not visible.  To determine if an object is
9413              * showing on the screen, use <code>isShowing</code>.
9414              *
9415              * @return true if object is visible; otherwise, false
9416              */
isVisible()9417             public boolean isVisible() {
9418                 AccessibleContext ac = getCurrentAccessibleContext();
9419                 if (ac instanceof AccessibleComponent) {
9420                     return ((AccessibleComponent) ac).isVisible();
9421                 } else {
9422                     Component c = getCurrentComponent();
9423                     if (c != null) {
9424                         return c.isVisible();
9425                     } else {
9426                         return false;
9427                     }
9428                 }
9429             }
9430 
9431             /**
9432              * Sets the visible state of the object.
9433              *
9434              * @param b if true, shows this object; otherwise, hides it
9435              */
setVisible(boolean b)9436             public void setVisible(boolean b) {
9437                 AccessibleContext ac = getCurrentAccessibleContext();
9438                 if (ac instanceof AccessibleComponent) {
9439                     ((AccessibleComponent) ac).setVisible(b);
9440                 } else {
9441                     Component c = getCurrentComponent();
9442                     if (c != null) {
9443                         c.setVisible(b);
9444                     }
9445                 }
9446             }
9447 
9448             /**
9449              * Determines if the object is showing.  This is determined
9450              * by checking the visibility of the object and ancestors
9451              * of the object.  Note: this will return true even if the
9452              * object is obscured by another (for example,
9453              * it happens to be underneath a menu that was pulled down).
9454              *
9455              * @return true if the object is showing; otherwise, false
9456              */
isShowing()9457             public boolean isShowing() {
9458                 AccessibleContext ac = getCurrentAccessibleContext();
9459                 if (ac instanceof AccessibleComponent) {
9460                     if (ac.getAccessibleParent() != null) {
9461                         return ((AccessibleComponent) ac).isShowing();
9462                     } else {
9463                         // Fixes 4529616 - AccessibleJTableCell.isShowing()
9464                         // returns false when the cell on the screen
9465                         // if no parent
9466                         return isVisible();
9467                     }
9468                 } else {
9469                     Component c = getCurrentComponent();
9470                     if (c != null) {
9471                         return c.isShowing();
9472                     } else {
9473                         return false;
9474                     }
9475                 }
9476             }
9477 
9478             /**
9479              * Checks whether the specified point is within this
9480              * object's bounds, where the point's x and y coordinates
9481              * are defined to be relative to the coordinate system of
9482              * the object.
9483              *
9484              * @param p the <code>Point</code> relative to the
9485              *    coordinate system of the object
9486              * @return true if object contains <code>Point</code>;
9487              *    otherwise false
9488              */
contains(Point p)9489             public boolean contains(Point p) {
9490                 AccessibleContext ac = getCurrentAccessibleContext();
9491                 if (ac instanceof AccessibleComponent) {
9492                     Rectangle r = ((AccessibleComponent) ac).getBounds();
9493                     return r.contains(p);
9494                 } else {
9495                     Component c = getCurrentComponent();
9496                     if (c != null) {
9497                         Rectangle r = c.getBounds();
9498                         return r.contains(p);
9499                     } else {
9500                         return getBounds().contains(p);
9501                     }
9502                 }
9503             }
9504 
9505             /**
9506              * Returns the location of the object on the screen.
9507              *
9508              * @return location of object on screen -- can be
9509              *    <code>null</code> if this object is not on the screen
9510              */
getLocationOnScreen()9511             public Point getLocationOnScreen() {
9512                 if (parent != null && parent.isShowing()) {
9513                     Point parentLocation = parent.getLocationOnScreen();
9514                     Point componentLocation = getLocation();
9515                     componentLocation.translate(parentLocation.x, parentLocation.y);
9516                     return componentLocation;
9517                 } else {
9518                     return null;
9519                 }
9520             }
9521 
9522             /**
9523              * Gets the location of the object relative to the parent
9524              * in the form of a point specifying the object's
9525              * top-left corner in the screen's coordinate space.
9526              *
9527              * @return an instance of <code>Point</code> representing
9528              *    the top-left corner of the object's bounds in the
9529              *    coordinate space of the screen; <code>null</code> if
9530              *    this object or its parent are not on the screen
9531              */
getLocation()9532             public Point getLocation() {
9533                 if (parent != null) {
9534                     Rectangle r = parent.getHeaderRect(column);
9535                     if (r != null) {
9536                         return r.getLocation();
9537                     }
9538                 }
9539                 return null;
9540             }
9541 
9542             /**
9543              * Sets the location of the object relative to the parent.
9544              * @param p the new position for the top-left corner
9545              * @see #getLocation
9546              */
setLocation(Point p)9547             public void setLocation(Point p) {
9548             }
9549 
9550             /**
9551              * Gets the bounds of this object in the form of a Rectangle object.
9552              * The bounds specify this object's width, height, and location
9553              * relative to its parent.
9554              *
9555              * @return A rectangle indicating this component's bounds; null if
9556              * this object is not on the screen.
9557              * @see #contains
9558              */
getBounds()9559             public Rectangle getBounds() {
9560                 if (parent != null) {
9561                     return parent.getHeaderRect(column);
9562                 } else {
9563                     return null;
9564                 }
9565             }
9566 
9567             /**
9568              * Sets the bounds of this object in the form of a Rectangle object.
9569              * The bounds specify this object's width, height, and location
9570              * relative to its parent.
9571              *
9572              * @param r rectangle indicating this component's bounds
9573              * @see #getBounds
9574              */
setBounds(Rectangle r)9575             public void setBounds(Rectangle r) {
9576                 AccessibleContext ac = getCurrentAccessibleContext();
9577                 if (ac instanceof AccessibleComponent) {
9578                     ((AccessibleComponent) ac).setBounds(r);
9579                 } else {
9580                     Component c = getCurrentComponent();
9581                     if (c != null) {
9582                         c.setBounds(r);
9583                     }
9584                 }
9585             }
9586 
9587             /**
9588              * Returns the size of this object in the form of a Dimension object.
9589              * The height field of the Dimension object contains this object's
9590              * height, and the width field of the Dimension object contains this
9591              * object's width.
9592              *
9593              * @return A Dimension object that indicates the size of this component;
9594              * null if this object is not on the screen
9595              * @see #setSize
9596              */
getSize()9597             public Dimension getSize() {
9598                 if (parent != null) {
9599                     Rectangle r = parent.getHeaderRect(column);
9600                     if (r != null) {
9601                         return r.getSize();
9602                     }
9603                 }
9604                 return null;
9605             }
9606 
9607             /**
9608              * Resizes this object so that it has width and height.
9609              *
9610              * @param d The dimension specifying the new size of the object.
9611              * @see #getSize
9612              */
setSize(Dimension d)9613             public void setSize (Dimension d) {
9614                 AccessibleContext ac = getCurrentAccessibleContext();
9615                 if (ac instanceof AccessibleComponent) {
9616                     ((AccessibleComponent) ac).setSize(d);
9617                 } else {
9618                     Component c = getCurrentComponent();
9619                     if (c != null) {
9620                         c.setSize(d);
9621                     }
9622                 }
9623             }
9624 
9625             /**
9626              * Returns the Accessible child, if one exists, contained at the local
9627              * coordinate Point.
9628              *
9629              * @param p The point relative to the coordinate system of this object.
9630              * @return the Accessible, if it exists, at the specified location;
9631              * otherwise null
9632              */
getAccessibleAt(Point p)9633             public Accessible getAccessibleAt(Point p) {
9634                 AccessibleContext ac = getCurrentAccessibleContext();
9635                 if (ac instanceof AccessibleComponent) {
9636                     return ((AccessibleComponent) ac).getAccessibleAt(p);
9637                 } else {
9638                     return null;
9639                 }
9640             }
9641 
9642             /**
9643              * Returns whether this object can accept focus or not.   Objects that
9644              * can accept focus will also have the AccessibleState.FOCUSABLE state
9645              * set in their AccessibleStateSets.
9646              *
9647              * @return true if object can accept focus; otherwise false
9648              * @see AccessibleContext#getAccessibleStateSet
9649              * @see AccessibleState#FOCUSABLE
9650              * @see AccessibleState#FOCUSED
9651              * @see AccessibleStateSet
9652              */
9653             @SuppressWarnings("deprecation")
isFocusTraversable()9654             public boolean isFocusTraversable() {
9655                 AccessibleContext ac = getCurrentAccessibleContext();
9656                 if (ac instanceof AccessibleComponent) {
9657                     return ((AccessibleComponent) ac).isFocusTraversable();
9658                 } else {
9659                     Component c = getCurrentComponent();
9660                     if (c != null) {
9661                         return c.isFocusTraversable();
9662                     } else {
9663                         return false;
9664                     }
9665                 }
9666             }
9667 
9668             /**
9669              * Requests focus for this object.  If this object cannot accept focus,
9670              * nothing will happen.  Otherwise, the object will attempt to take
9671              * focus.
9672              * @see #isFocusTraversable
9673              */
requestFocus()9674             public void requestFocus() {
9675                 AccessibleContext ac = getCurrentAccessibleContext();
9676                 if (ac instanceof AccessibleComponent) {
9677                     ((AccessibleComponent) ac).requestFocus();
9678                 } else {
9679                     Component c = getCurrentComponent();
9680                     if (c != null) {
9681                         c.requestFocus();
9682                     }
9683                 }
9684             }
9685 
9686             /**
9687              * Adds the specified focus listener to receive focus events from this
9688              * component.
9689              *
9690              * @param l the focus listener
9691              * @see #removeFocusListener
9692              */
addFocusListener(FocusListener l)9693             public void addFocusListener(FocusListener l) {
9694                 AccessibleContext ac = getCurrentAccessibleContext();
9695                 if (ac instanceof AccessibleComponent) {
9696                     ((AccessibleComponent) ac).addFocusListener(l);
9697                 } else {
9698                     Component c = getCurrentComponent();
9699                     if (c != null) {
9700                         c.addFocusListener(l);
9701                     }
9702                 }
9703             }
9704 
9705             /**
9706              * Removes the specified focus listener so it no longer receives focus
9707              * events from this component.
9708              *
9709              * @param l the focus listener
9710              * @see #addFocusListener
9711              */
removeFocusListener(FocusListener l)9712             public void removeFocusListener(FocusListener l) {
9713                 AccessibleContext ac = getCurrentAccessibleContext();
9714                 if (ac instanceof AccessibleComponent) {
9715                     ((AccessibleComponent) ac).removeFocusListener(l);
9716                 } else {
9717                     Component c = getCurrentComponent();
9718                     if (c != null) {
9719                         c.removeFocusListener(l);
9720                     }
9721                 }
9722             }
9723 
9724         } // inner class AccessibleJTableHeaderCell
9725 
9726     }  // inner class AccessibleJTable
9727 
9728 }  // End of Class JTable
9729