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