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