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