       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         return selectionModel.getSelectedIndices();
    2272     }
    2273
    2274     /**
    2275      * Returns the indices of all selected columns.
    2276      *
    2277      * @return an array of integers containing the indices of all selected columns,
    2278      *         or an empty array if no column is selected
    2279      * @see #getSelectedColumn
    2280      */
    2281     @BeanProperty(bound = false)
    2282     public int[] getSelectedColumns() {
    2283         return columnModel.getSelectedColumns();
    2284     }
    2285
    2286     /**
    2287      * Returns the number of selected rows.
    2288      *
    2289      * @return the number of selected rows, 0 if no rows are selected
    2290      */
    2291     @BeanProperty(bound = false)
    2292     public int getSelectedRowCount() {
    2293         return selectionModel.getSelectedItemsCount();
    2294     }
    2295
    2296     /**
    2297      * Returns the number of selected columns.
    2298      *
    2299      * @return the number of selected columns, 0 if no columns are selected
    2300      */
    2301     @BeanProperty(bound = false)
    2302     public int getSelectedColumnCount() {
    2303         return columnModel.getSelectedColumnCount();
    2304     }
    2305
    2306     /**
    2307      * Returns true if the specified index is in the valid range of rows,
    2308      * and the row at that index is selected.
    2309      *
    2310      * @param row a row in the row model
    2311      * @return true if <code>row</code> is a valid index and the row at
    2312      *              that index is selected (where 0 is the first row)
    2313      */
    2314     public boolean isRowSelected(int row) {
    2315         return selectionModel.isSelectedIndex(row);
    2316     }
    2317
    2318     /**
    2319      * Returns true if the specified index is in the valid range of columns,
    2320      * and the column at that index is selected.
    2321      *
    2322      * @param   column   the column in the column model
    2323      * @return true if <code>column</code> is a valid index and the column at
    2324      *              that index is selected (where 0 is the first column)
    2325      */
    2326     public boolean isColumnSelected(int column) {
    2327         return columnModel.getSelectionModel().isSelectedIndex(column);
    2328     }
    2329
    2330     /**
    2331      * Returns true if the specified indices are in the valid range of rows
    2332      * and columns and the cell at the specified position is selected.
    2333      * @param row   the row being queried
    2334      * @param column  the column being queried
    2335      *
    2336      * @return true if <code>row</code> and <code>column</code> are valid indices
    2337      *              and the cell at index <code>(row, column)</code> is selected,
    2338      *              where the first row and first column are at index 0
    2339      */
    2340     public boolean isCellSelected(int row, int column) {
    2341         if (!getRowSelectionAllowed() && !getColumnSelectionAllowed()) {
    2342             return false;
    2343         }
    2344         return (!getRowSelectionAllowed() || isRowSelected(row)) &&
    2345                (!getColumnSelectionAllowed() || isColumnSelected(column));
    2346     }
    2347
    2348     private void changeSelectionModel(ListSelectionModel sm, int index,
    2349                                       boolean toggle, boolean extend, boolean selected,
    2350                                       int anchor, boolean anchorSelected) {
    2351         if (extend) {
    2352             if (toggle) {
    2353                 if (anchorSelected) {
    2354                     sm.addSelectionInterval(anchor, index);
    2355                 } else {
    2356                     sm.removeSelectionInterval(anchor, index);
    2357                     // this is a Windows-only behavior that we want for file lists
    2358                     if (Boolean.TRUE == getClientProperty("Table.isFileList")) {
    2359                         sm.addSelectionInterval(index, index);
    2360                         sm.setAnchorSelectionIndex(anchor);
    2361                     }
    2362                 }
    2363             }
    2364             else {
    2365                 sm.setSelectionInterval(anchor, index);
    2366             }
    2367         }
    2368         else {
    2369             if (toggle) {
    2370                 if (selected) {
    2371                     sm.removeSelectionInterval(index, index);
    2372                 }
    2373                 else {
    2374                     sm.addSelectionInterval(index, index);
    2375                 }
    2376             }
    2377             else {
    2378                 sm.setSelectionInterval(index, index);
    2379             }
    2380         }
    2381     }
    2382
    2383     /**
    2384      * Updates the selection models of the table, depending on the state of the
    2385      * two flags: <code>toggle</code> and <code>extend</code>. Most changes
    2386      * to the selection that are the result of keyboard or mouse events received
    2387      * by the UI are channeled through this method so that the behavior may be
    2388      * overridden by a subclass. Some UIs may need more functionality than
    2389      * this method provides, such as when manipulating the lead for discontiguous
    2390      * selection, and may not call into this method for some selection changes.
    2391      * <p>
    2392      * This implementation uses the following conventions:
    2393      * <ul>
    2394      * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>false</em>.
    2395      *      Clear the previous selection and ensure the new cell is selected.
    2396      * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>true</em>.
    2397      *      Extend the previous selection from the anchor to the specified cell,
    2398      *      clearing all other selections.
    2399      * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>false</em>.
    2400      *      If the specified cell is selected, deselect it. If it is not selected, select it.
    2401      * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>true</em>.
    2402      *      Apply the selection state of the anchor to all cells between it and the
    2403      *      specified cell.
    2404      * </ul>
    2405      * @param  rowIndex   affects the selection at <code>row</code>
    2406      * @param  columnIndex  affects the selection at <code>column</code>
    2407      * @param  toggle  see description above
    2408      * @param  extend  if true, extend the current selection
    2409      *
    2410      * @since 1.3
    2411      */
    2412     public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
    2413         ListSelectionModel rsm = getSelectionModel();
    2414         ListSelectionModel csm = getColumnModel().getSelectionModel();
    2415
    2416         int anchorRow = getAdjustedIndex(rsm.getAnchorSelectionIndex(), true);
    2417         int anchorCol = getAdjustedIndex(csm.getAnchorSelectionIndex(), false);
    2418
    2419         boolean anchorSelected = true;
    2420
    2421         if (anchorRow == -1) {
    2422             if (getRowCount() > 0) {
    2423                 anchorRow = 0;
    2424             }
    2425             anchorSelected = false;
    2426         }
    2427
    2428         if (anchorCol == -1) {
    2429             if (getColumnCount() > 0) {
    2430                 anchorCol = 0;
    2431             }
    2432             anchorSelected = false;
    2433         }
    2434
    2435         // Check the selection here rather than in each selection model.
    2436         // This is significant in cell selection mode if we are supposed
    2437         // to be toggling the selection. In this case it is better to
    2438         // ensure that the cell's selection state will indeed be changed.
    2439         // If this were done in the code for the selection model it
    2440         // might leave a cell in selection state if the row was
    2441         // selected but the column was not - as it would toggle them both.
    2442         boolean selected = isCellSelected(rowIndex, columnIndex);
    2443         anchorSelected = anchorSelected && isCellSelected(anchorRow, anchorCol);
    2444
    2445         changeSelectionModel(csm, columnIndex, toggle, extend, selected,
    2446                              anchorCol, anchorSelected);
    2447         changeSelectionModel(rsm, rowIndex, toggle, extend, selected,
    2448                              anchorRow, anchorSelected);
    2449
    2450         // Scroll after changing the selection as blit scrolling is immediate,
    2451         // so that if we cause the repaint after the scroll we end up painting
    2452         // everything!
    2453         if (getAutoscrolls()) {
    2454             Rectangle cellRect = getCellRect(rowIndex, columnIndex, false);
    2455             if (cellRect != null) {
    2456                 scrollRectToVisible(cellRect);
    2457             }
    2458         }
    2459     }
    2460
    2461     /**
    2462      * Returns the foreground color for selected cells.
    2463      *
    2464      * @return the <code>Color</code> object for the foreground property
    2465      * @see #setSelectionForeground
    2466      * @see #setSelectionBackground
    2467      */
    2468     public Color getSelectionForeground() {
    2469         return selectionForeground;
    2470     }
    2471
    2472     /**
    2473      * Sets the foreground color for selected cells.  Cell renderers
    2474      * can use this color to render text and graphics for selected
    2475      * cells.
    2476      * <p>
    2477      * The default value of this property is defined by the look
    2478      * and feel implementation.
    2479      * <p>
    2480      * This is a <a href="http://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html">JavaBeans</a> bound property.
    2481      *
    2482      * @param selectionForeground  the <code>Color</code> to use in the foreground
    2483      *                             for selected list items
    2484      * @see #getSelectionForeground
    2485      * @see #setSelectionBackground
    2486      * @see #setForeground
    2487      * @see #setBackground
    2488      * @see #setFont
    2489      */
    2490     @BeanProperty(description
    2491             = "A default foreground color for selected cells.")
    2492     public void setSelectionForeground(Color selectionForeground) {
    2493         Color old = this.selectionForeground;
    2494         this.selectionForeground = selectionForeground;
    2495         firePropertyChange("selectionForeground", old, selectionForeground);
    2496         repaint();
    2497     }
    2498
    2499     /**
    2500      * Returns the background color for selected cells.
    2501      *
    2502      * @return the <code>Color</code> used for the background of selected list items
    2503      * @see #setSelectionBackground
    2504      * @see #setSelectionForeground
    2505      */
    2506     public Color getSelectionBackground() {
    2507         return selectionBackground;
    2508     }
    2509
    2510     /**
    2511      * Sets the background color for selected cells.  Cell renderers
    2512      * can use this color to the fill selected cells.
    2513      * <p>
    2514      * The default value of this property is defined by the look
    2515      * and feel implementation.
    2516      * <p>
    2517      * This is a <a href="http://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html">JavaBeans</a> bound property.
    2518      *
    2519      * @param selectionBackground  the <code>Color</code> to use for the background
    2520      *                             of selected cells
    2521      * @see #getSelectionBackground
    2522      * @see #setSelectionForeground
    2523      * @see #setForeground
    2524      * @see #setBackground
    2525      * @see #setFont
    2526      */
    2527     @BeanProperty(description
    2528             = "A default background color for selected cells.")
    2529     public void setSelectionBackground(Color selectionBackground) {
    2530         Color old = this.selectionBackground;
    2531         this.selectionBackground = selectionBackground;
    2532         firePropertyChange("selectionBackground", old, selectionBackground);
    2533         repaint();
    2534     }
    2535
    2536     /**
    2537      * Returns the <code>TableColumn</code> object for the column in the table
    2538      * whose identifier is equal to <code>identifier</code>, when compared using
    2539      * <code>equals</code>.
    2540      *
    2541      * @return  the <code>TableColumn</code> object that matches the identifier
    2542      * @exception IllegalArgumentException      if <code>identifier</code> is <code>null</code> or no <code>TableColumn</code> has this identifier
    2543      *
    2544      * @param   identifier                      the identifier object
    2545      */
    2546     public TableColumn getColumn(Object identifier) {
    2547         TableColumnModel cm = getColumnModel();
    2548         int columnIndex = cm.getColumnIndex(identifier);
    2549         return cm.getColumn(columnIndex);
    2550     }
    2551
    2552 //
    2553 // Informally implement the TableModel interface.
    2554 //
    2555
    2556     /**
    2557      * Maps the index of the column in the view at
    2558      * <code>viewColumnIndex</code> to the index of the column
    2559      * in the table model.  Returns the index of the corresponding
    2560      * column in the model.  If <code>viewColumnIndex</code>
    2561      * is less than zero, returns <code>viewColumnIndex</code>.
    2562      *
    2563      * @param   viewColumnIndex     the index of the column in the view
    2564      * @return  the index of the corresponding column in the model
    2565      *
    2566      * @see #convertColumnIndexToView
    2567      */
    2568     public int convertColumnIndexToModel(int viewColumnIndex) {
    2569         return SwingUtilities2.convertColumnIndexToModel(
    2570                 getColumnModel(), viewColumnIndex);
    2571     }
    2572
    2573     /**
    2574      * Maps the index of the column in the table model at
    2575      * <code>modelColumnIndex</code> to the index of the column
    2576      * in the view.  Returns the index of the
    2577      * corresponding column in the view; returns -1 if this column is not
    2578      * being displayed.  If <code>modelColumnIndex</code> is less than zero,
    2579      * returns <code>modelColumnIndex</code>.
    2580      *
    2581      * @param   modelColumnIndex     the index of the column in the model
    2582      * @return   the index of the corresponding column in the view
    2583      *
    2584      * @see #convertColumnIndexToModel
    2585      */
    2586     public int convertColumnIndexToView(int modelColumnIndex) {
    2587         return SwingUtilities2.convertColumnIndexToView(
    2588                 getColumnModel(), modelColumnIndex);
    2589     }
    2590
    2591     /**
    2592      * Maps the index of the row in terms of the
    2593      * <code>TableModel</code> to the view.  If the contents of the
    2594      * model are not sorted the model and view indices are the same.
    2595      *
    2596      * @param modelRowIndex the index of the row in terms of the model
    2597      * @return the index of the corresponding row in the view, or -1 if
    2598      *         the row isn't visible
    2599      * @throws IndexOutOfBoundsException if sorting is enabled and passed an
    2600      *         index outside the number of rows of the <code>TableModel</code>
    2601      * @see javax.swing.table.TableRowSorter
    2602      * @since 1.6
    2603      */
    2604     public int convertRowIndexToView(int modelRowIndex) {
    2605         RowSorter<?> sorter = getRowSorter();
    2606         if (sorter != null) {
    2607             return sorter.convertRowIndexToView(modelRowIndex);
    2608         }
    2609         return modelRowIndex;
    2610     }
    2611
    2612     /**
    2613      * Maps the index of the row in terms of the view to the
    2614      * underlying <code>TableModel</code>.  If the contents of the
    2615      * model are not sorted the model and view indices are the same.
    2616      *
    2617      * @param viewRowIndex the index of the row in the view
    2618      * @return the index of the corresponding row in the model
    2619      * @throws IndexOutOfBoundsException if sorting is enabled and passed an
    2620      *         index outside the range of the <code>JTable</code> as
    2621      *         determined by the method <code>getRowCount</code>
    2622      * @see javax.swing.table.TableRowSorter
    2623      * @see #getRowCount
    2624      * @since 1.6
    2625      */
    2626     public int convertRowIndexToModel(int viewRowIndex) {
    2627         RowSorter<?> sorter = getRowSorter();
    2628         if (sorter != null) {
    2629             return sorter.convertRowIndexToModel(viewRowIndex);
    2630         }
    2631         return viewRowIndex;
    2632     }
    2633
    2634     /**
    2635      * Returns the number of rows that can be shown in the
    2636      * <code>JTable</code>, given unlimited space.  If a
    2637      * <code>RowSorter</code> with a filter has been specified, the
    2638      * number of rows returned may differ from that of the underlying
    2639      * <code>TableModel</code>.
    2640      *
    2641      * @return the number of rows shown in the <code>JTable</code>
    2642      * @see #getColumnCount
    2643      */
    2644     @BeanProperty(bound = false)
    2645     public int getRowCount() {
    2646         RowSorter<?> sorter = getRowSorter();
    2647         if (sorter != null) {
    2648             return sorter.getViewRowCount();
    2649         }
    2650         return getModel().getRowCount();
    2651     }
    2652
    2653     /**
    2654      * Returns the number of columns in the column model. Note that this may
    2655      * be different from the number of columns in the table model.
    2656      *
    2657      * @return  the number of columns in the table
    2658      * @see #getRowCount
    2659      * @see #removeColumn
    2660      */
    2661     @BeanProperty(bound = false)
    2662     public int getColumnCount() {
    2663         return getColumnModel().getColumnCount();
    2664     }
    2665
    2666     /**
    2667      * Returns the name of the column appearing in the view at
    2668      * column position <code>column</code>.
    2669      *
    2670      * @param  column    the column in the view being queried
    2671      * @return the name of the column at position <code>column</code>
    2672                         in the view where the first column is column 0
    2673      */
    2674     public String getColumnName(int column) {
    2675         return getModel().getColumnName(convertColumnIndexToModel(column));
    2676     }
    2677
    2678     /**
    2679      * Returns the type of the column appearing in the view at
    2680      * column position <code>column</code>.
    2681      *
    2682      * @param   column   the column in the view being queried
    2683      * @return the type of the column at position <code>column</code>
    2684      *          in the view where the first column is column 0
    2685      */
    2686     public Class<?> getColumnClass(int column) {
    2687         return getModel().getColumnClass(convertColumnIndexToModel(column));
    2688     }
    2689
    2690     /**
    2691      * Returns the cell value at <code>row</code> and <code>column</code>.
    2692      * <p>
    2693      * <b>Note</b>: The column is specified in the table view's display
    2694      *              order, and not in the <code>TableModel</code>'s column
    2695      *              order.  This is an important distinction because as the
    2696      *              user rearranges the columns in the table,
    2697      *              the column at a given index in the view will change.
    2698      *              Meanwhile the user's actions never affect the model's
    2699      *              column ordering.
    2700      *
    2701      * @param   row             the row whose value is to be queried
    2702      * @param   column          the column whose value is to be queried
    2703      * @return  the Object at the specified cell
    2704      */
    2705     public Object getValueAt(int row, int column) {
    2706         return getModel().getValueAt(convertRowIndexToModel(row),
    2707                                      convertColumnIndexToModel(column));
    2708     }
    2709
    2710     /**
    2711      * Sets the value for the cell in the table model at <code>row</code>
    2712      * and <code>column</code>.
    2713      * <p>
    2714      * <b>Note</b>: The column is specified in the table view's display
    2715      *              order, and not in the <code>TableModel</code>'s column
    2716      *              order.  This is an important distinction because as the
    2717      *              user rearranges the columns in the table,
    2718      *              the column at a given index in the view will change.
    2719      *              Meanwhile the user's actions never affect the model's
    2720      *              column ordering.
    2721      *
    2722      * <code>aValue</code> is the new value.
    2723      *
    2724      * @param   aValue          the new value
    2725      * @param   row             the row of the cell to be changed
    2726      * @param   column          the column of the cell to be changed
    2727      * @see #getValueAt
    2728      */
    2729     public void setValueAt(Object aValue, int row, int column) {
    2730         getModel().setValueAt(aValue, convertRowIndexToModel(row),
    2731                               convertColumnIndexToModel(column));
    2732     }
    2733
    2734     /**
    2735      * Returns true if the cell at <code>row</code> and <code>column</code>
    2736      * is editable.  Otherwise, invoking <code>setValueAt</code> on the cell
    2737      * will have no effect.
    2738      * <p>
    2739      * <b>Note</b>: The column is specified in the table view's display
    2740      *              order, and not in the <code>TableModel</code>'s column
    2741      *              order.  This is an important distinction because as the
    2742      *              user rearranges the columns in the table,
    2743      *              the column at a given index in the view will change.
    2744      *              Meanwhile the user's actions never affect the model's
    2745      *              column ordering.
    2746      *
    2747      *
    2748      * @param   row      the row whose value is to be queried
    2749      * @param   column   the column whose value is to be queried
    2750      * @return  true if the cell is editable
    2751      * @see #setValueAt
    2752      */
    2753     public boolean isCellEditable(int row, int column) {
    2754         return getModel().isCellEditable(convertRowIndexToModel(row),
    2755                                          convertColumnIndexToModel(column));
    2756     }
    2757 //
    2758 // Adding and removing columns in the view
    2759 //
    2760
    2761     /**
    2762      *  Appends <code>aColumn</code> to the end of the array of columns held by
    2763      *  this <code>JTable</code>'s column model.
    2764      *  If the column name of <code>aColumn</code> is <code>null</code>,
    2765      *  sets the column name of <code>aColumn</code> to the name
    2766      *  returned by <code>getModel().getColumnName()</code>.
    2767      *  <p>
    2768      *  To add a column to this <code>JTable</code> to display the
    2769      *  <code>modelColumn</code>'th column of data in the model with a
    2770      *  given <code>width</code>, <code>cellRenderer</code>,
    2771      *  and <code>cellEditor</code> you can use:
    2772      *  <pre>
    2773      *
    2774      *      addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
    2775      *
    2776      *  </pre>
    2777      *  [Any of the <code>TableColumn</code> constructors can be used
    2778      *  instead of this one.]
    2779      *  The model column number is stored inside the <code>TableColumn</code>
    2780      *  and is used during rendering and editing to locate the appropriates
    2781      *  data values in the model. The model column number does not change
    2782      *  when columns are reordered in the view.
    2783      *
    2784      *  @param  aColumn         the <code>TableColumn</code> to be added
    2785      *  @see    #removeColumn
    2786      */
    2787     public void addColumn(TableColumn aColumn) {
    2788         if (aColumn.getHeaderValue() == null) {
    2789             int modelColumn = aColumn.getModelIndex();
    2790             String columnName = getModel().getColumnName(modelColumn);
    2791             aColumn.setHeaderValue(columnName);
    2792         }
    2793         getColumnModel().addColumn(aColumn);
    2794     }
    2795
    2796     /**
    2797      *  Removes <code>aColumn</code> from this <code>JTable</code>'s
    2798      *  array of columns.  Note: this method does not remove the column
    2799      *  of data from the model; it just removes the <code>TableColumn</code>
    2800      *  that was responsible for displaying it.
    2801      *
    2802      *  @param  aColumn         the <code>TableColumn</code> to be removed
    2803      *  @see    #addColumn
    2804      */
    2805     public void removeColumn(TableColumn aColumn) {
    2806         getColumnModel().removeColumn(aColumn);
    2807     }
    2808
    2809     /**
    2810      * Moves the column <code>column</code> to the position currently
    2811      * occupied by the column <code>targetColumn</code> in the view.
    2812      * The old column at <code>targetColumn</code> is
    2813      * shifted left or right to make room.
    2814      *
    2815      * @param   column                  the index of column to be moved
    2816      * @param   targetColumn            the new index of the column
    2817      */
    2818     public void moveColumn(int column, int targetColumn) {
    2819         getColumnModel().moveColumn(column, targetColumn);
    2820     }
    2821
    2822 //
    2823 // Cover methods for various models and helper methods
    2824 //
    2825
    2826     /**
    2827      * Returns the index of the column that <code>point</code> lies in,
    2828      * or -1 if the result is not in the range
    2829      * [0, <code>getColumnCount()</code>-1].
    2830      *
    2831      * @param   point   the location of interest
    2832      * @return  the index of the column that <code>point</code> lies in,
    2833      *          or -1 if the result is not in the range
    2834      *          [0, <code>getColumnCount()</code>-1]
    2835      * @see     #rowAtPoint
    2836      */
    2837     public int columnAtPoint(Point point) {
    2838         int x = point.x;
    2839         if( !getComponentOrientation().isLeftToRight() ) {
    2840             x = getWidth() - x - 1;
    2841         }
    2842         return getColumnModel().getColumnIndexAtX(x);
    2843     }
    2844
    2845     /**
    2846      * Returns the index of the row that <code>point</code> lies in,
    2847      * or -1 if the result is not in the range
    2848      * [0, <code>getRowCount()</code>-1].
    2849      *
    2850      * @param   point   the location of interest
    2851      * @return  the index of the row that <code>point</code> lies in,
    2852      *          or -1 if the result is not in the range
    2853      *          [0, <code>getRowCount()</code>-1]
    2854      * @see     #columnAtPoint
    2855      */
    2856     public int rowAtPoint(Point point) {
    2857         int y = point.y;
    2858         int result = (rowModel == null) ?  y/getRowHeight() : rowModel.getIndex(y);
    2859         if (result < 0) {
    2860             return -1;
    2861         }
    2862         else if (result >= getRowCount()) {
    2863             return -1;
    2864         }
    2865         else {
    2866             return result;
    2867         }
    2868     }
    2869
    2870     /**
    2871      * Returns a rectangle for the cell that lies at the intersection of
    2872      * <code>row</code> and <code>column</code>.
    2873      * If <code>includeSpacing</code> is true then the value returned
    2874      * has the full height and width of the row and column
    2875      * specified. If it is false, the returned rectangle is inset by the
    2876      * intercell spacing to return the true bounds of the rendering or
    2877      * editing component as it will be set during rendering.
    2878      * <p>
    2879      * If the column index is valid but the row index is less
    2880      * than zero the method returns a rectangle with the
    2881      * <code>y</code> and <code>height</code> values set appropriately
    2882      * and the <code>x</code> and <code>width</code> values both set
    2883      * to zero. In general, when either the row or column indices indicate a
    2884      * cell outside the appropriate range, the method returns a rectangle
    2885      * depicting the closest edge of the closest cell that is within
    2886      * the table's range. When both row and column indices are out
    2887      * of range the returned rectangle covers the closest
    2888      * point of the closest cell.
    2889      * <p>
    2890      * In all cases, calculations that use this method to calculate
    2891      * results along one axis will not fail because of anomalies in
    2892      * calculations along the other axis. When the cell is not valid
    2893      * the <code>includeSpacing</code> parameter is ignored.
    2894      *
    2895      * @param   row                   the row index where the desired cell
    2896      *                                is located
    2897      * @param   column                the column index where the desired cell
    2898      *                                is located in the display; this is not
    2899      *                                necessarily the same as the column index
    2900      *                                in the data model for the table; the
    2901      *                                {@link #convertColumnIndexToView(int)}
    2902      *                                method may be used to convert a data
    2903      *                                model column index to a display
    2904      *                                column index
    2905      * @param   includeSpacing        if false, return the true cell bounds -
    2906      *                                computed by subtracting the intercell
    2907      *                                spacing from the height and widths of
    2908      *                                the column and row models
    2909      *
    2910      * @return  the rectangle containing the cell at location
    2911      *          <code>row</code>,<code>column</code>
    2912      * @see #getIntercellSpacing
    2913      */
    2914     public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
    2915         Rectangle r = new Rectangle();
    2916         boolean valid = true;
    2917         if (row < 0) {
    2918             // y = height = 0;
    2919             valid = false;
    2920         }
    2921         else if (row >= getRowCount()) {
    2922             r.y = getHeight();
    2923             valid = false;
    2924         }
    2925         else {
    2926             r.height = getRowHeight(row);
    2927             r.y = (rowModel == null) ? row * r.height : rowModel.getPosition(row);
    2928         }
    2929
    2930         if (column < 0) {
    2931             if( !getComponentOrientation().isLeftToRight() ) {
    2932                 r.x = getWidth();
    2933             }
    2934             // otherwise, x = width = 0;
    2935             valid = false;
    2936         }
    2937         else if (column >= getColumnCount()) {
    2938             if( getComponentOrientation().isLeftToRight() ) {
    2939                 r.x = getWidth();
    2940             }
    2941             // otherwise, x = width = 0;
    2942             valid = false;
    2943         }
    2944         else {
    2945             TableColumnModel cm = getColumnModel();
    2946             if( getComponentOrientation().isLeftToRight() ) {
    2947                 for(int i = 0; i < column; i++) {
    2948                     r.x += cm.getColumn(i).getWidth();
    2949                 }
    2950             } else {
    2951                 for(int i = cm.getColumnCount()-1; i > column; i--) {
    2952                     r.x += cm.getColumn(i).getWidth();
    2953                 }
    2954             }
    2955             r.width = cm.getColumn(column).getWidth();
    2956         }
    2957
    2958         if (valid && !includeSpacing) {
    2959             // Bound the margins by their associated dimensions to prevent
    2960             // returning bounds with negative dimensions.
    2961             int rm = Math.min(getRowMargin(), r.height);
    2962             int cm = Math.min(getColumnModel().getColumnMargin(), r.width);
    2963             // This is not the same as grow(), it rounds differently.
    2964             r.setBounds(r.x + cm/2, r.y + rm/2, r.width - cm, r.height - rm);
    2965         }
    2966         return r;
    2967     }
    2968
    2969     private int viewIndexForColumn(TableColumn aColumn) {
    2970         TableColumnModel cm = getColumnModel();
    2971         for (int column = 0; column < cm.getColumnCount(); column++) {
    2972             if (cm.getColumn(column) == aColumn) {
    2973                 return column;
    2974             }
    2975         }
    2976         return -1;
    2977     }
    2978
    2979     /**
    2980      * Causes this table to lay out its rows and columns.  Overridden so
    2981      * that columns can be resized to accommodate a change in the size of
    2982      * a containing parent.
    2983      * Resizes one or more of the columns in the table
    2984      * so that the total width of all of this <code>JTable</code>'s
    2985      * columns is equal to the width of the table.
    2986      * <p>
    2987      * Before the layout begins the method gets the
    2988      * <code>resizingColumn</code> of the <code>tableHeader</code>.
    2989      * When the method is called as a result of the resizing of an enclosing window,
    2990      * the <code>resizingColumn</code> is <code>null</code>. This means that resizing
    2991      * has taken place "outside" the <code>JTable</code> and the change -
    2992      * or "delta" - should be distributed to all of the columns regardless
    2993      * of this <code>JTable</code>'s automatic resize mode.
    2994      * <p>
    2995      * If the <code>resizingColumn</code> is not <code>null</code>, it is one of
    2996      * the columns in the table that has changed size rather than
    2997      * the table itself. In this case the auto-resize modes govern
    2998      * the way the extra (or deficit) space is distributed
    2999      * amongst the available columns.
    3000      * <p>
    3001      * The modes are:
    3002      * <ul>
    3003      * <li>  AUTO_RESIZE_OFF: Don't automatically adjust the column's
    3004      * widths at all. Use a horizontal scrollbar to accommodate the
    3005      * columns when their sum exceeds the width of the
    3006      * <code>Viewport</code>.  If the <code>JTable</code> is not
    3007      * enclosed in a <code>JScrollPane</code> this may
    3008      * leave parts of the table invisible.
    3009      * <li>  AUTO_RESIZE_NEXT_COLUMN: Use just the column after the
    3010      * resizing column. This results in the "boundary" or divider
    3011      * between adjacent cells being independently adjustable.
    3012      * <li>  AUTO_RESIZE_SUBSEQUENT_COLUMNS: Use all columns after the
    3013      * one being adjusted to absorb the changes.  This is the
    3014      * default behavior.
    3015      * <li>  AUTO_RESIZE_LAST_COLUMN: Automatically adjust the
    3016      * size of the last column only. If the bounds of the last column
    3017      * prevent the desired size from being allocated, set the
    3018      * width of the last column to the appropriate limit and make
    3019      * no further adjustments.
    3020      * <li>  AUTO_RESIZE_ALL_COLUMNS: Spread the delta amongst all the columns
    3021      * in the <code>JTable</code>, including the one that is being
    3022      * adjusted.
    3023      * </ul>
    3024      * <p>
    3025      * <b>Note:</b> When a <code>JTable</code> makes adjustments
    3026      *   to the widths of the columns it respects their minimum and
    3027      *   maximum values absolutely.  It is therefore possible that,
    3028      *   even after this method is called, the total width of the columns
    3029      *   is still not equal to the width of the table. When this happens
    3030      *   the <code>JTable</code> does not put itself
    3031      *   in AUTO_RESIZE_OFF mode to bring up a scroll bar, or break other
    3032      *   commitments of its current auto-resize mode -- instead it
    3033      *   allows its bounds to be set larger (or smaller) than the total of the
    3034      *   column minimum or maximum, meaning, either that there
    3035      *   will not be enough room to display all of the columns, or that the
    3036      *   columns will not fill the <code>JTable</code>'s bounds.
    3037      *   These respectively, result in the clipping of some columns
    3038      *   or an area being painted in the <code>JTable</code>'s
    3039      *   background color during painting.
    3040      * <p>
    3041      *   The mechanism for distributing the delta amongst the available
    3042      *   columns is provided in a private method in the <code>JTable</code>
    3043      *   class:
    3044      * <pre>
    3045      *   adjustSizes(long targetSize, final Resizable3 r, boolean inverse)
    3046      * </pre>
    3047      *   an explanation of which is provided in the following section.
    3048      *   <code>Resizable3</code> is a private
    3049      *   interface that allows any data structure containing a collection
    3050      *   of elements with a size, preferred size, maximum size and minimum size
    3051      *   to have its elements manipulated by the algorithm.
    3052      *
    3053      * <H3> Distributing the delta </H3>
    3054      *
    3055      * <H4> Overview </H4>
    3056      * <P>
    3057      * Call "DELTA" the difference between the target size and the
    3058      * sum of the preferred sizes of the elements in r. The individual
    3059      * sizes are calculated by taking the original preferred
    3060      * sizes and adding a share of the DELTA - that share being based on
    3061      * how far each preferred size is from its limiting bound (minimum or
    3062      * maximum).
    3063      *
    3064      * <H4>Definition</H4>
    3065      * <P>
    3066      * Call the individual constraints min[i], max[i], and pref[i].
    3067      * <p>
    3068      * Call their respective sums: MIN, MAX, and PREF.
    3069      * <p>
    3070      * Each new size will be calculated using:
    3071      *
    3072      * <pre>
    3073      *          size[i] = pref[i] + delta[i]
    3074      * </pre>
    3075      * where each individual delta[i] is calculated according to:
    3076      * <p>
    3077      * If (DELTA &lt; 0) we are in shrink mode where:
    3078      *
    3079      * <PRE>
    3080      *                        DELTA
    3081      *          delta[i] = ------------ * (pref[i] - min[i])
    3082      *                     (PREF - MIN)
    3083      * </PRE>
    3084      * If (DELTA &gt; 0) we are in expand mode where:
    3085      *
    3086      * <PRE>
    3087      *                        DELTA
    3088      *          delta[i] = ------------ * (max[i] - pref[i])
    3089      *                      (MAX - PREF)
    3090      * </PRE>
    3091      * <P>
    3092      * The overall effect is that the total size moves that same percentage,
    3093      * k, towards the total minimum or maximum and that percentage guarantees
    3094      * accommodation of the required space, DELTA.
    3095      *
    3096      * <H4>Details</H4>
    3097      * <P>
    3098      * Naive evaluation of the formulae presented here would be subject to
    3099      * the aggregated rounding errors caused by doing this operation in finite
    3100      * precision (using ints). To deal with this, the multiplying factor above,
    3101      * is constantly recalculated and this takes account of the rounding
    3102      * errors in the previous iterations. The result is an algorithm that
    3103      * produces a set of integers whose values exactly sum to the supplied
    3104      * <code>targetSize</code>, and does so by spreading the rounding
    3105      * errors evenly over the given elements.
    3106      *
    3107      * <H4>When the MAX and MIN bounds are hit</H4>
    3108      * <P>
    3109      * When <code>targetSize</code> is outside the [MIN, MAX] range,
    3110      * the algorithm sets all sizes to their appropriate limiting value
    3111      * (maximum or minimum).
    3112      *
    3113      */
    3114     public void doLayout() {
    3115         TableColumn resizingColumn = getResizingColumn();
    3116         if (resizingColumn == null) {
    3117             setWidthsFromPreferredWidths(false);
    3118         }
    3119         else {
    3120             // JTable behaves like a layout manger - but one in which the
    3121             // user can come along and dictate how big one of the children
    3122             // (columns) is supposed to be.
    3123
    3124             // A column has been resized and JTable may need to distribute
    3125             // any overall delta to other columns, according to the resize mode.
    3126             int columnIndex = viewIndexForColumn(resizingColumn);
    3127             int delta = getWidth() - getColumnModel().getTotalColumnWidth();
    3128             accommodateDelta(columnIndex, delta);
    3129             delta = getWidth() - getColumnModel().getTotalColumnWidth();
    3130
    3131             // If the delta cannot be completely accomodated, then the
    3132             // resizing column will have to take any remainder. This means
    3133             // that the column is not being allowed to take the requested
    3134             // width. This happens under many circumstances: For example,
    3135             // AUTO_RESIZE_NEXT_COLUMN specifies that any delta be distributed
    3136             // to the column after the resizing column. If one were to attempt
    3137             // to resize the last column of the table, there would be no
    3138             // columns after it, and hence nowhere to distribute the delta.
    3139             // It would then be given entirely back to the resizing column,
    3140             // preventing it from changing size.
    3141             if (delta != 0) {
    3142                 resizingColumn.setWidth(resizingColumn.getWidth() + delta);
    3143             }
    3144
    3145             // At this point the JTable has to work out what preferred sizes
    3146             // would have resulted in the layout the user has chosen.
    3147             // Thereafter, during window resizing etc. it has to work off
    3148             // the preferred sizes as usual - the idea being that, whatever
    3149             // the user does, everything stays in synch and things don't jump
    3150             // around.
    3151             setWidthsFromPreferredWidths(true);
    3152         }
    3153
    3154         super.doLayout();
    3155     }
    3156
    3157     private TableColumn getResizingColumn() {
    3158         return (tableHeader == null) ? null
    3159                                      : tableHeader.getResizingColumn();
    3160     }
    3161
    3162     /**
    3163      * Sizes the table columns to fit the available space.
    3164      *
    3165      * @param lastColumnOnly determines whether to resize last column only
    3166      * @deprecated As of Swing version 1.0.3,
    3167      * replaced by <code>doLayout()</code>.
    3168      * @see #doLayout
    3169      */
    3170     @Deprecated
    3171     public void sizeColumnsToFit(boolean lastColumnOnly) {
    3172         int oldAutoResizeMode = autoResizeMode;
    3173         setAutoResizeMode(lastColumnOnly ? AUTO_RESIZE_LAST_COLUMN
    3174                                          : AUTO_RESIZE_ALL_COLUMNS);
    3175         sizeColumnsToFit(-1);
    3176         setAutoResizeMode(oldAutoResizeMode);
    3177     }
    3178
    3179     /**
    3180      * Obsolete as of Java 2 platform v1.4.  Please use the
    3181      * <code>doLayout()</code> method instead.
    3182      * @param resizingColumn    the column whose resizing made this adjustment
    3183      *                          necessary or -1 if there is no such column
    3184      * @see  #doLayout
    3185      */
    3186     public void sizeColumnsToFit(int resizingColumn) {
    3187         if (resizingColumn == -1) {
    3188             setWidthsFromPreferredWidths(false);
    3189         }
    3190         else {
    3191             if (autoResizeMode == AUTO_RESIZE_OFF) {
    3192                 TableColumn aColumn = getColumnModel().getColumn(resizingColumn);
    3193                 aColumn.setPreferredWidth(aColumn.getWidth());
    3194             }
    3195             else {
    3196                 int delta = getWidth() - getColumnModel().getTotalColumnWidth();
    3197                 accommodateDelta(resizingColumn, delta);
    3198                 setWidthsFromPreferredWidths(true);
    3199             }
    3200         }
    3201     }
    3202
    3203     private void setWidthsFromPreferredWidths(final boolean inverse) {
    3204         int totalWidth     = getWidth();
    3205         int totalPreferred = getPreferredSize().width;
    3206         int target = !inverse ? totalWidth : totalPreferred;
    3207
    3208         final TableColumnModel cm = columnModel;
    3209         Resizable3 r = new Resizable3() {
    3210             public int  getElementCount()      { return cm.getColumnCount(); }
    3211             public int  getLowerBoundAt(int i) { return cm.getColumn(i).getMinWidth(); }
    3212             public int  getUpperBoundAt(int i) { return cm.getColumn(i).getMaxWidth(); }
    3213             public int  getMidPointAt(int i)  {
    3214                 if (!inverse) {
    3215                     return cm.getColumn(i).getPreferredWidth();
    3216                 }
    3217                 else {
    3218                     return cm.getColumn(i).getWidth();
    3219                 }
    3220             }
    3221             public void setSizeAt(int s, int i) {
    3222                 if (!inverse) {
    3223                     cm.getColumn(i).setWidth(s);
    3224                 }
    3225                 else {
    3226                     cm.getColumn(i).setPreferredWidth(s);
    3227                 }
    3228             }
    3229         };
    3230
    3231         adjustSizes(target, r, inverse);
    3232     }
    3233
    3234
    3235     // Distribute delta over columns, as indicated by the autoresize mode.
    3236     private void accommodateDelta(int resizingColumnIndex, int delta) {
    3237         int columnCount = getColumnCount();
    3238         int from = resizingColumnIndex;
    3239         int to;
    3240
    3241         // Use the mode to determine how to absorb the changes.
    3242         switch(autoResizeMode) {
    3243             case AUTO_RESIZE_NEXT_COLUMN:
    3244                 from = from + 1;
    3245                 to = Math.min(from + 1, columnCount); break;
    3246             case AUTO_RESIZE_SUBSEQUENT_COLUMNS:
    3247                 from = from + 1;
    3248                 to = columnCount; break;
    3249             case AUTO_RESIZE_LAST_COLUMN:
    3250                 from = columnCount - 1;
    3251                 to = from + 1; break;
    3252             case AUTO_RESIZE_ALL_COLUMNS:
    3253                 from = 0;
    3254                 to = columnCount; break;
    3255             default:
    3256                 return;
    3257         }
    3258
    3259         final int start = from;
    3260         final int end = to;
    3261         final TableColumnModel cm = columnModel;
    3262         Resizable3 r = new Resizable3() {
    3263             public int  getElementCount()       { return end-start; }
    3264             public int  getLowerBoundAt(int i)  { return cm.getColumn(i+start).getMinWidth(); }
    3265             public int  getUpperBoundAt(int i)  { return cm.getColumn(i+start).getMaxWidth(); }
    3266             public int  getMidPointAt(int i)    { return cm.getColumn(i+start).getWidth(); }
    3267             public void setSizeAt(int s, int i) {        cm.getColumn(i+start).setWidth(s); }
    3268         };
    3269
    3270         int totalWidth = 0;
    3271         for(int i = from; i < to; i++) {
    3272             TableColumn aColumn = columnModel.getColumn(i);
    3273             int input = aColumn.getWidth();
    3274             totalWidth = totalWidth + input;
    3275         }
    3276
    3277         adjustSizes(totalWidth + delta, r, false);
    3278     }
    3279
    3280     private interface Resizable2 {
    3281         public int  getElementCount();
    3282         public int  getLowerBoundAt(int i);
    3283         public int  getUpperBoundAt(int i);
    3284         public void setSizeAt(int newSize, int i);
    3285     }
    3286
    3287     private interface Resizable3 extends Resizable2 {
    3288         public int  getMidPointAt(int i);
    3289     }
    3290
    3291
    3292     private void adjustSizes(long target, final Resizable3 r, boolean inverse) {
    3293         int N = r.getElementCount();
    3294         long totalPreferred = 0;
    3295         for(int i = 0; i < N; i++) {
    3296             totalPreferred += r.getMidPointAt(i);
    3297         }
    3298         Resizable2 s;
    3299         if ((target < totalPreferred) == !inverse) {
    3300             s = new Resizable2() {
    3301                 public int  getElementCount()      { return r.getElementCount(); }
    3302                 public int  getLowerBoundAt(int i) { return r.getLowerBoundAt(i); }
    3303                 public int  getUpperBoundAt(int i) { return r.getMidPointAt(i); }
    3304                 public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
    3305
    3306             };
    3307         }
    3308         else {
    3309             s = new Resizable2() {
    3310                 public int  getElementCount()      { return r.getElementCount(); }
    3311                 public int  getLowerBoundAt(int i) { return r.getMidPointAt(i); }
    3312                 public int  getUpperBoundAt(int i) { return r.getUpperBoundAt(i); }
    3313                 public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
    3314
    3315             };
    3316         }
    3317         adjustSizes(target, s, !inverse);
    3318     }
    3319
    3320     private void adjustSizes(long target, Resizable2 r, boolean limitToRange) {
    3321         long totalLowerBound = 0;
    3322         long totalUpperBound = 0;
    3323         for(int i = 0; i < r.getElementCount(); i++) {
    3324             totalLowerBound += r.getLowerBoundAt(i);
    3325             totalUpperBound += r.getUpperBoundAt(i);
    3326         }
    3327
    3328         if (limitToRange) {
    3329             target = Math.min(Math.max(totalLowerBound, target), totalUpperBound);
    3330         }
    3331
    3332         for(int i = 0; i < r.getElementCount(); i++) {
    3333             int lowerBound = r.getLowerBoundAt(i);
    3334             int upperBound = r.getUpperBoundAt(i);
    3335             // Check for zero. This happens when the distribution of the delta
    3336             // finishes early due to a series of "fixed" entries at the end.
    3337             // In this case, lowerBound == upperBound, for all subsequent terms.
    3338             int newSize;
    3339             if (totalLowerBound == totalUpperBound) {
    3340                 newSize = lowerBound;
    3341             }
    3342             else {
    3343                 double f = (double)(target - totalLowerBound)/(totalUpperBound - totalLowerBound);
    3344                 newSize = (int)Math.round(lowerBound+f*(upperBound - lowerBound));
    3345                 // We'd need to round manually in an all integer version.
    3346                 // size[i] = (int)(((totalUpperBound - target) * lowerBound +
    3347                 //     (target - totalLowerBound) * upperBound)/(totalUpperBound-totalLowerBound));
    3348             }
    3349             r.setSizeAt(newSize, i);
    3350             target -= newSize;
    3351             totalLowerBound -= lowerBound;
    3352             totalUpperBound -= upperBound;
    3353         }
    3354     }
    3355
    3356     /**
    3357      * Overrides <code>JComponent</code>'s <code>getToolTipText</code>
    3358      * method in order to allow the renderer's tips to be used
    3359      * if it has text set.
    3360      * <p>
    3361      * <b>Note:</b> For <code>JTable</code> to properly display
    3362      * tooltips of its renderers
    3363      * <code>JTable</code> must be a registered component with the
    3364      * <code>ToolTipManager</code>.
    3365      * This is done automatically in <code>initializeLocalVars</code>,
    3366      * but if at a later point <code>JTable</code> is told
    3367      * <code>setToolTipText(null)</code> it will unregister the table
    3368      * component, and no tips from renderers will display anymore.
    3369      *
    3370      * @see JComponent#getToolTipText
    3371      */
    3372     public String getToolTipText(MouseEvent event) {
    3373         String tip = null;
    3374         Point p = event.getPoint();
    3375
    3376         // Locate the renderer under the event location
    3377         int hitColumnIndex = columnAtPoint(p);
    3378         int hitRowIndex = rowAtPoint(p);
    3379
    3380         if ((hitColumnIndex != -1) && (hitRowIndex != -1)) {
    3381             TableCellRenderer renderer = getCellRenderer(hitRowIndex, hitColumnIndex);
    3382             Component component = prepareRenderer(renderer, hitRowIndex, hitColumnIndex);
    3383
    3384             // Now have to see if the component is a JComponent before
    3385             // getting the tip
    3386             if (component instanceof JComponent) {
    3387                 // Convert the event to the renderer's coordinate system
    3388                 Rectangle cellRect = getCellRect(hitRowIndex, hitColumnIndex, false);
    3389                 p.translate(-cellRect.x, -cellRect.y);
    3390                 @SuppressWarnings("deprecation")
    3391                 final int modifiers = event.getModifiers();
    3392                 MouseEvent newEvent = new MouseEvent(component, event.getID(),
    3393                                           event.getWhen(), modifiers,
    3394                                           p.x, p.y,
    3395                                           event.getXOnScreen(),
    3396                                           event.getYOnScreen(),
    3397                                           event.getClickCount(),
    3398                                           event.isPopupTrigger(),
    3399                                           MouseEvent.NOBUTTON);
    3400                 MouseEventAccessor meAccessor = AWTAccessor.getMouseEventAccessor();
    3401                 meAccessor.setCausedByTouchEvent(newEvent,
    3402                     meAccessor.isCausedByTouchEvent(event));
    3403
    3404                 tip = ((JComponent)component).getToolTipText(newEvent);
    3405             }
    3406         }
    3407
    3408         // No tip from the renderer get our own tip
    3409         if (tip == null)
    3410             tip = getToolTipText();
    3411
    3412         return tip;
    3413     }
    3414
    3415 //
    3416 // Editing Support
    3417 //
    3418
    3419     /**
    3420      * Sets whether editors in this JTable get the keyboard focus
    3421      * when an editor is activated as a result of the JTable
    3422      * forwarding keyboard events for a cell.
    3423      * By default, this property is false, and the JTable
    3424      * retains the focus unless the cell is clicked.
    3425      *
    3426      * @param surrendersFocusOnKeystroke true if the editor should get the focus
    3427      *          when keystrokes cause the editor to be
    3428      *          activated
    3429      *
    3430      *
    3431      * @see #getSurrendersFocusOnKeystroke
    3432      * @since 1.4
    3433      */
    3434     public void setSurrendersFocusOnKeystroke(boolean surrendersFocusOnKeystroke) {
    3435         this.surrendersFocusOnKeystroke = surrendersFocusOnKeystroke;
    3436     }
    3437
    3438     /**
    3439      * Returns true if the editor should get the focus
    3440      * when keystrokes cause the editor to be activated
    3441      *
    3442      * @return  true if the editor should get the focus
    3443      *          when keystrokes cause the editor to be
    3444      *          activated
    3445      *
    3446      * @see #setSurrendersFocusOnKeystroke
    3447      * @since 1.4
    3448      */
    3449     public boolean getSurrendersFocusOnKeystroke() {
    3450         return surrendersFocusOnKeystroke;
    3451     }
    3452
    3453     /**
    3454      * Programmatically starts editing the cell at <code>row</code> and
    3455      * <code>column</code>, if those indices are in the valid range, and
    3456      * the cell at those indices is editable.
    3457      * Note that this is a convenience method for
    3458      * <code>editCellAt(int, int, null)</code>.
    3459      *
    3460      * @param   row                             the row to be edited
    3461      * @param   column                          the column to be edited
    3462      * @return  false if for any reason the cell cannot be edited,
    3463      *                or if the indices are invalid
    3464      */
    3465     public boolean editCellAt(int row, int column) {
    3466         return editCellAt(row, column, null);
    3467     }
    3468
    3469     /**
    3470      * Programmatically starts editing the cell at <code>row</code> and
    3471      * <code>column</code>, if those indices are in the valid range, and
    3472      * the cell at those indices is editable.
    3473      * To prevent the <code>JTable</code> from
    3474      * editing a particular table, column or cell value, return false from
    3475      * the <code>isCellEditable</code> method in the <code>TableModel</code>
    3476      * interface.
    3477      *
    3478      * @param   row     the row to be edited
    3479      * @param   column  the column to be edited
    3480      * @param   e       event to pass into <code>shouldSelectCell</code>;
    3481      *                  note that as of Java 2 platform v1.2, the call to
    3482      *                  <code>shouldSelectCell</code> is no longer made
    3483      * @return  false if for any reason the cell cannot be edited,
    3484      *                or if the indices are invalid
    3485      */
    3486     public boolean editCellAt(int row, int column, EventObject e){
    3487         if (cellEditor != null && !cellEditor.stopCellEditing()) {
    3488             return false;
    3489         }
    3490
    3491         if (row < 0 || row >= getRowCount() ||
    3492             column < 0 || column >= getColumnCount()) {
    3493             return false;
    3494         }
    3495
    3496         if (!isCellEditable(row, column))
    3497             return false;
    3498
    3499         if (editorRemover == null) {
    3500             KeyboardFocusManager fm =
    3501                 KeyboardFocusManager.getCurrentKeyboardFocusManager();
    3502             editorRemover = new CellEditorRemover(fm);
    3503             fm.addPropertyChangeListener("permanentFocusOwner", editorRemover);
    3504         }
    3505
    3506         TableCellEditor editor = getCellEditor(row, column);
    3507         if (editor != null && editor.isCellEditable(e)) {
    3508             editorComp = prepareEditor(editor, row, column);
    3509             if (editorComp == null) {
    3510                 removeEditor();
    3511                 return false;
    3512             }
    3513             editorComp.setBounds(getCellRect(row, column, false));
    3514             add(editorComp);
    3515             editorComp.validate();
    3516             editorComp.repaint();
    3517
    3518             setCellEditor(editor);
    3519             setEditingRow(row);
    3520             setEditingColumn(column);
    3521             editor.addCellEditorListener(this);
    3522
    3523             return true;
    3524         }
    3525         return false;
    3526     }
    3527
    3528     /**
    3529      * Returns true if a cell is being edited.
    3530      *
    3531      * @return  true if the table is editing a cell
    3532      * @see     #editingColumn
    3533      * @see     #editingRow
    3534      */
    3535     @BeanProperty(bound = false)
    3536     public boolean isEditing() {
    3537         return cellEditor != null;
    3538     }
    3539
    3540     /**
    3541      * Returns the component that is handling the editing session.
    3542      * If nothing is being edited, returns null.
    3543      *
    3544      * @return  Component handling editing session
    3545      */
    3546     @BeanProperty(bound = false)
    3547     public Component getEditorComponent() {
    3548         return editorComp;
    3549     }
    3550
    3551     /**
    3552      * Returns the index of the column that contains the cell currently
    3553      * being edited.  If nothing is being edited, returns -1.
    3554      *
    3555      * @return  the index of the column that contains the cell currently
    3556      *          being edited; returns -1 if nothing being edited
    3557      * @see #editingRow
    3558      */
    3559     public int getEditingColumn() {
    3560         return editingColumn;
    3561     }
    3562
    3563     /**
    3564      * Returns the index of the row that contains the cell currently
    3565      * being edited.  If nothing is being edited, returns -1.
    3566      *
    3567      * @return  the index of the row that contains the cell currently
    3568      *          being edited; returns -1 if nothing being edited
    3569      * @see #editingColumn
    3570      */
    3571     public int getEditingRow() {
    3572         return editingRow;
    3573     }
    3574
    3575 //
    3576 // Managing TableUI
    3577 //
    3578
    3579     /**
    3580      * Returns the L&amp;F object that renders this component.
    3581      *
    3582      * @return the <code>TableUI</code> object that renders this component
    3583      */
    3584     public TableUI getUI() {
    3585         return (TableUI)ui;
    3586     }
    3587
    3588     /**
    3589      * Sets the L&amp;F object that renders this component and repaints.
    3590      *
    3591      * @param ui  the TableUI L&amp;F object
    3592      * @see UIDefaults#getUI
    3593      */
    3594     @BeanProperty(hidden = true, visualUpdate = true, description
    3595             = "The UI object that implements the Component's LookAndFeel.")
    3596     public void setUI(TableUI ui) {
    3597         if (this.ui != ui) {
    3598             super.setUI(ui);
    3599             repaint();
    3600         }
    3601     }
    3602
    3603     /**
    3604      * Notification from the <code>UIManager</code> that the L&amp;F has changed.
    3605      * Replaces the current UI object with the latest version from the
    3606      * <code>UIManager</code>.
    3607      *
    3608      * @see JComponent#updateUI
    3609      */
    3610     public void updateUI() {
    3611         if (updateInProgress) {
    3612             return;
    3613         }
    3614
    3615         updateInProgress = true;
    3616
    3617         try {
    3618             // Update the UIs of the cell renderers, cell editors and header renderers.
    3619             TableColumnModel cm = getColumnModel();
    3620             for(int column = 0; column < cm.getColumnCount(); column++) {
    3621                 TableColumn aColumn = cm.getColumn(column);
    3622                 SwingUtilities.updateRendererOrEditorUI(aColumn.getCellRenderer());
    3623                 SwingUtilities.updateRendererOrEditorUI(aColumn.getCellEditor());
    3624                 SwingUtilities.updateRendererOrEditorUI(aColumn.getHeaderRenderer());
    3625             }
    3626
    3627             // Update the UIs of all the default renderers.
    3628             Enumeration<?> defaultRenderers = defaultRenderersByColumnClass.elements();
    3629             while (defaultRenderers.hasMoreElements()) {
    3630                 SwingUtilities.updateRendererOrEditorUI(defaultRenderers.nextElement());
    3631             }
    3632
    3633             // Update the UIs of all the default editors.
    3634             Enumeration<?> defaultEditors = defaultEditorsByColumnClass.elements();
    3635             while (defaultEditors.hasMoreElements()) {
    3636                 SwingUtilities.updateRendererOrEditorUI(defaultEditors.nextElement());
    3637             }
    3638
    3639             // Update the UI of the table header
    3640             if (tableHeader != null && tableHeader.getParent() == null) {
    3641                 tableHeader.updateUI();
    3642             }
    3643
    3644             // Update UI applied to parent ScrollPane
    3645             configureEnclosingScrollPaneUI();
    3646
    3647             setUI((TableUI)UIManager.getUI(this));
    3648         } finally {
    3649             updateInProgress = false;
    3650         }
    3651     }
    3652
    3653     /**
    3654      * Returns the suffix used to construct the name of the L&amp;F class used to
    3655      * render this component.
    3656      *
    3657      * @return the string "TableUI"
    3658      * @see JComponent#getUIClassID
    3659      * @see UIDefaults#getUI
    3660      */
    3661     @BeanProperty(bound = false)
    3662     public String getUIClassID() {
    3663         return uiClassID;
    3664     }
    3665
    3666
    3667 //
    3668 // Managing models
    3669 //
    3670
    3671     /**
    3672      * Sets the data model for this table to {@code dataModel} and registers
    3673      * with it for listener notifications from the new data model.
    3674      *
    3675      * @param  dataModel the new data source for this table
    3676      * @throws IllegalArgumentException if {@code dataModel} is {@code null}
    3677      * @see #getModel
    3678      */
    3679     @BeanProperty(description
    3680             = "The model that is the source of the data for this view.")
    3681     public void setModel(final TableModel dataModel) {
    3682         if (dataModel == null) {
    3683             throw new IllegalArgumentException("Cannot set a null TableModel");
    3684         }
    3685         if (this.dataModel != dataModel) {
    3686             TableModel old = this.dataModel;
    3687             if (old != null) {
    3688                 old.removeTableModelListener(this);
    3689             }
    3690             this.dataModel = dataModel;
    3691             dataModel.addTableModelListener(this);
    3692
    3693             tableChanged(new TableModelEvent(dataModel, TableModelEvent.HEADER_ROW));
    3694
    3695             firePropertyChange("model", old, dataModel);
    3696
    3697             if (getAutoCreateRowSorter()) {
    3698                 setRowSorter(new TableRowSorter<TableModel>(dataModel));
    3699             }
    3700         }
    3701     }
    3702
    3703     /**
    3704      * Returns the {@code TableModel} that provides the data displayed by this
    3705      * {@code JTable}.
    3706      *
    3707      * @return the {@code TableModel} that provides the data displayed by this
    3708      *         {@code JTable}
    3709      * @see #setModel
    3710      */
    3711     public TableModel getModel() {
    3712         return dataModel;
    3713     }
    3714
    3715     /**
    3716      * Sets the column model for this table to {@code columnModel} and registers
    3717      * for listener notifications from the new column model. Also sets the
    3718      * column model of the {@code JTableHeader} to {@code columnModel}.
    3719      *
    3720      * @param  columnModel the new data source for this table
    3721      * @throws IllegalArgumentException if {@code columnModel} is {@code null}
    3722      * @see #getColumnModel
    3723      */
    3724     @BeanProperty(description
    3725             = "The object governing the way columns appear in the view.")
    3726     public void setColumnModel(final TableColumnModel columnModel) {
    3727         if (columnModel == null) {
    3728             throw new IllegalArgumentException("Cannot set a null ColumnModel");
    3729         }
    3730         TableColumnModel old = this.columnModel;
    3731         if (columnModel != old) {
    3732             if (old != null) {
    3733                 old.removeColumnModelListener(this);
    3734             }
    3735             this.columnModel = columnModel;
    3736             columnModel.addColumnModelListener(this);
    3737
    3738             // Set the column model of the header as well.
    3739             if (tableHeader != null) {
    3740                 tableHeader.setColumnModel(columnModel);
    3741             }
    3742
    3743             firePropertyChange("columnModel", old, columnModel);
    3744             resizeAndRepaint();
    3745         }
    3746     }
    3747
    3748     /**
    3749      * Returns the {@code TableColumnModel} that contains all column information
    3750      * of this table.
    3751      *
    3752      * @return the object that provides the column state of the table
    3753      * @see #setColumnModel
    3754      */
    3755     public TableColumnModel getColumnModel() {
    3756         return columnModel;
    3757     }
    3758
    3759     /**
    3760      * Sets the row selection model for this table to {@code selectionModel}
    3761      * and registers for listener notifications from the new selection model.
    3762      *
    3763      * @param  selectionModel the new selection model
    3764      * @throws IllegalArgumentException if {@code selectionModel} is
    3765      *         {@code null}
    3766      * @see #getSelectionModel
    3767      */
    3768     @BeanProperty(description
    3769             = "The selection model for rows.")
    3770     public void setSelectionModel(final ListSelectionModel selectionModel) {
    3771         if (selectionModel == null) {
    3772             throw new IllegalArgumentException("Cannot set a null SelectionModel");
    3773         }
    3774
    3775         ListSelectionModel oldModel = this.selectionModel;
    3776
    3777         if (selectionModel != oldModel) {
    3778             if (oldModel != null) {
    3779                 oldModel.removeListSelectionListener(this);
    3780             }
    3781
    3782             this.selectionModel = selectionModel;
    3783             selectionModel.addListSelectionListener(this);
    3784
    3785             firePropertyChange("selectionModel", oldModel, selectionModel);
    3786             repaint();
    3787         }
    3788     }
    3789
    3790     /**
    3791      * Returns the {@code ListSelectionModel} that is used to maintain row
    3792      * selection state.
    3793      *
    3794      * @return the object that provides row selection state, {@code null} if row
    3795      *         selection is not allowed
    3796      * @see #setSelectionModel
    3797      */
    3798     public ListSelectionModel getSelectionModel() {
    3799         return selectionModel;
    3800     }
    3801
    3802 //
    3803 // RowSorterListener
    3804 //
    3805
    3806     /**
    3807      * <code>RowSorterListener</code> notification that the
    3808      * <code>RowSorter</code> has changed in some way.
    3809      *
    3810      * @param e the <code>RowSorterEvent</code> describing the change
    3811      * @throws NullPointerException if <code>e</code> is <code>null</code>
    3812      * @since 1.6
    3813      */
    3814     public void sorterChanged(RowSorterEvent e) {
    3815         if (e.getType() == RowSorterEvent.Type.SORT_ORDER_CHANGED) {
    3816             JTableHeader header = getTableHeader();
    3817             if (header != null) {
    3818                 header.repaint();
    3819             }
    3820         }
    3821         else if (e.getType() == RowSorterEvent.Type.SORTED) {
    3822             sorterChanged = true;
    3823             if (!ignoreSortChange) {
    3824                 sortedTableChanged(e, null);
    3825             }
    3826         }
    3827     }
    3828
    3829
    3830     /**
    3831      * SortManager provides support for managing the selection and variable
    3832      * row heights when sorting is enabled. This information is encapsulated
    3833      * into a class to avoid bulking up JTable.
    3834      */
    3835     private final class SortManager {
    3836         RowSorter<? extends TableModel> sorter;
    3837
    3838         // Selection, in terms of the model. This is lazily created
    3839         // as needed.
    3840         private ListSelectionModel modelSelection;
    3841         private int modelLeadIndex;
    3842         // Set to true while in the process of changing the selection.
    3843         // If this is true the selection change is ignored.
    3844         private boolean syncingSelection;
    3845         // Temporary cache of selection, in terms of model. This is only used
    3846         // if we don't need the full weight of modelSelection.
    3847         private int[] lastModelSelection;
    3848
    3849         // Heights of the rows in terms of the model.
    3850         private SizeSequence modelRowSizes;
    3851
    3852
    3853         SortManager(RowSorter<? extends TableModel> sorter) {
    3854             this.sorter = sorter;
    3855             sorter.addRowSorterListener(JTable.this);
    3856         }
    3857
    3858         /**
    3859          * Disposes any resources used by this SortManager.
    3860          */
    3861         public void dispose() {
    3862             if (sorter != null) {
    3863                 sorter.removeRowSorterListener(JTable.this);
    3864             }
    3865         }
    3866
    3867         /**
    3868          * Sets the height for a row at a specified index.
    3869          */
    3870         public void setViewRowHeight(int viewIndex, int rowHeight) {
    3871             if (modelRowSizes == null) {
    3872                 modelRowSizes = new SizeSequence(getModel().getRowCount(),
    3873                                                  getRowHeight());
    3874             }
    3875             modelRowSizes.setSize(convertRowIndexToModel(viewIndex),rowHeight);
    3876         }
    3877
    3878         /**
    3879          * Invoked when the underlying model has completely changed.
    3880          */
    3881         public void allChanged() {
    3882             modelLeadIndex = -1;
    3883             modelSelection = null;
    3884             modelRowSizes = null;
    3885         }
    3886
    3887         /**
    3888          * Invoked when the selection, on the view, has changed.
    3889          */
    3890         public void viewSelectionChanged(ListSelectionEvent e) {
    3891             if (!syncingSelection && modelSelection != null) {
    3892                 modelSelection = null;
    3893             }
    3894         }
    3895
    3896         /**
    3897          * Invoked when either the table model has changed, or the RowSorter
    3898          * has changed. This is invoked prior to notifying the sorter of the
    3899          * change.
    3900          */
    3901         public void prepareForChange(RowSorterEvent sortEvent,
    3902                                      ModelChange change) {
    3903             if (getUpdateSelectionOnSort()) {
    3904                 cacheSelection(sortEvent, change);
    3905             }
    3906         }
    3907
    3908         /**
    3909          * Updates the internal cache of the selection based on the change.
    3910          */
    3911         private void cacheSelection(RowSorterEvent sortEvent,
    3912                                     ModelChange change) {
    3913             if (sortEvent != null) {
    3914                 // sort order changed. If modelSelection is null and filtering
    3915                 // is enabled we need to cache the selection in terms of the
    3916                 // underlying model, this will allow us to correctly restore
    3917                 // the selection even if rows are filtered out.
    3918                 if (modelSelection == null &&
    3919                         sorter.getViewRowCount() != getModel().getRowCount()) {
    3920                     modelSelection = new DefaultListSelectionModel();
    3921                     ListSelectionModel viewSelection = getSelectionModel();
    3922                     int min = viewSelection.getMinSelectionIndex();
    3923                     int max = viewSelection.getMaxSelectionIndex();
    3924                     int modelIndex;
    3925                     for (int viewIndex = min; viewIndex <= max; viewIndex++) {
    3926                         if (viewSelection.isSelectedIndex(viewIndex)) {
    3927                             modelIndex = convertRowIndexToModel(
    3928                                     sortEvent, viewIndex);
    3929                             if (modelIndex != -1) {
    3930                                 modelSelection.addSelectionInterval(
    3931                                     modelIndex, modelIndex);
    3932                             }
    3933                         }
    3934                     }
    3935                     modelIndex = convertRowIndexToModel(sortEvent,
    3936                             viewSelection.getLeadSelectionIndex());
    3937                     SwingUtilities2.setLeadAnchorWithoutSelection(
    3938                             modelSelection, modelIndex, modelIndex);
    3939                 } else if (modelSelection == null) {
    3940                     // Sorting changed, haven't cached selection in terms
    3941                     // of model and no filtering. Temporarily cache selection.
    3942                     cacheModelSelection(sortEvent);
    3943                 }
    3944             } else if (change.allRowsChanged) {
    3945                 // All the rows have changed, chuck any cached selection.
    3946                 modelSelection = null;
    3947             } else if (modelSelection != null) {
    3948                 // Table changed, reflect changes in cached selection model.
    3949                 switch(change.type) {
    3950                 case TableModelEvent.DELETE:
    3951                     modelSelection.removeIndexInterval(change.startModelIndex,
    3952                                                        change.endModelIndex);
    3953                     break;
    3954                 case TableModelEvent.INSERT:
    3955                     modelSelection.insertIndexInterval(change.startModelIndex,
    3956                                                        change.length,
    3957                                                        true);
    3958                     break;
    3959                 default:
    3960                     break;
    3961                 }
    3962             } else {
    3963                 // table changed, but haven't cached rows, temporarily
    3964                 // cache them.
    3965                 cacheModelSelection(null);
    3966             }
    3967         }
    3968
    3969         private void cacheModelSelection(RowSorterEvent sortEvent) {
    3970             lastModelSelection = convertSelectionToModel(sortEvent);
    3971             modelLeadIndex = convertRowIndexToModel(sortEvent,
    3972                         selectionModel.getLeadSelectionIndex());
    3973         }
    3974
    3975         /**
    3976          * Inovked when either the table has changed or the sorter has changed
    3977          * and after the sorter has been notified. If necessary this will
    3978          * reapply the selection and variable row heights.
    3979          */
    3980         public void processChange(RowSorterEvent sortEvent,
    3981                                   ModelChange change,
    3982                                   boolean sorterChanged) {
    3983             if (change != null) {
    3984                 if (change.allRowsChanged) {
    3985                     modelRowSizes = null;
    3986                     rowModel = null;
    3987                 } else if (modelRowSizes != null) {
    3988                     if (change.type == TableModelEvent.INSERT) {
    3989                         modelRowSizes.insertEntries(change.startModelIndex,
    3990                                                     change.endModelIndex -
    3991                                                     change.startModelIndex + 1,
    3992                                                     getRowHeight());
    3993                     } else if (change.type == TableModelEvent.DELETE) {
    3994                         modelRowSizes.removeEntries(change.startModelIndex,
    3995                                                     change.endModelIndex -
    3996                                                     change.startModelIndex +1 );
    3997                     }
    3998                 }
    3999             }
    4000             if (sorterChanged) {
    4001                 setViewRowHeightsFromModel();
    4002                 restoreSelection(change);
    4003             }
    4004         }
    4005
    4006         /**
    4007          * Resets the variable row heights in terms of the view from
    4008          * that of the variable row heights in terms of the model.
    4009          */
    4010         private void setViewRowHeightsFromModel() {
    4011             if (modelRowSizes != null) {
    4012                 rowModel.setSizes(getRowCount(), getRowHeight());
    4013                 for (int viewIndex = getRowCount() - 1; viewIndex >= 0;
    4014                          viewIndex--) {
    4015                     int modelIndex = convertRowIndexToModel(viewIndex);
    4016                     rowModel.setSize(viewIndex,
    4017                                      modelRowSizes.getSize(modelIndex));
    4018                 }
    4019             }
    4020         }
    4021
    4022         /**
    4023          * Restores the selection from that in terms of the model.
    4024          */
    4025         private void restoreSelection(ModelChange change) {
    4026             syncingSelection = true;
    4027             if (lastModelSelection != null) {
    4028                 restoreSortingSelection(lastModelSelection,
    4029                                         modelLeadIndex, change);
    4030                 lastModelSelection = null;
    4031             } else if (modelSelection != null) {
    4032                 ListSelectionModel viewSelection = getSelectionModel();
    4033                 viewSelection.setValueIsAdjusting(true);
    4034                 viewSelection.clearSelection();
    4035                 int min = modelSelection.getMinSelectionIndex();
    4036                 int max = modelSelection.getMaxSelectionIndex();
    4037                 int viewIndex;
    4038                 for (int modelIndex = min; modelIndex <= max; modelIndex++) {
    4039                     if (modelSelection.isSelectedIndex(modelIndex)) {
    4040                         viewIndex = convertRowIndexToView(modelIndex);
    4041                         if (viewIndex != -1) {
    4042                             viewSelection.addSelectionInterval(viewIndex,
    4043                                                                viewIndex);
    4044                         }
    4045                     }
    4046                 }
    4047                 // Restore the lead
    4048                 int viewLeadIndex = modelSelection.getLeadSelectionIndex();
    4049                 if (viewLeadIndex != -1 && !modelSelection.isSelectionEmpty()) {
    4050                     viewLeadIndex = convertRowIndexToView(viewLeadIndex);
    4051                 }
    4052                 SwingUtilities2.setLeadAnchorWithoutSelection(
    4053                         viewSelection, viewLeadIndex, viewLeadIndex);
    4054                 viewSelection.setValueIsAdjusting(false);
    4055             }
    4056             syncingSelection = false;
    4057         }
    4058     }
    4059
    4060
    4061     /**
    4062      * ModelChange is used when sorting to restore state, it corresponds
    4063      * to data from a TableModelEvent.  The values are precalculated as
    4064      * they are used extensively.
    4065      */
    4066     private final class ModelChange {
    4067         // Starting index of the change, in terms of the model
    4068         int startModelIndex;
    4069
    4070         // Ending index of the change, in terms of the model
    4071         int endModelIndex;
    4072
    4073         // Type of change
    4074         int type;
    4075
    4076         // Number of rows in the model
    4077         int modelRowCount;
    4078
    4079         // The event that triggered this.
    4080         TableModelEvent event;
    4081
    4082         // Length of the change (end - start + 1)
    4083         int length;
    4084
    4085         // True if the event indicates all the contents have changed
    4086         boolean allRowsChanged;
    4087
    4088         ModelChange(TableModelEvent e) {
    4089             startModelIndex = Math.max(0, e.getFirstRow());
    4090             endModelIndex = e.getLastRow();
    4091             modelRowCount = getModel().getRowCount();
    4092             if (endModelIndex < 0) {
    4093                 endModelIndex = Math.max(0, modelRowCount - 1);
    4094             }
    4095             length = endModelIndex - startModelIndex + 1;
    4096             type = e.getType();
    4097             event = e;
    4098             allRowsChanged = (e.getLastRow() == Integer.MAX_VALUE);
    4099         }
    4100     }
    4101
    4102     /**
    4103      * Invoked when <code>sorterChanged</code> is invoked, or
    4104      * when <code>tableChanged</code> is invoked and sorting is enabled.
    4105      */
    4106     private void sortedTableChanged(RowSorterEvent sortedEvent,
    4107                                     TableModelEvent e) {
    4108         int editingModelIndex = -1;
    4109         ModelChange change = (e != null) ? new ModelChange(e) : null;
    4110
    4111         if ((change == null || !change.allRowsChanged) &&
    4112                 this.editingRow != -1) {
    4113             editingModelIndex = convertRowIndexToModel(sortedEvent,
    4114                                                        this.editingRow);
    4115         }
    4116
    4117         sortManager.prepareForChange(sortedEvent, change);
    4118
    4119         if (e != null) {
    4120             if (change.type == TableModelEvent.UPDATE) {
    4121                 repaintSortedRows(change);
    4122             }
    4123             notifySorter(change);
    4124             if (change.type != TableModelEvent.UPDATE) {
    4125                 // If the Sorter is unsorted we will not have received
    4126                 // notification, force treating insert/delete as a change.
    4127                 sorterChanged = true;
    4128             }
    4129         }
    4130         else {
    4131             sorterChanged = true;
    4132         }
    4133
    4134         sortManager.processChange(sortedEvent, change, sorterChanged);
    4135
    4136         if (sorterChanged) {
    4137             // Update the editing row
    4138             if (this.editingRow != -1) {
    4139                 int newIndex = (editingModelIndex == -1) ? -1 :
    4140                         convertRowIndexToView(editingModelIndex,change);
    4141                 restoreSortingEditingRow(newIndex);
    4142             }
    4143
    4144             // And handle the appropriate repainting.
    4145             if (e == null || change.type != TableModelEvent.UPDATE) {
    4146                 resizeAndRepaint();
    4147             }
    4148         }
    4149
    4150         // Check if lead/anchor need to be reset.
    4151         if (change != null && change.allRowsChanged) {
    4152             clearSelectionAndLeadAnchor();
    4153             resizeAndRepaint();
    4154         }
    4155     }
    4156
    4157     /**
    4158      * Repaints the sort of sorted rows in response to a TableModelEvent.
    4159      */
    4160     private void repaintSortedRows(ModelChange change) {
    4161         if (change.startModelIndex > change.endModelIndex ||
    4162                 change.startModelIndex + 10 < change.endModelIndex) {
    4163             // Too much has changed, punt
    4164             repaint();
    4165             return;
    4166         }
    4167         int eventColumn = change.event.getColumn();
    4168         int columnViewIndex = eventColumn;
    4169         if (columnViewIndex == TableModelEvent.ALL_COLUMNS) {
    4170             columnViewIndex = 0;
    4171         }
    4172         else {
    4173             columnViewIndex = convertColumnIndexToView(columnViewIndex);
    4174             if (columnViewIndex == -1) {
    4175                 return;
    4176             }
    4177         }
    4178         int modelIndex = change.startModelIndex;
    4179         while (modelIndex <= change.endModelIndex) {
    4180             int viewIndex = convertRowIndexToView(modelIndex++);
    4181             if (viewIndex != -1) {
    4182                 Rectangle dirty = getCellRect(viewIndex, columnViewIndex,
    4183                                               false);
    4184                 int x = dirty.x;
    4185                 int w = dirty.width;
    4186                 if (eventColumn == TableModelEvent.ALL_COLUMNS) {
    4187                     x = 0;
    4188                     w = getWidth();
    4189                 }
    4190                 repaint(x, dirty.y, w, dirty.height);
    4191             }
    4192         }
    4193     }
    4194
    4195     /**
    4196      * Restores the selection after a model event/sort order changes.
    4197      * All coordinates are in terms of the model.
    4198      */
    4199     private void restoreSortingSelection(int[] selection, int lead,
    4200             ModelChange change) {
    4201         // Convert the selection from model to view
    4202         for (int i = selection.length - 1; i >= 0; i--) {
    4203             selection[i] = convertRowIndexToView(selection[i], change);
    4204         }
    4205         lead = convertRowIndexToView(lead, change);
    4206
    4207         // Check for the common case of no change in selection for 1 row
    4208         if (selection.length == 0 ||
    4209             (selection.length == 1 && selection[0] == getSelectedRow())) {
    4210             return;
    4211         }
    4212
    4213         // And apply the new selection
    4214         selectionModel.setValueIsAdjusting(true);
    4215         selectionModel.clearSelection();
    4216         for (int i = selection.length - 1; i >= 0; i--) {
    4217             if (selection[i] != -1) {
    4218                 selectionModel.addSelectionInterval(selection[i],
    4219                                                     selection[i]);
    4220             }
    4221         }
    4222         SwingUtilities2.setLeadAnchorWithoutSelection(
    4223                 selectionModel, lead, lead);
    4224         selectionModel.setValueIsAdjusting(false);
    4225     }
    4226
    4227     /**
    4228      * Restores the editing row after a model event/sort order change.
    4229      *
    4230      * @param editingRow new index of the editingRow, in terms of the view
    4231      */
    4232     private void restoreSortingEditingRow(int editingRow) {
    4233         if (editingRow == -1) {
    4234             // Editing row no longer being shown, cancel editing
    4235             TableCellEditor editor = getCellEditor();
    4236             if (editor != null) {
    4237                 // First try and cancel
    4238                 editor.cancelCellEditing();
    4239                 if (getCellEditor() != null) {
    4240                     // CellEditor didn't cede control, forcefully
    4241                     // remove it
    4242                     removeEditor();
    4243                 }
    4244             }
    4245         }
    4246         else {
    4247             // Repositioning handled in BasicTableUI
    4248             this.editingRow = editingRow;
    4249             repaint();
    4250         }
    4251     }
    4252
    4253     /**
    4254      * Notifies the sorter of a change in the underlying model.
    4255      */
    4256     private void notifySorter(ModelChange change) {
    4257         try {
    4258             ignoreSortChange = true;
    4259             sorterChanged = false;
    4260             switch(change.type) {
    4261             case TableModelEvent.UPDATE:
    4262                 if (change.event.getLastRow() == Integer.MAX_VALUE) {
    4263                     sortManager.sorter.allRowsChanged();
    4264                 } else if (change.event.getColumn() ==
    4265                            TableModelEvent.ALL_COLUMNS) {
    4266                     sortManager.sorter.rowsUpdated(change.startModelIndex,
    4267                                        change.endModelIndex);
    4268                 } else {
    4269                     sortManager.sorter.rowsUpdated(change.startModelIndex,
    4270                                        change.endModelIndex,
    4271                                        change.event.getColumn());
    4272                 }
    4273                 break;
    4274             case TableModelEvent.INSERT:
    4275                 sortManager.sorter.rowsInserted(change.startModelIndex,
    4276                                     change.endModelIndex);
    4277                 break;
    4278             case TableModelEvent.DELETE:
    4279                 sortManager.sorter.rowsDeleted(change.startModelIndex,
    4280                                    change.endModelIndex);
    4281                 break;
    4282             }
    4283         } finally {
    4284             ignoreSortChange = false;
    4285         }
    4286     }
    4287
    4288     /**
    4289      * Converts a model index to view index.  This is called when the
    4290      * sorter or model changes and sorting is enabled.
    4291      *
    4292      * @param change describes the TableModelEvent that initiated the change;
    4293      *        will be null if called as the result of a sort
    4294      */
    4295     private int convertRowIndexToView(int modelIndex, ModelChange change) {
    4296         if (modelIndex < 0) {
    4297             return -1;
    4298         }
    4299         if (change != null && modelIndex >= change.startModelIndex) {
    4300             if (change.type == TableModelEvent.INSERT) {
    4301                 if (modelIndex + change.length >= change.modelRowCount) {
    4302                     return -1;
    4303                 }
    4304                 return sortManager.sorter.convertRowIndexToView(
    4305                         modelIndex + change.length);
    4306             }
    4307             else if (change.type == TableModelEvent.DELETE) {
    4308                 if (modelIndex <= change.endModelIndex) {
    4309                     // deleted
    4310                     return -1;
    4311                 }
    4312                 else {
    4313                     if (modelIndex - change.length >= change.modelRowCount) {
    4314                         return -1;
    4315                     }
    4316                     return sortManager.sorter.convertRowIndexToView(
    4317                             modelIndex - change.length);
    4318                 }
    4319             }
    4320             // else, updated
    4321         }
    4322         if (modelIndex >= getModel().getRowCount()) {
    4323             return -1;
    4324         }
    4325         return sortManager.sorter.convertRowIndexToView(modelIndex);
    4326     }
    4327
    4328     /**
    4329      * Converts the selection to model coordinates.  This is used when
    4330      * the model changes or the sorter changes.
    4331      */
    4332     private int[] convertSelectionToModel(RowSorterEvent e) {
    4333         int[] selection = getSelectedRows();
    4334         for (int i = selection.length - 1; i >= 0; i--) {
    4335             selection[i] = convertRowIndexToModel(e, selection[i]);
    4336         }
    4337         return selection;
    4338     }
    4339
    4340     private int convertRowIndexToModel(RowSorterEvent e, int viewIndex) {
    4341         if (e != null) {
    4342             if (e.getPreviousRowCount() == 0) {
    4343                 return viewIndex;
    4344             }
    4345             // range checking handled by RowSorterEvent
    4346             return e.convertPreviousRowIndexToModel(viewIndex);
    4347         }
    4348         // Make sure the viewIndex is valid
    4349         if (viewIndex < 0 || viewIndex >= getRowCount()) {
    4350             return -1;
    4351         }
    4352         return convertRowIndexToModel(viewIndex);
    4353     }
    4354
    4355 //
    4356 // Implementing TableModelListener interface
    4357 //
    4358
    4359     /**
    4360      * Invoked when this table's <code>TableModel</code> generates
    4361      * a <code>TableModelEvent</code>.
    4362      * The <code>TableModelEvent</code> should be constructed in the
    4363      * coordinate system of the model; the appropriate mapping to the
    4364      * view coordinate system is performed by this <code>JTable</code>
    4365      * when it receives the event.
    4366      * <p>
    4367      * Application code will not use these methods explicitly, they
    4368      * are used internally by <code>JTable</code>.
    4369      * <p>
    4370      * Note that as of 1.3, this method clears the selection, if any.
    4371      */
    4372     public void tableChanged(TableModelEvent e) {
    4373         if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
    4374             // The whole thing changed
    4375             clearSelectionAndLeadAnchor();
    4376
    4377             rowModel = null;
    4378
    4379             if (sortManager != null) {
    4380                 try {
    4381                     ignoreSortChange = true;
    4382                     sortManager.sorter.modelStructureChanged();
    4383                 } finally {
    4384                     ignoreSortChange = false;
    4385                 }
    4386                 sortManager.allChanged();
    4387             }
    4388
    4389             if (getAutoCreateColumnsFromModel()) {
    4390                 // This will effect invalidation of the JTable and JTableHeader.
    4391                 createDefaultColumnsFromModel();
    4392                 return;
    4393             }
    4394
    4395             resizeAndRepaint();
    4396             return;
    4397         }
    4398
    4399         if (sortManager != null) {
    4400             sortedTableChanged(null, e);
    4401             return;
    4402         }
    4403
    4404         // The totalRowHeight calculated below will be incorrect if
    4405         // there are variable height rows. Repaint the visible region,
    4406         // but don't return as a revalidate may be necessary as well.
    4407         if (rowModel != null) {
    4408             repaint();
    4409         }
    4410
    4411         if (e.getType() == TableModelEvent.INSERT) {
    4412             tableRowsInserted(e);
    4413             return;
    4414         }
    4415
    4416         if (e.getType() == TableModelEvent.DELETE) {
    4417             tableRowsDeleted(e);
    4418             return;
    4419         }
    4420
    4421         int modelColumn = e.getColumn();
    4422         int start = e.getFirstRow();
    4423         int end = e.getLastRow();
    4424
    4425         Rectangle dirtyRegion;
    4426         if (modelColumn == TableModelEvent.ALL_COLUMNS) {
    4427             // 1 or more rows changed
    4428             dirtyRegion = new Rectangle(0, start * getRowHeight(),
    4429                                         getColumnModel().getTotalColumnWidth(), 0);
    4430         }
    4431         else {
    4432             // A cell or column of cells has changed.
    4433             // Unlike the rest of the methods in the JTable, the TableModelEvent
    4434             // uses the coordinate system of the model instead of the view.
    4435             // This is the only place in the JTable where this "reverse mapping"
    4436             // is used.
    4437             int column = convertColumnIndexToView(modelColumn);
    4438             dirtyRegion = getCellRect(start, column, false);
    4439         }
    4440
    4441         // Now adjust the height of the dirty region according to the value of "end".
    4442         // Check for Integer.MAX_VALUE as this will cause an overflow.
    4443         if (end != Integer.MAX_VALUE) {
    4444             dirtyRegion.height = (end-start+1)*getRowHeight();
    4445             repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
    4446         }
    4447         // In fact, if the end is Integer.MAX_VALUE we need to revalidate anyway
    4448         // because the scrollbar may need repainting.
    4449         else {
    4450             clearSelectionAndLeadAnchor();
    4451             resizeAndRepaint();
    4452             rowModel = null;
    4453         }
    4454     }
    4455
    4456     /*
    4457      * Invoked when rows have been inserted into the table.
    4458      * <p>
    4459      * Application code will not use these methods explicitly, they
    4460      * are used internally by JTable.
    4461      *
    4462      * @param e the TableModelEvent encapsulating the insertion
    4463      */
    4464     private void tableRowsInserted(TableModelEvent e) {
    4465         int start = e.getFirstRow();
    4466         int end = e.getLastRow();
    4467         if (start < 0) {
    4468             start = 0;
    4469         }
    4470         if (end < 0) {
    4471             end = getRowCount()-1;
    4472         }
    4473
    4474         // Adjust the selection to account for the new rows.
    4475         int length = end - start + 1;
    4476         selectionModel.insertIndexInterval(start, length, true);
    4477
    4478         // If we have variable height rows, adjust the row model.
    4479         if (rowModel != null) {
    4480             rowModel.insertEntries(start, length, getRowHeight());
    4481         }
    4482         int rh = getRowHeight() ;
    4483         Rectangle drawRect = new Rectangle(0, start * rh,
    4484                                         getColumnModel().getTotalColumnWidth(),
    4485                                            (getRowCount()-start) * rh);
    4486
    4487         revalidate();
    4488         // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
    4489         // repaint still required in the unusual case where there is no ScrollPane
    4490         repaint(drawRect);
    4491     }
    4492
    4493     /*
    4494      * Invoked when rows have been removed from the table.
    4495      * <p>
    4496      * Application code will not use these methods explicitly, they
    4497      * are used internally by JTable.
    4498      *
    4499      * @param e the TableModelEvent encapsulating the deletion
    4500      */
    4501     private void tableRowsDeleted(TableModelEvent e) {
    4502         int start = e.getFirstRow();
    4503         int end = e.getLastRow();
    4504         if (start < 0) {
    4505             start = 0;
    4506         }
    4507         if (end < 0) {
    4508             end = getRowCount()-1;
    4509         }
    4510
    4511         int deletedCount = end - start + 1;
    4512         int previousRowCount = getRowCount() + deletedCount;
    4513         // Adjust the selection to account for the new rows
    4514         selectionModel.removeIndexInterval(start, end);
    4515
    4516         // If we have variable height rows, adjust the row model.
    4517         if (rowModel != null) {
    4518             rowModel.removeEntries(start, deletedCount);
    4519         }
    4520
    4521         int rh = getRowHeight();
    4522         Rectangle drawRect = new Rectangle(0, start * rh,
    4523                                         getColumnModel().getTotalColumnWidth(),
    4524                                         (previousRowCount - start) * rh);
    4525
    4526         revalidate();
    4527         // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
    4528         // repaint still required in the unusual case where there is no ScrollPane
    4529         repaint(drawRect);
    4530     }
    4531
    4532 //
    4533 // Implementing TableColumnModelListener interface
    4534 //
    4535
    4536     /**
    4537      * Invoked when a column is added to the table column model.
    4538      * <p>
    4539      * Application code will not use these methods explicitly, they
    4540      * are used internally by JTable.
    4541      *
    4542      * @see TableColumnModelListener
    4543      */
    4544     public void columnAdded(TableColumnModelEvent e) {
    4545         // If I'm currently editing, then I should stop editing
    4546         if (isEditing()) {
    4547             removeEditor();
    4548         }
    4549         resizeAndRepaint();
    4550     }
    4551
    4552     /**
    4553      * Invoked when a column is removed from the table column model.
    4554      * <p>
    4555      * Application code will not use these methods explicitly, they
    4556      * are used internally by JTable.
    4557      *
    4558      * @see TableColumnModelListener
    4559      */
    4560     public void columnRemoved(TableColumnModelEvent e) {
    4561         // If I'm currently editing, then I should stop editing
    4562         if (isEditing()) {
    4563             removeEditor();
    4564         }
    4565         resizeAndRepaint();
    4566     }
    4567
    4568     /**
    4569      * Invoked when a column is repositioned. If a cell is being
    4570      * edited, then editing is stopped and the cell is redrawn.
    4571      * <p>
    4572      * Application code will not use these methods explicitly, they
    4573      * are used internally by JTable.
    4574      *
    4575      * @param e   the event received
    4576      * @see TableColumnModelListener
    4577      */
    4578     public void columnMoved(TableColumnModelEvent e) {
    4579         if (isEditing() && !getCellEditor().stopCellEditing()) {
    4580             getCellEditor().cancelCellEditing();
    4581         }
    4582         repaint();
    4583     }
    4584
    4585     /**
    4586      * Invoked when a column is moved due to a margin change.
    4587      * If a cell is being edited, then editing is stopped and the cell
    4588      * is redrawn.
    4589      * <p>
    4590      * Application code will not use these methods explicitly, they
    4591      * are used internally by JTable.
    4592      *
    4593      * @param  e    the event received
    4594      * @see TableColumnModelListener
    4595      */
    4596     public void columnMarginChanged(ChangeEvent e) {
    4597         if (isEditing() && !getCellEditor().stopCellEditing()) {
    4598             getCellEditor().cancelCellEditing();
    4599         }
    4600         TableColumn resizingColumn = getResizingColumn();
    4601         // Need to do this here, before the parent's
    4602         // layout manager calls getPreferredSize().
    4603         if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF) {
    4604             resizingColumn.setPreferredWidth(resizingColumn.getWidth());
    4605         }
    4606         resizeAndRepaint();
    4607     }
    4608
    4609     private int limit(int i, int a, int b) {
    4610         return Math.min(b, Math.max(i, a));
    4611     }
    4612
    4613     /**
    4614      * Invoked when the selection model of the <code>TableColumnModel</code>
    4615      * is changed.
    4616      * <p>
    4617      * Application code will not use these methods explicitly, they
    4618      * are used internally by JTable.
    4619      *
    4620      * @param  e  the event received
    4621      * @see TableColumnModelListener
    4622      */
    4623     public void columnSelectionChanged(ListSelectionEvent e) {
    4624         boolean isAdjusting = e.getValueIsAdjusting();
    4625         if (columnSelectionAdjusting && !isAdjusting) {
    4626             // The assumption is that when the model is no longer adjusting
    4627             // we will have already gotten all the changes, and therefore
    4628             // don't need to do an additional paint.
    4629             columnSelectionAdjusting = false;
    4630             return;
    4631         }
    4632         columnSelectionAdjusting = isAdjusting;
    4633         // The getCellRect() call will fail unless there is at least one row.
    4634         if (getRowCount() <= 0 || getColumnCount() <= 0) {
    4635             return;
    4636         }
    4637         int firstIndex = limit(e.getFirstIndex(), 0, getColumnCount()-1);
    4638         int lastIndex = limit(e.getLastIndex(), 0, getColumnCount()-1);
    4639         int minRow = 0;
    4640         int maxRow = getRowCount() - 1;
    4641         if (getRowSelectionAllowed()) {
    4642             minRow = selectionModel.getMinSelectionIndex();
    4643             maxRow = selectionModel.getMaxSelectionIndex();
    4644             int leadRow = getAdjustedIndex(selectionModel.getLeadSelectionIndex(), true);
    4645
    4646             if (minRow == -1 || maxRow == -1) {
    4647                 if (leadRow == -1) {
    4648                     // nothing to repaint, return
    4649                     return;
    4650                 }
    4651
    4652                 // only thing to repaint is the lead
    4653                 minRow = maxRow = leadRow;
    4654             } else {
    4655                 // We need to consider more than just the range between
    4656                 // the min and max selected index. The lead row, which could
    4657                 // be outside this range, should be considered also.
    4658                 if (leadRow != -1) {
    4659                     minRow = Math.min(minRow, leadRow);
    4660                     maxRow = Math.max(maxRow, leadRow);
    4661                 }
    4662             }
    4663         }
    4664         Rectangle firstColumnRect = getCellRect(minRow, firstIndex, false);
    4665         Rectangle lastColumnRect = getCellRect(maxRow, lastIndex, false);
    4666         Rectangle dirtyRegion = firstColumnRect.union(lastColumnRect);
    4667         repaint(dirtyRegion);
    4668     }
    4669
    4670 //
    4671 // Implementing ListSelectionListener interface
    4672 //
    4673
    4674     /**
    4675      * Invoked when the row selection changes -- repaints to show the new
    4676      * selection.
    4677      * <p>
    4678      * Application code will not use these methods explicitly, they
    4679      * are used internally by JTable.
    4680      *
    4681      * @param e   the event received
    4682      * @see ListSelectionListener
    4683      */
    4684     public void valueChanged(ListSelectionEvent e) {
    4685         if (sortManager != null) {
    4686             sortManager.viewSelectionChanged(e);
    4687         }
    4688         boolean isAdjusting = e.getValueIsAdjusting();
    4689         if (rowSelectionAdjusting && !isAdjusting) {
    4690             // The assumption is that when the model is no longer adjusting
    4691             // we will have already gotten all the changes, and therefore
    4692             // don't need to do an additional paint.
    4693             rowSelectionAdjusting = false;
    4694             return;
    4695         }
    4696         rowSelectionAdjusting = isAdjusting;
    4697         // The getCellRect() calls will fail unless there is at least one column.
    4698         if (getRowCount() <= 0 || getColumnCount() <= 0) {
    4699             return;
    4700         }
    4701         int firstIndex = limit(e.getFirstIndex(), 0, getRowCount()-1);
    4702         int lastIndex = limit(e.getLastIndex(), 0, getRowCount()-1);
    4703         Rectangle firstRowRect = getCellRect(firstIndex, 0, false);
    4704         Rectangle lastRowRect = getCellRect(lastIndex, getColumnCount()-1, false);
    4705         Rectangle dirtyRegion = firstRowRect.union(lastRowRect);
    4706         repaint(dirtyRegion);
    4707     }
    4708
    4709 //
    4710 // Implementing the CellEditorListener interface
    4711 //
    4712
    4713     /**
    4714      * Invoked when editing is finished. The changes are saved and the
    4715      * editor is discarded.
    4716      * <p>
    4717      * Application code will not use these methods explicitly, they
    4718      * are used internally by JTable.
    4719      *
    4720      * @param  e  the event received
    4721      * @see CellEditorListener
    4722      */
    4723     public void editingStopped(ChangeEvent e) {
    4724         // Take in the new value
    4725         TableCellEditor editor = getCellEditor();
    4726         if (editor != null) {
    4727             Object value = editor.getCellEditorValue();
    4728             setValueAt(value, editingRow, editingColumn);
    4729             removeEditor();
    4730         }
    4731     }
    4732
    4733     /**
    4734      * Invoked when editing is canceled. The editor object is discarded
    4735      * and the cell is rendered once again.
    4736      * <p>
    4737      * Application code will not use these methods explicitly, they
    4738      * are used internally by JTable.
    4739      *
    4740      * @param  e  the event received
    4741      * @see CellEditorListener
    4742      */
    4743     public void editingCanceled(ChangeEvent e) {
    4744         removeEditor();
    4745     }
    4746
    4747 //
    4748 // Implementing the Scrollable interface
    4749 //
    4750
    4751     /**
    4752      * Sets the preferred size of the viewport for this table.
    4753      *
    4754      * @param size  a <code>Dimension</code> object specifying the <code>preferredSize</code> of a
    4755      *              <code>JViewport</code> whose view is this table
    4756      * @see Scrollable#getPreferredScrollableViewportSize
    4757      */
    4758     @BeanProperty(bound = false, description
    4759             = "The preferred size of the viewport.")
    4760     public void setPreferredScrollableViewportSize(Dimension size) {
    4761         preferredViewportSize = size;
    4762     }
    4763
    4764     /**
    4765      * Returns the preferred size of the viewport for this table.
    4766      *
    4767      * @return a <code>Dimension</code> object containing the <code>preferredSize</code> of the <code>JViewport</code>
    4768      *         which displays this table
    4769      * @see Scrollable#getPreferredScrollableViewportSize
    4770      */
    4771     public Dimension getPreferredScrollableViewportSize() {
    4772         return preferredViewportSize;
    4773     }
    4774
    4775     /**
    4776      * Returns the scroll increment (in pixels) that completely exposes one new
    4777      * row or column (depending on the orientation).
    4778      * <p>
    4779      * This method is called each time the user requests a unit scroll.
    4780      *
    4781      * @param visibleRect the view area visible within the viewport
    4782      * @param orientation either <code>SwingConstants.VERTICAL</code>
    4783      *                  or <code>SwingConstants.HORIZONTAL</code>
    4784      * @param direction less than zero to scroll up/left,
    4785      *                  greater than zero for down/right
    4786      * @return the "unit" increment for scrolling in the specified direction
    4787      * @see Scrollable#getScrollableUnitIncrement
    4788      */
    4789     public int getScrollableUnitIncrement(Rectangle visibleRect,
    4790                                           int orientation,
    4791                                           int direction) {
    4792         int leadingRow;
    4793         int leadingCol;
    4794         Rectangle leadingCellRect;
    4795
    4796         int leadingVisibleEdge;
    4797         int leadingCellEdge;
    4798         int leadingCellSize;
    4799
    4800         leadingRow = getLeadingRow(visibleRect);
    4801         leadingCol = getLeadingCol(visibleRect);
    4802         if (orientation == SwingConstants.VERTICAL && leadingRow < 0) {
    4803             // Couldn't find leading row - return some default value
    4804             return getRowHeight();
    4805         }
    4806         else if (orientation == SwingConstants.HORIZONTAL && leadingCol < 0) {
    4807             // Couldn't find leading col - return some default value
    4808             return 100;
    4809         }
    4810
    4811         // Note that it's possible for one of leadingCol or leadingRow to be
    4812         // -1, depending on the orientation.  This is okay, as getCellRect()
    4813         // still provides enough information to calculate the unit increment.
    4814         leadingCellRect = getCellRect(leadingRow, leadingCol, true);
    4815         leadingVisibleEdge = leadingEdge(visibleRect, orientation);
    4816         leadingCellEdge = leadingEdge(leadingCellRect, orientation);
    4817
    4818         if (orientation == SwingConstants.VERTICAL) {
    4819             leadingCellSize = leadingCellRect.height;
    4820
    4821         }
    4822         else {
    4823             leadingCellSize = leadingCellRect.width;
    4824         }
    4825
    4826         // 4 cases:
    4827         // #1: Leading cell fully visible, reveal next cell
    4828         // #2: Leading cell fully visible, hide leading cell
    4829         // #3: Leading cell partially visible, hide rest of leading cell
    4830         // #4: Leading cell partially visible, reveal rest of leading cell
    4831
    4832         if (leadingVisibleEdge == leadingCellEdge) { // Leading cell is fully
    4833                                                      // visible
    4834             // Case #1: Reveal previous cell
    4835             if (direction < 0) {
    4836                 int retVal = 0;
    4837
    4838                 if (orientation == SwingConstants.VERTICAL) {
    4839                     // Loop past any zero-height rows
    4840                     while (--leadingRow >= 0) {
    4841                         retVal = getRowHeight(leadingRow);
    4842                         if (retVal != 0) {
    4843                             break;
    4844                         }
    4845                     }
    4846                 }
    4847                 else { // HORIZONTAL
    4848                     // Loop past any zero-width cols
    4849                     while (--leadingCol >= 0) {
    4850                         retVal = getCellRect(leadingRow, leadingCol, true).width;
    4851                         if (retVal != 0) {
    4852                             break;
    4853                         }
    4854                     }
    4855                 }
    4856                 return retVal;
    4857             }
    4858             else { // Case #2: hide leading cell
    4859                 return leadingCellSize;
    4860             }
    4861         }
    4862         else { // Leading cell is partially hidden
    4863             // Compute visible, hidden portions
    4864             int hiddenAmt = Math.abs(leadingVisibleEdge - leadingCellEdge);
    4865             int visibleAmt = leadingCellSize - hiddenAmt;
    4866
    4867             if (direction > 0) {
    4868                 // Case #3: hide showing portion of leading cell
    4869                 return visibleAmt;
    4870             }
    4871             else { // Case #4: reveal hidden portion of leading cell
    4872                 return hiddenAmt;
    4873             }
    4874         }
    4875     }
    4876
    4877     /**
    4878      * Returns <code>visibleRect.height</code> or
    4879      * <code>visibleRect.width</code>,
    4880      * depending on this table's orientation.  Note that as of Swing 1.1.1
    4881      * (Java 2 v 1.2.2) the value
    4882      * returned will ensure that the viewport is cleanly aligned on
    4883      * a row boundary.
    4884      *
    4885      * @return <code>visibleRect.height</code> or
    4886      *                                  <code>visibleRect.width</code>
    4887      *                                  per the orientation
    4888      * @see Scrollable#getScrollableBlockIncrement
    4889      */
    4890     public int getScrollableBlockIncrement(Rectangle visibleRect,
    4891             int orientation, int direction) {
    4892
    4893         if (getRowCount() == 0) {
    4894             // Short-circuit empty table model
    4895             if (SwingConstants.VERTICAL == orientation) {
    4896                 int rh = getRowHeight();
    4897                 return (rh > 0) ? Math.max(rh, (visibleRect.height / rh) * rh) :
    4898                                   visibleRect.height;
    4899             }
    4900             else {
    4901                 return visibleRect.width;
    4902             }
    4903         }
    4904         // Shortcut for vertical scrolling of a table w/ uniform row height
    4905         if (null == rowModel && SwingConstants.VERTICAL == orientation) {
    4906             int row = rowAtPoint(visibleRect.getLocation());
    4907             assert row != -1;
    4908             int col = columnAtPoint(visibleRect.getLocation());
    4909             Rectangle cellRect = getCellRect(row, col, true);
    4910
    4911             if (cellRect.y == visibleRect.y) {
    4912                 int rh = getRowHeight();
    4913                 assert rh > 0;
    4914                 return Math.max(rh, (visibleRect.height / rh) * rh);
    4915             }
    4916         }
    4917         if (direction < 0) {
    4918             return getPreviousBlockIncrement(visibleRect, orientation);
    4919         }
    4920         else {
    4921             return getNextBlockIncrement(visibleRect, orientation);
    4922         }
    4923     }
    4924
    4925     /**
    4926      * Called to get the block increment for upward scrolling in cases of
    4927      * horizontal scrolling, or for vertical scrolling of a table with
    4928      * variable row heights.
    4929      */
    4930     private int getPreviousBlockIncrement(Rectangle visibleRect,
    4931                                           int orientation) {
    4932         // Measure back from visible leading edge
    4933         // If we hit the cell on its leading edge, it becomes the leading cell.
    4934         // Else, use following cell
    4935
    4936         int row;
    4937         int col;
    4938
    4939         int   newEdge;
    4940         Point newCellLoc;
    4941
    4942         int visibleLeadingEdge = leadingEdge(visibleRect, orientation);
    4943         boolean leftToRight = getComponentOrientation().isLeftToRight();
    4944         int newLeadingEdge;
    4945
    4946         // Roughly determine the new leading edge by measuring back from the
    4947         // leading visible edge by the size of the visible rect, and find the
    4948         // cell there.
    4949         if (orientation == SwingConstants.VERTICAL) {
    4950             newEdge = visibleLeadingEdge - visibleRect.height;
    4951             int x = visibleRect.x + (leftToRight ? 0 : visibleRect.width);
    4952             newCellLoc = new Point(x, newEdge);
    4953         }
    4954         else if (leftToRight) {
    4955             newEdge = visibleLeadingEdge - visibleRect.width;
    4956             newCellLoc = new Point(newEdge, visibleRect.y);
    4957         }
    4958         else { // Horizontal, right-to-left
    4959             newEdge = visibleLeadingEdge + visibleRect.width;
    4960             newCellLoc = new Point(newEdge - 1, visibleRect.y);
    4961         }
    4962         row = rowAtPoint(newCellLoc);
    4963         col = columnAtPoint(newCellLoc);
    4964
    4965         // If we're measuring past the beginning of the table, we get an invalid
    4966         // cell.  Just go to the beginning of the table in this case.
    4967         if (orientation == SwingConstants.VERTICAL & row < 0) {
    4968             newLeadingEdge = 0;
    4969         }
    4970         else if (orientation == SwingConstants.HORIZONTAL & col < 0) {
    4971             if (leftToRight) {
    4972                 newLeadingEdge = 0;
    4973             }
    4974             else {
    4975                 newLeadingEdge = getWidth();
    4976             }
    4977         }
    4978         else {
    4979             // Refine our measurement
    4980             Rectangle newCellRect = getCellRect(row, col, true);
    4981             int newCellLeadingEdge = leadingEdge(newCellRect, orientation);
    4982             int newCellTrailingEdge = trailingEdge(newCellRect, orientation);
    4983
    4984             // Usually, we hit in the middle of newCell, and want to scroll to
    4985             // the beginning of the cell after newCell.  But there are a
    4986             // couple corner cases where we want to scroll to the beginning of
    4987             // newCell itself.  These cases are:
    4988             // 1) newCell is so large that it ends at or extends into the
    4989             //    visibleRect (newCell is the leading cell, or is adjacent to
    4990             //    the leading cell)
    4991             // 2) newEdge happens to fall right on the beginning of a cell
    4992
    4993             // Case 1
    4994             if ((orientation == SwingConstants.VERTICAL || leftToRight) &&
    4995                 (newCellTrailingEdge >= visibleLeadingEdge)) {
    4996                 newLeadingEdge = newCellLeadingEdge;
    4997             }
    4998             else if (orientation == SwingConstants.HORIZONTAL &&
    4999                      !leftToRight &&
    5000                      newCellTrailingEdge <= visibleLeadingEdge) {
    5001                 newLeadingEdge = newCellLeadingEdge;
    5002             }
    5003             // Case 2:
    5004             else if (newEdge == newCellLeadingEdge) {
    5005                 newLeadingEdge = newCellLeadingEdge;
    5006             }
    5007             // Common case: scroll to cell after newCell
    5008             else {
    5009                 newLeadingEdge = newCellTrailingEdge;
    5010             }
    5011         }
    5012         return Math.abs(visibleLeadingEdge - newLeadingEdge);
    5013     }
    5014
    5015     /**
    5016      * Called to get the block increment for downward scrolling in cases of
    5017      * horizontal scrolling, or for vertical scrolling of a table with
    5018      * variable row heights.
    5019      */
    5020     private int getNextBlockIncrement(Rectangle visibleRect,
    5021                                       int orientation) {
    5022         // Find the cell at the trailing edge.  Return the distance to put
    5023         // that cell at the leading edge.
    5024         int trailingRow = getTrailingRow(visibleRect);
    5025         int trailingCol = getTrailingCol(visibleRect);
    5026
    5027         Rectangle cellRect;
    5028         boolean cellFillsVis;
    5029
    5030         int cellLeadingEdge;
    5031         int cellTrailingEdge;
    5032         int newLeadingEdge;
    5033         int visibleLeadingEdge = leadingEdge(visibleRect, orientation);
    5034
    5035         // If we couldn't find trailing cell, just return the size of the
    5036         // visibleRect.  Note that, for instance, we don't need the
    5037         // trailingCol to proceed if we're scrolling vertically, because
    5038         // cellRect will still fill in the required dimensions.  This would
    5039         // happen if we're scrolling vertically, and the table is not wide
    5040         // enough to fill the visibleRect.
    5041         if (orientation == SwingConstants.VERTICAL && trailingRow < 0) {
    5042             return visibleRect.height;
    5043         }
    5044         else if (orientation == SwingConstants.HORIZONTAL && trailingCol < 0) {
    5045             return visibleRect.width;
    5046         }
    5047         cellRect = getCellRect(trailingRow, trailingCol, true);
    5048         cellLeadingEdge = leadingEdge(cellRect, orientation);
    5049         cellTrailingEdge = trailingEdge(cellRect, orientation);
    5050
    5051         if (orientation == SwingConstants.VERTICAL ||
    5052             getComponentOrientation().isLeftToRight()) {
    5053             cellFillsVis = cellLeadingEdge <= visibleLeadingEdge;
    5054         }
    5055         else { // Horizontal, right-to-left
    5056             cellFillsVis = cellLeadingEdge >= visibleLeadingEdge;
    5057         }
    5058
    5059         if (cellFillsVis) {
    5060             // The visibleRect contains a single large cell.  Scroll to the end
    5061             // of this cell, so the following cell is the first cell.
    5062             newLeadingEdge = cellTrailingEdge;
    5063         }
    5064         else if (cellTrailingEdge == trailingEdge(visibleRect, orientation)) {
    5065             // The trailing cell happens to end right at the end of the
    5066             // visibleRect.  Again, scroll to the beginning of the next cell.
    5067             newLeadingEdge = cellTrailingEdge;
    5068         }
    5069         else {
    5070             // Common case: the trailing cell is partially visible, and isn't
    5071             // big enough to take up the entire visibleRect.  Scroll so it
    5072             // becomes the leading cell.
    5073             newLeadingEdge = cellLeadingEdge;
    5074         }
    5075         return Math.abs(newLeadingEdge - visibleLeadingEdge);
    5076     }
    5077
    5078     /*
    5079      * Return the row at the top of the visibleRect
    5080      *
    5081      * May return -1
    5082      */
    5083     private int getLeadingRow(Rectangle visibleRect) {
    5084         Point leadingPoint;
    5085
    5086         if (getComponentOrientation().isLeftToRight()) {
    5087             leadingPoint = new Point(visibleRect.x, visibleRect.y);
    5088         }
    5089         else {
    5090             leadingPoint = new Point(visibleRect.x + visibleRect.width - 1,
    5091                                      visibleRect.y);
    5092         }
    5093         return rowAtPoint(leadingPoint);
    5094     }
    5095
    5096     /*
    5097      * Return the column at the leading edge of the visibleRect.
    5098      *
    5099      * May return -1
    5100      */
    5101     private int getLeadingCol(Rectangle visibleRect) {
    5102         Point leadingPoint;
    5103
    5104         if (getComponentOrientation().isLeftToRight()) {
    5105             leadingPoint = new Point(visibleRect.x, visibleRect.y);
    5106         }
    5107         else {
    5108             leadingPoint = new Point(visibleRect.x + visibleRect.width - 1,
    5109                                      visibleRect.y);
    5110         }
    5111         return columnAtPoint(leadingPoint);
    5112     }
    5113
    5114     /*
    5115      * Return the row at the bottom of the visibleRect.
    5116      *
    5117      * May return -1
    5118      */
    5119     private int getTrailingRow(Rectangle visibleRect) {
    5120         Point trailingPoint;
    5121
    5122         if (getComponentOrientation().isLeftToRight()) {
    5123             trailingPoint = new Point(visibleRect.x,
    5124                                       visibleRect.y + visibleRect.height - 1);
    5125         }
    5126         else {
    5127             trailingPoint = new Point(visibleRect.x + visibleRect.width - 1,
    5128                                       visibleRect.y + visibleRect.height - 1);
    5129         }
    5130         return rowAtPoint(trailingPoint);
    5131     }
    5132
    5133     /*
    5134      * Return the column at the trailing edge of the visibleRect.
    5135      *
    5136      * May return -1
    5137      */
    5138     private int getTrailingCol(Rectangle visibleRect) {
    5139         Point trailingPoint;
    5140
    5141         if (getComponentOrientation().isLeftToRight()) {
    5142             trailingPoint = new Point(visibleRect.x + visibleRect.width - 1,
    5143                                       visibleRect.y);
    5144         }
    5145         else {
    5146             trailingPoint = new Point(visibleRect.x, visibleRect.y);
    5147         }
    5148         return columnAtPoint(trailingPoint);
    5149     }
    5150
    5151     /*
    5152      * Returns the leading edge ("beginning") of the given Rectangle.
    5153      * For VERTICAL, this is the top, for left-to-right, the left side, and for
    5154      * right-to-left, the right side.
    5155      */
    5156     private int leadingEdge(Rectangle rect, int orientation) {
    5157         if (orientation == SwingConstants.VERTICAL) {
    5158             return rect.y;
    5159         }
    5160         else if (getComponentOrientation().isLeftToRight()) {
    5161             return rect.x;
    5162         }
    5163         else { // Horizontal, right-to-left
    5164             return rect.x + rect.width;
    5165         }
    5166     }
    5167
    5168     /*
    5169      * Returns the trailing edge ("end") of the given Rectangle.
    5170      * For VERTICAL, this is the bottom, for left-to-right, the right side, and
    5171      * for right-to-left, the left side.
    5172      */
    5173     private int trailingEdge(Rectangle rect, int orientation) {
    5174         if (orientation == SwingConstants.VERTICAL) {
    5175             return rect.y + rect.height;
    5176         }
    5177         else if (getComponentOrientation().isLeftToRight()) {
    5178             return rect.x + rect.width;
    5179         }
    5180         else { // Horizontal, right-to-left
    5181             return rect.x;
    5182         }
    5183     }
    5184
    5185     /**
    5186      * Returns false if <code>autoResizeMode</code> is set to
    5187      * <code>AUTO_RESIZE_OFF</code>, which indicates that the
    5188      * width of the viewport does not determine the width
    5189      * of the table.  Otherwise returns true.
    5190      *
    5191      * @return false if <code>autoResizeMode</code> is set
    5192      *   to <code>AUTO_RESIZE_OFF</code>, otherwise returns true
    5193      * @see Scrollable#getScrollableTracksViewportWidth
    5194      */
    5195     @BeanProperty(bound = false)
    5196     public boolean getScrollableTracksViewportWidth() {
    5197         return !(autoResizeMode == AUTO_RESIZE_OFF);
    5198     }
    5199
    5200     /**
    5201      * Returns {@code false} to indicate that the height of the viewport does
    5202      * not determine the height of the table, unless
    5203      * {@code getFillsViewportHeight} is {@code true} and the preferred height
    5204      * of the table is smaller than the viewport's height.
    5205      *
    5206      * @return {@code false} unless {@code getFillsViewportHeight} is
    5207      *         {@code true} and the table needs to be stretched to fill
    5208      *         the viewport
    5209      * @see Scrollable#getScrollableTracksViewportHeight
    5210      * @see #setFillsViewportHeight
    5211      * @see #getFillsViewportHeight
    5212      */
    5213     @BeanProperty(bound = false)
    5214     public boolean getScrollableTracksViewportHeight() {
    5215         Container parent = SwingUtilities.getUnwrappedParent(this);
    5216         return getFillsViewportHeight()
    5217                && parent instanceof JViewport
    5218                && parent.getHeight() > getPreferredSize().height;
    5219     }
    5220
    5221     /**
    5222      * Sets whether or not this table is always made large enough
    5223      * to fill the height of an enclosing viewport. If the preferred
    5224      * height of the table is smaller than the viewport, then the table
    5225      * will be stretched to fill the viewport. In other words, this
    5226      * ensures the table is never smaller than the viewport.
    5227      * The default for this property is {@code false}.
    5228      *
    5229      * @param fillsViewportHeight whether or not this table is always
    5230      *        made large enough to fill the height of an enclosing
    5231      *        viewport
    5232      * @see #getFillsViewportHeight
    5233      * @see #getScrollableTracksViewportHeight
    5234      * @since 1.6
    5235      */
    5236     @BeanProperty(description
    5237             = "Whether or not this table is always made large enough to fill the height of an enclosing viewport")
    5238     public void setFillsViewportHeight(boolean fillsViewportHeight) {
    5239         boolean old = this.fillsViewportHeight;
    5240         this.fillsViewportHeight = fillsViewportHeight;
    5241         resizeAndRepaint();
    5242         firePropertyChange("fillsViewportHeight", old, fillsViewportHeight);
    5243     }
    5244
    5245     /**
    5246      * Returns whether or not this table is always made large enough
    5247      * to fill the height of an enclosing viewport.
    5248      *
    5249      * @return whether or not this table is always made large enough
    5250      *         to fill the height of an enclosing viewport
    5251      * @see #setFillsViewportHeight
    5252      * @since 1.6
    5253      */
    5254     public boolean getFillsViewportHeight() {
    5255         return fillsViewportHeight;
    5256     }
    5257
    5258 //
    5259 // Protected Methods
    5260 //
    5261
    5262     protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
    5263                                         int condition, boolean pressed) {
    5264         boolean retValue = super.processKeyBinding(ks, e, condition, pressed);
    5265
    5266         // Start editing when a key is typed. UI classes can disable this behavior
    5267         // by setting the client property JTable.autoStartsEdit to Boolean.FALSE.
    5268         if (!retValue && condition == WHEN_ANCESTOR_OF_FOCUSED_COMPONENT &&
    5269             isFocusOwner() &&
    5270             !Boolean.FALSE.equals(getClientProperty("JTable.autoStartsEdit"))) {
    5271             // We do not have a binding for the event.
    5272             Component editorComponent = getEditorComponent();
    5273             if (editorComponent == null) {
    5274                 // Only attempt to install the editor on a KEY_PRESSED,
    5275                 if (e == null || e.getID() != KeyEvent.KEY_PRESSED) {
    5276                     return false;
    5277                 }
    5278                 // Don't start when just a modifier is pressed
    5279                 int code = e.getKeyCode();
    5280                 if (code == KeyEvent.VK_SHIFT || code == KeyEvent.VK_CONTROL ||
    5281                     code == KeyEvent.VK_ALT) {
    5282                     return false;
    5283                 }
    5284                 // Try to install the editor
    5285                 int leadRow = getSelectionModel().getLeadSelectionIndex();
    5286                 int leadColumn = getColumnModel().getSelectionModel().
    5287                                    getLeadSelectionIndex();
    5288                 if (leadRow != -1 && leadColumn != -1 && !isEditing()) {
    5289                     if (!editCellAt(leadRow, leadColumn, e)) {
    5290                         return false;
    5291                     }
    5292                 }
    5293                 editorComponent = getEditorComponent();
    5294                 if (editorComponent == null) {
    5295                     return false;
    5296                 }
    5297             }
    5298             // If the editorComponent is a JComponent, pass the event to it.
    5299             if (editorComponent instanceof JComponent) {
    5300                 retValue = ((JComponent)editorComponent).processKeyBinding
    5301                                         (ks, e, WHEN_FOCUSED, pressed);
    5302                 // If we have started an editor as a result of the user
    5303                 // pressing a key and the surrendersFocusOnKeystroke property
    5304                 // is true, give the focus to the new editor.
    5305                 if (getSurrendersFocusOnKeystroke()) {
    5306                     editorComponent.requestFocus();
    5307                 }
    5308             }
    5309         }
    5310         return retValue;
    5311     }
    5312
    5313     /**
    5314      * Creates default cell renderers for objects, numbers, doubles, dates,
    5315      * booleans, and icons.
    5316      * @see javax.swing.table.DefaultTableCellRenderer
    5317      *
    5318      */
    5319     protected void createDefaultRenderers() {
    5320         defaultRenderersByColumnClass = new UIDefaults(8, 0.75f);
    5321
    5322         // Objects
    5323         defaultRenderersByColumnClass.put(Object.class, (UIDefaults.LazyValue)
    5324                 t -> new DefaultTableCellRenderer.UIResource());
    5325
    5326         // Numbers
    5327         defaultRenderersByColumnClass.put(Number.class, (UIDefaults.LazyValue)
    5328                 t -> new NumberRenderer());
    5329
    5330         // Doubles and Floats
    5331         defaultRenderersByColumnClass.put(Float.class, (UIDefaults.LazyValue)
    5332                 t -> new DoubleRenderer());
    5333         defaultRenderersByColumnClass.put(Double.class, (UIDefaults.LazyValue)
    5334                 t -> new DoubleRenderer());
    5335
    5336         // Dates
    5337         defaultRenderersByColumnClass.put(Date.class, (UIDefaults.LazyValue)
    5338                 t -> new DateRenderer());
    5339
    5340         // Icons and ImageIcons
    5341         defaultRenderersByColumnClass.put(Icon.class, (UIDefaults.LazyValue)
    5342                 t -> new IconRenderer());
    5343         defaultRenderersByColumnClass.put(ImageIcon.class, (UIDefaults.LazyValue)
    5344                 t -> new IconRenderer());
    5345
    5346         // Booleans
    5347         defaultRenderersByColumnClass.put(Boolean.class, (UIDefaults.LazyValue)
    5348                 t -> new BooleanRenderer());
    5349     }
    5350
    5351     /**
    5352      * Default Renderers
    5353      **/
    5354     static class NumberRenderer extends DefaultTableCellRenderer.UIResource {
    5355         public NumberRenderer() {
    5356             super();
    5357             setHorizontalAlignment(JLabel.RIGHT);
    5358         }
    5359     }
    5360
    5361     static class DoubleRenderer extends NumberRenderer {
    5362         NumberFormat formatter;
    5363         public DoubleRenderer() { super(); }
    5364
    5365         public void setValue(Object value) {
    5366             if (formatter == null) {
    5367                 formatter = NumberFormat.getInstance();
    5368             }
    5369             setText((value == null) ? "" : formatter.format(value));
    5370         }
    5371     }
    5372
    5373     static class DateRenderer extends DefaultTableCellRenderer.UIResource {
    5374         DateFormat formatter;
    5375         public DateRenderer() { super(); }
    5376
    5377         public void setValue(Object value) {
    5378             if (formatter==null) {
    5379                 formatter = DateFormat.getDateInstance();
    5380             }
    5381             setText((value == null) ? "" : formatter.format(value));
    5382         }
    5383     }
    5384
    5385     static class IconRenderer extends DefaultTableCellRenderer.UIResource {
    5386         public IconRenderer() {
    5387             super();
    5388             setHorizontalAlignment(JLabel.CENTER);
    5389         }
    5390         public void setValue(Object value) { setIcon((value instanceof Icon) ? (Icon)value : null); }
    5391     }
    5392
    5393
    5394     static class BooleanRenderer extends JCheckBox implements TableCellRenderer, UIResource
    5395     {
    5396         private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
    5397
    5398         public BooleanRenderer() {
    5399             super();
    5400             setHorizontalAlignment(JLabel.CENTER);
    5401             setBorderPainted(true);
    5402         }
    5403
    5404         public Component getTableCellRendererComponent(JTable table, Object value,
    5405                                                        boolean isSelected, boolean hasFocus, int row, int column) {
    5406             if (isSelected) {
    5407                 setForeground(table.getSelectionForeground());
    5408                 super.setBackground(table.getSelectionBackground());
    5409             }
    5410             else {
    5411                 setForeground(table.getForeground());
    5412                 setBackground(table.getBackground());
    5413             }
    5414             setSelected((value != null && ((Boolean)value).booleanValue()));
    5415
    5416             if (hasFocus) {
    5417                 setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
    5418             } else {
    5419                 setBorder(noFocusBorder);
    5420             }
    5421
    5422             return this;
    5423         }
    5424     }
    5425
    5426     /**
    5427      * Creates default cell editors for objects, numbers, and boolean values.
    5428      * @see DefaultCellEditor
    5429      */
    5430     protected void createDefaultEditors() {
    5431         defaultEditorsByColumnClass = new UIDefaults(3, 0.75f);
    5432
    5433         // Objects
    5434         defaultEditorsByColumnClass.put(Object.class, (UIDefaults.LazyValue)
    5435                 t -> new GenericEditor());
    5436
    5437         // Numbers
    5438         defaultEditorsByColumnClass.put(Number.class, (UIDefaults.LazyValue)
    5439                 t -> new NumberEditor());
    5440
    5441         // Booleans
    5442         defaultEditorsByColumnClass.put(Boolean.class, (UIDefaults.LazyValue)
    5443                 t -> new BooleanEditor());
    5444     }
    5445
    5446     /**
    5447      * Default Editors
    5448      */
    5449     static class GenericEditor extends DefaultCellEditor {
    5450
    5451         Class<?>[] argTypes = new Class<?>[]{String.class};
    5452         java.lang.reflect.Constructor<?> constructor;
    5453         Object value;
    5454
    5455         public GenericEditor() {
    5456             super(new JTextField());
    5457             getComponent().setName("Table.editor");
    5458         }
    5459
    5460         public boolean stopCellEditing() {
    5461             String s = (String)super.getCellEditorValue();
    5462             // Here we are dealing with the case where a user
    5463             // has deleted the string value in a cell, possibly
    5464             // after a failed validation. Return null, so that
    5465             // they have the option to replace the value with
    5466             // null or use escape to restore the original.
    5467             // For Strings, return "" for backward compatibility.
    5468             try {
    5469                 if ("".equals(s)) {
    5470                     if (constructor.getDeclaringClass() == String.class) {
    5471                         value = s;
    5472                     }
    5473                     return super.stopCellEditing();
    5474                 }
    5475
    5476                 SwingUtilities2.checkAccess(constructor.getModifiers());
    5477                 value = constructor.newInstance(new Object[]{s});
    5478             }
    5479             catch (Exception e) {
    5480                 ((JComponent)getComponent()).setBorder(new LineBorder(Color.red));
    5481                 return false;
    5482             }
    5483             return super.stopCellEditing();
    5484         }
    5485
    5486         public Component getTableCellEditorComponent(JTable table, Object value,
    5487                                                  boolean isSelected,
    5488                                                  int row, int column) {
    5489             this.value = null;
    5490             ((JComponent)getComponent()).setBorder(new LineBorder(Color.black));
    5491             try {
    5492                 Class<?> type = table.getColumnClass(column);
    5493                 // Since our obligation is to produce a value which is
    5494                 // assignable for the required type it is OK to use the
    5495                 // String constructor for columns which are declared
    5496                 // to contain Objects. A String is an Object.
    5497                 if (type == Object.class) {
    5498                     type = String.class;
    5499                 }
    5500                 ReflectUtil.checkPackageAccess(type);
    5501                 SwingUtilities2.checkAccess(type.getModifiers());
    5502                 constructor = type.getConstructor(argTypes);
    5503             }
    5504             catch (Exception e) {
    5505                 return null;
    5506             }
    5507             return super.getTableCellEditorComponent(table, value, isSelected, row, column);
    5508         }
    5509
    5510         public Object getCellEditorValue() {
    5511             return value;
    5512         }
    5513     }
    5514
    5515     static class NumberEditor extends GenericEditor {
    5516
    5517         public NumberEditor() {
    5518             ((JTextField)getComponent()).setHorizontalAlignment(JTextField.RIGHT);
    5519         }
    5520     }
    5521
    5522     static class BooleanEditor extends DefaultCellEditor {
    5523         public BooleanEditor() {
    5524             super(new JCheckBox());
    5525             JCheckBox checkBox = (JCheckBox)getComponent();
    5526             checkBox.setHorizontalAlignment(JCheckBox.CENTER);
    5527         }
    5528     }
    5529
    5530     /**
    5531      * Initializes table properties to their default values.
    5532      */
    5533     protected void initializeLocalVars() {
    5534         updateSelectionOnSort = true;
    5535         setOpaque(true);
    5536         createDefaultRenderers();
    5537         createDefaultEditors();
    5538
    5539         setTableHeader(createDefaultTableHeader());
    5540
    5541         setShowGrid(true);
    5542         setAutoResizeMode(AUTO_RESIZE_SUBSEQUENT_COLUMNS);
    5543         setRowHeight(16);
    5544         isRowHeightSet = false;
    5545         setRowMargin(1);
    5546         setRowSelectionAllowed(true);
    5547         setCellEditor(null);
    5548         setEditingColumn(-1);
    5549         setEditingRow(-1);
    5550         setSurrendersFocusOnKeystroke(false);
    5551         setPreferredScrollableViewportSize(new Dimension(450, 400));
    5552
    5553         // I'm registered to do tool tips so we can draw tips for the renderers
    5554         ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
    5555         toolTipManager.registerComponent(this);
    5556
    5557         setAutoscrolls(true);
    5558     }
    5559
    5560     /**
    5561      * Returns the default table model object, which is
    5562      * a <code>DefaultTableModel</code>.  A subclass can override this
    5563      * method to return a different table model object.
    5564      *
    5565      * @return the default table model object
    5566      * @see javax.swing.table.DefaultTableModel
    5567      */
    5568     protected TableModel createDefaultDataModel() {
    5569         return new DefaultTableModel();
    5570     }
    5571
    5572     /**
    5573      * Returns the default column model object, which is
    5574      * a <code>DefaultTableColumnModel</code>.  A subclass can override this
    5575      * method to return a different column model object.
    5576      *
    5577      * @return the default column model object
    5578      * @see javax.swing.table.DefaultTableColumnModel
    5579      */
    5580     protected TableColumnModel createDefaultColumnModel() {
    5581         return new DefaultTableColumnModel();
    5582     }
    5583
    5584     /**
    5585      * Returns the default selection model object, which is
    5586      * a <code>DefaultListSelectionModel</code>.  A subclass can override this
    5587      * method to return a different selection model object.
    5588      *
    5589      * @return the default selection model object
    5590      * @see javax.swing.DefaultListSelectionModel
    5591      */
    5592     protected ListSelectionModel createDefaultSelectionModel() {
    5593         return new DefaultListSelectionModel();
    5594     }
    5595
    5596     /**
    5597      * Returns the default table header object, which is
    5598      * a <code>JTableHeader</code>.  A subclass can override this
    5599      * method to return a different table header object.
    5600      *
    5601      * @return the default table header object
    5602      * @see javax.swing.table.JTableHeader
    5603      */
    5604     protected JTableHeader createDefaultTableHeader() {
    5605         return new JTableHeader(columnModel);
    5606     }
    5607
    5608     /**
    5609      * Equivalent to <code>revalidate</code> followed by <code>repaint</code>.
    5610      */
    5611     protected void resizeAndRepaint() {
    5612         revalidate();
    5613         repaint();
    5614     }
    5615
    5616     /**
    5617      * Returns the active cell editor, which is {@code null} if the table
    5618      * is not currently editing.
    5619      *
    5620      * @return the {@code TableCellEditor} that does the editing,
    5621      *         or {@code null} if the table is not currently editing.
    5622      * @see #cellEditor
    5623      * @see #getCellEditor(int, int)
    5624      */
    5625     public TableCellEditor getCellEditor() {
    5626         return cellEditor;
    5627     }
    5628
    5629     /**
    5630      * Sets the active cell editor.
    5631      *
    5632      * @param anEditor the active cell editor
    5633      * @see #cellEditor
    5634      */
    5635     @BeanProperty(description
    5636             = "The table's active cell editor.")
    5637     public void setCellEditor(TableCellEditor anEditor) {
    5638         TableCellEditor oldEditor = cellEditor;
    5639         cellEditor = anEditor;
    5640         firePropertyChange("tableCellEditor", oldEditor, anEditor);
    5641     }
    5642
    5643     /**
    5644      * Sets the <code>editingColumn</code> variable.
    5645      * @param aColumn  the column of the cell to be edited
    5646      *
    5647      * @see #editingColumn
    5648      */
    5649     public void setEditingColumn(int aColumn) {
    5650         editingColumn = aColumn;
    5651     }
    5652
    5653     /**
    5654      * Sets the <code>editingRow</code> variable.
    5655      * @param aRow  the row of the cell to be edited
    5656      *
    5657      * @see #editingRow
    5658      */
    5659     public void setEditingRow(int aRow) {
    5660         editingRow = aRow;
    5661     }
    5662
    5663     /**
    5664      * Returns an appropriate renderer for the cell specified by this row and
    5665      * column. If the <code>TableColumn</code> for this column has a non-null
    5666      * renderer, returns that.  If not, finds the class of the data in
    5667      * this column (using <code>getColumnClass</code>)
    5668      * and returns the default renderer for this type of data.
    5669      * <p>
    5670      * <b>Note:</b>
    5671      * Throughout the table package, the internal implementations always
    5672      * use this method to provide renderers so that this default behavior
    5673      * can be safely overridden by a subclass.
    5674      *
    5675      * @param row       the row of the cell to render, where 0 is the first row
    5676      * @param column    the column of the cell to render,
    5677      *                  where 0 is the first column
    5678      * @return the assigned renderer; if <code>null</code>
    5679      *                  returns the default renderer
    5680      *                  for this type of object
    5681      * @see javax.swing.table.DefaultTableCellRenderer
    5682      * @see javax.swing.table.TableColumn#setCellRenderer
    5683      * @see #setDefaultRenderer
    5684      */
    5685     public TableCellRenderer getCellRenderer(int row, int column) {
    5686         TableColumn tableColumn = getColumnModel().getColumn(column);
    5687         TableCellRenderer renderer = tableColumn.getCellRenderer();
    5688         if (renderer == null) {
    5689             renderer = getDefaultRenderer(getColumnClass(column));
    5690         }
    5691         return renderer;
    5692     }
    5693
    5694     /**
    5695      * Prepares the renderer by querying the data model for the
    5696      * value and selection state
    5697      * of the cell at <code>row</code>, <code>column</code>.
    5698      * Returns the component (may be a <code>Component</code>
    5699      * or a <code>JComponent</code>) under the event location.
    5700      * <p>
    5701      * During a printing operation, this method will configure the
    5702      * renderer without indicating selection or focus, to prevent
    5703      * them from appearing in the printed output. To do other
    5704      * customizations based on whether or not the table is being
    5705      * printed, you can check the value of
    5706      * {@link javax.swing.JComponent#isPaintingForPrint()}, either here
    5707      * or within custom renderers.
    5708      * <p>
    5709      * <b>Note:</b>
    5710      * Throughout the table package, the internal implementations always
    5711      * use this method to prepare renderers so that this default behavior
    5712      * can be safely overridden by a subclass.
    5713      *
    5714      * @param renderer  the <code>TableCellRenderer</code> to prepare
    5715      * @param row       the row of the cell to render, where 0 is the first row
    5716      * @param column    the column of the cell to render,
    5717      *                  where 0 is the first column
    5718      * @return          the <code>Component</code> under the event location
    5719      */
    5720     public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
    5721         Object value = getValueAt(row, column);
    5722
    5723         boolean isSelected = false;
    5724         boolean hasFocus = false;
    5725
    5726         // Only indicate the selection and focused cell if not printing
    5727         if (!isPaintingForPrint()) {
    5728             isSelected = isCellSelected(row, column);
    5729
    5730             boolean rowIsLead =
    5731                 (selectionModel.getLeadSelectionIndex() == row);
    5732             boolean colIsLead =
    5733                 (columnModel.getSelectionModel().getLeadSelectionIndex() == column);
    5734
    5735             hasFocus = (rowIsLead && colIsLead) && isFocusOwner();
    5736         }
    5737
    5738         return renderer.getTableCellRendererComponent(this, value,
    5739                                                       isSelected, hasFocus,
    5740                                                       row, column);
    5741     }
    5742
    5743     /**
    5744      * Returns an appropriate editor for the cell specified by
    5745      * <code>row</code> and <code>column</code>. If the
    5746      * <code>TableColumn</code> for this column has a non-null editor,
    5747      * returns that.  If not, finds the class of the data in this
    5748      * column (using <code>getColumnClass</code>)
    5749      * and returns the default editor for this type of data.
    5750      * <p>
    5751      * <b>Note:</b>
    5752      * Throughout the table package, the internal implementations always
    5753      * use this method to provide editors so that this default behavior
    5754      * can be safely overridden by a subclass.
    5755      *
    5756      * @param row       the row of the cell to edit, where 0 is the first row
    5757      * @param column    the column of the cell to edit,
    5758      *                  where 0 is the first column
    5759      * @return          the editor for this cell;
    5760      *                  if <code>null</code> return the default editor for
    5761      *                  this type of cell
    5762      * @see DefaultCellEditor
    5763      */
    5764     public TableCellEditor getCellEditor(int row, int column) {
    5765         TableColumn tableColumn = getColumnModel().getColumn(column);
    5766         TableCellEditor editor = tableColumn.getCellEditor();
    5767         if (editor == null) {
    5768             editor = getDefaultEditor(getColumnClass(column));
    5769         }
    5770         return editor;
    5771     }
    5772
    5773
    5774     /**
    5775      * Prepares the editor by querying the data model for the value and
    5776      * selection state of the cell at <code>row</code>, <code>column</code>.
    5777      * <p>
    5778      * <b>Note:</b>
    5779      * Throughout the table package, the internal implementations always
    5780      * use this method to prepare editors so that this default behavior
    5781      * can be safely overridden by a subclass.
    5782      *
    5783      * @param editor  the <code>TableCellEditor</code> to set up
    5784      * @param row     the row of the cell to edit,
    5785      *                where 0 is the first row
    5786      * @param column  the column of the cell to edit,
    5787      *                where 0 is the first column
    5788      * @return the <code>Component</code> being edited
    5789      */
    5790     @SuppressWarnings("deprecation")
    5791     public Component prepareEditor(TableCellEditor editor, int row, int column) {
    5792         Object value = getValueAt(row, column);
    5793         boolean isSelected = isCellSelected(row, column);
    5794         Component comp = editor.getTableCellEditorComponent(this, value, isSelected,
    5795                                                   row, column);
    5796         if (comp instanceof JComponent) {
    5797             JComponent jComp = (JComponent)comp;
    5798             if (jComp.getNextFocusableComponent() == null) {
    5799                 jComp.setNextFocusableComponent(this);
    5800             }
    5801         }
    5802         return comp;
    5803     }
    5804
    5805     /**
    5806      * Discards the editor object and frees the real estate it used for
    5807      * cell rendering.
    5808      */
    5809     public void removeEditor() {
    5810         KeyboardFocusManager.getCurrentKeyboardFocusManager().
    5811             removePropertyChangeListener("permanentFocusOwner", editorRemover);
    5812         editorRemover = null;
    5813
    5814         TableCellEditor editor = getCellEditor();
    5815         if(editor != null) {
    5816             editor.removeCellEditorListener(this);
    5817             if (editorComp != null) {
    5818                 Component focusOwner =
    5819                         KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
    5820                 boolean isFocusOwnerInTheTable = focusOwner != null?
    5821                         SwingUtilities.isDescendingFrom(focusOwner, this):false;
    5822                 remove(editorComp);
    5823                 if(isFocusOwnerInTheTable) {
    5824                     requestFocusInWindow();
    5825                 }
    5826             }
    5827
    5828             Rectangle cellRect = getCellRect(editingRow, editingColumn, false);
    5829
    5830             setCellEditor(null);
    5831             setEditingColumn(-1);
    5832             setEditingRow(-1);
    5833             editorComp = null;
    5834
    5835             repaint(cellRect);
    5836         }
    5837     }
    5838
    5839 //
    5840 // Serialization
    5841 //
    5842
    5843     /**
    5844      * See readObject() and writeObject() in JComponent for more
    5845      * information about serialization in Swing.
    5846      */
    5847     private void writeObject(ObjectOutputStream s) throws IOException {
    5848         s.defaultWriteObject();
    5849         if (getUIClassID().equals(uiClassID)) {
    5850             byte count = JComponent.getWriteObjCounter(this);
    5851             JComponent.setWriteObjCounter(this, --count);
    5852             if (count == 0 && ui != null) {
    5853                 ui.installUI(this);
    5854             }
    5855         }
    5856     }
    5857
    5858     private void readObject(ObjectInputStream s)
    5859         throws IOException, ClassNotFoundException
    5860     {
    5861         ObjectInputStream.GetField f = s.readFields();
    5862
    5863         TableModel newDataModel = (TableModel) f.get("dataModel", null);
    5864         if (newDataModel == null) {
    5865             throw new InvalidObjectException("Null dataModel");
    5866         }
    5867         dataModel = newDataModel;
    5868
    5869         TableColumnModel newColumnModel = (TableColumnModel) f.get("columnModel", null);
    5870         if (newColumnModel == null) {
    5871             throw new InvalidObjectException("Null columnModel");
    5872         }
    5873         columnModel = newColumnModel;
    5874
    5875         ListSelectionModel newSelectionModel = (ListSelectionModel) f.get("selectionModel", null);
    5876         if (newSelectionModel == null) {
    5877             throw new InvalidObjectException("Null selectionModel");
    5878         }
    5879         selectionModel = newSelectionModel;
    5880
    5881         tableHeader = (JTableHeader) f.get("tableHeader", null);
    5882         int newRowHeight = f.get("rowHeight", 0);
    5883         if (newRowHeight <= 0) {
    5884             throw new InvalidObjectException("Row height less than 1");
    5885         }
    5886         rowHeight = newRowHeight;
    5887
    5888         rowMargin = f.get("rowMargin", 0);
    5889         Color newGridColor = (Color) f.get("gridColor", null);
    5890         if (newGridColor == null) {
    5891             throw new InvalidObjectException("Null gridColor");
    5892         }
    5893         gridColor = newGridColor;
    5894
    5895         showHorizontalLines = f.get("showHorizontalLines", false);
    5896         showVerticalLines = f.get("showVerticalLines", false);
    5897         int newAutoResizeMode = f.get("autoResizeMode", 0);
    5898         if (!isValidAutoResizeMode(newAutoResizeMode)) {
    5899             throw new InvalidObjectException("autoResizeMode is not valid");
    5900         }
    5901         autoResizeMode = newAutoResizeMode;
    5902         autoCreateColumnsFromModel = f.get("autoCreateColumnsFromModel", false);
    5903         preferredViewportSize = (Dimension) f.get("preferredViewportSize", null);
    5904         rowSelectionAllowed = f.get("rowSelectionAllowed", false);
    5905         cellSelectionEnabled = f.get("cellSelectionEnabled", false);
    5906         selectionForeground = (Color) f.get("selectionForeground", null);
    5907         selectionBackground = (Color) f.get("selectionBackground", null);
    5908         rowModel = (SizeSequence) f.get("rowModel", null);
    5909
    5910         boolean newDragEnabled = f.get("dragEnabled", false);
    5911         checkDragEnabled(newDragEnabled);
    5912         dragEnabled = newDragEnabled;
    5913
    5914         surrendersFocusOnKeystroke = f.get("surrendersFocusOnKeystroke", false);
    5915         editorRemover = (PropertyChangeListener) f.get("editorRemover", null);
    5916         columnSelectionAdjusting = f.get("columnSelectionAdjusting", false);
    5917         rowSelectionAdjusting = f.get("rowSelectionAdjusting", false);
    5918         printError = (Throwable) f.get("printError", null);
    5919         isRowHeightSet = f.get("isRowHeightSet", false);
    5920         updateSelectionOnSort = f.get("updateSelectionOnSort", false);
    5921         ignoreSortChange = f.get("ignoreSortChange", false);
    5922         sorterChanged = f.get("sorterChanged", false);
    5923         autoCreateRowSorter = f.get("autoCreateRowSorter", false);
    5924         fillsViewportHeight = f.get("fillsViewportHeight", false);
    5925         DropMode newDropMode = (DropMode) f.get("dropMode",
    5926                 DropMode.USE_SELECTION);
    5927         checkDropMode(newDropMode);
    5928         dropMode = newDropMode;
    5929
    5930         if ((ui != null) && (getUIClassID().equals(uiClassID))) {
    5931             ui.installUI(this);
    5932         }
    5933         createDefaultRenderers();
    5934         createDefaultEditors();
    5935
    5936         // If ToolTipText != null, then the tooltip has already been
    5937         // registered by JComponent.readObject() and we don't want
    5938         // to re-register here
    5939         if (getToolTipText() == null) {
    5940             ToolTipManager.sharedInstance().registerComponent(this);
    5941          }
    5942     }
    5943
    5944     /* Called from the JComponent's EnableSerializationFocusListener to
    5945      * do any Swing-specific pre-serialization configuration.
    5946      */
    5947     void compWriteObjectNotify() {
    5948         super.compWriteObjectNotify();
    5949         // If ToolTipText != null, then the tooltip has already been
    5950         // unregistered by JComponent.compWriteObjectNotify()
    5951         if (getToolTipText() == null) {
    5952             ToolTipManager.sharedInstance().unregisterComponent(this);
    5953         }
    5954     }
    5955
    5956     /**
    5957      * Returns a string representation of this table. This method
    5958      * is intended to be used only for debugging purposes, and the
    5959      * content and format of the returned string may vary between
    5960      * implementations. The returned string may be empty but may not
    5961      * be <code>null</code>.
    5962      *
    5963      * @return  a string representation of this table
    5964      */
    5965     protected String paramString() {
    5966         String gridColorString = (gridColor != null ?
    5967                                   gridColor.toString() : "");
    5968         String showHorizontalLinesString = (showHorizontalLines ?
    5969                                             "true" : "false");
    5970         String showVerticalLinesString = (showVerticalLines ?
    5971                                           "true" : "false");
    5972         String autoResizeModeString;
    5973         if (autoResizeMode == AUTO_RESIZE_OFF) {
    5974             autoResizeModeString = "AUTO_RESIZE_OFF";
    5975         } else if (autoResizeMode == AUTO_RESIZE_NEXT_COLUMN) {
    5976             autoResizeModeString = "AUTO_RESIZE_NEXT_COLUMN";
    5977         } else if (autoResizeMode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) {
    5978             autoResizeModeString = "AUTO_RESIZE_SUBSEQUENT_COLUMNS";
    5979         } else if (autoResizeMode == AUTO_RESIZE_LAST_COLUMN) {
    5980             autoResizeModeString = "AUTO_RESIZE_LAST_COLUMN";
    5981         } else if (autoResizeMode == AUTO_RESIZE_ALL_COLUMNS)  {
    5982             autoResizeModeString = "AUTO_RESIZE_ALL_COLUMNS";
    5983         } else autoResizeModeString = "";
    5984         String autoCreateColumnsFromModelString = (autoCreateColumnsFromModel ?
    5985                                                    "true" : "false");
    5986         String preferredViewportSizeString = (preferredViewportSize != null ?
    5987                                               preferredViewportSize.toString()
    5988                                               : "");
    5989         String rowSelectionAllowedString = (rowSelectionAllowed ?
    5990                                             "true" : "false");
    5991         String cellSelectionEnabledString = (cellSelectionEnabled ?
    5992                                             "true" : "false");
    5993         String selectionForegroundString = (selectionForeground != null ?
    5994                                             selectionForeground.toString() :
    5995                                             "");
    5996         String selectionBackgroundString = (selectionBackground != null ?
    5997                                             selectionBackground.toString() :
    5998                                             "");
    5999
    6000         return super.paramString() +
    6001         ",autoCreateColumnsFromModel=" + autoCreateColumnsFromModelString +
    6002         ",autoResizeMode=" + autoResizeModeString +
    6003         ",cellSelectionEnabled=" + cellSelectionEnabledString +
    6004         ",editingColumn=" + editingColumn +
    6005         ",editingRow=" + editingRow +
    6006         ",gridColor=" + gridColorString +
    6007         ",preferredViewportSize=" + preferredViewportSizeString +
    6008         ",rowHeight=" + rowHeight +
    6009         ",rowMargin=" + rowMargin +
    6010         ",rowSelectionAllowed=" + rowSelectionAllowedString +
    6011         ",selectionBackground=" + selectionBackgroundString +
    6012         ",selectionForeground=" + selectionForegroundString +
    6013         ",showHorizontalLines=" + showHorizontalLinesString +
    6014         ",showVerticalLines=" + showVerticalLinesString;
    6015     }
    6016
    6017     // This class tracks changes in the keyboard focus state. It is used
    6018     // when the JTable is editing to determine when to cancel the edit.
    6019     // If focus switches to a component outside of the jtable, but in the
    6020     // same window, this will cancel editing.
    6021     class CellEditorRemover implements PropertyChangeListener {
    6022         KeyboardFocusManager focusManager;
    6023
    6024         public CellEditorRemover(KeyboardFocusManager fm) {
    6025             this.focusManager = fm;
    6026         }
    6027
    6028         @SuppressWarnings("deprecation")
    6029         public void propertyChange(PropertyChangeEvent ev) {
    6030             if (!isEditing() || getClientProperty("terminateEditOnFocusLost") != Boolean.TRUE) {
    6031                 return;
    6032             }
    6033
    6034             Component c = focusManager.getPermanentFocusOwner();
    6035             while (c != null) {
    6036                 if (c == JTable.this) {
    6037                     // focus remains inside the table
    6038                     return;
    6039                 } else if ((c instanceof Window) ||
    6040                            (c instanceof Applet && c.getParent() == null)) {
    6041                     if (c == SwingUtilities.getRoot(JTable.this)) {
    6042                         if (!getCellEditor().stopCellEditing()) {
    6043                             getCellEditor().cancelCellEditing();
    6044                         }
    6045                     }
    6046                     break;
    6047                 }
    6048                 c = c.getParent();
    6049             }
    6050         }
    6051     }
    6052
    6053 /////////////////
    6054 // Printing Support
    6055 /////////////////
    6056
    6057     /**
    6058      * A convenience method that displays a printing dialog, and then prints
    6059      * this <code>JTable</code> in mode <code>PrintMode.FIT_WIDTH</code>,
    6060      * with no header or footer text. A modal progress dialog, with an abort
    6061      * option, will be shown for the duration of printing.
    6062      * <p>
    6063      * Note: In headless mode, no dialogs are shown and printing
    6064      * occurs on the default printer.
    6065      *
    6066      * @return true, unless printing is cancelled by the user
    6067      * @throws SecurityException if this thread is not allowed to
    6068      *                           initiate a print job request
    6069      * @throws PrinterException if an error in the print system causes the job
    6070      *                          to be aborted
    6071      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
    6072      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
    6073      * @see #getPrintable
    6074      *
    6075      * @since 1.5
    6076      */
    6077     public boolean print() throws PrinterException {
    6078
    6079         return print(PrintMode.FIT_WIDTH);
    6080     }
    6081
    6082     /**
    6083      * A convenience method that displays a printing dialog, and then prints
    6084      * this <code>JTable</code> in the given printing mode,
    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      * @param  printMode        the printing mode that the printable should use
    6092      * @return true, unless printing is cancelled by the user
    6093      * @throws SecurityException if this thread is not allowed to
    6094      *                           initiate a print job request
    6095      * @throws PrinterException if an error in the print system causes the job
    6096      *                          to be aborted
    6097      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
    6098      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
    6099      * @see #getPrintable
    6100      *
    6101      * @since 1.5
    6102      */
    6103     public boolean print(PrintMode printMode) throws PrinterException {
    6104
    6105         return print(printMode, null, null);
    6106     }
    6107
    6108     /**
    6109      * A convenience method that displays a printing dialog, and then prints
    6110      * this <code>JTable</code> in the given printing mode,
    6111      * with the specified header and footer text. A modal progress dialog,
    6112      * with an abort option, will be shown for the duration of printing.
    6113      * <p>
    6114      * Note: In headless mode, no dialogs are shown and printing
    6115      * occurs on the default printer.
    6116      *
    6117      * @param  printMode        the printing mode that the printable should use
    6118      * @param  headerFormat     a <code>MessageFormat</code> specifying the text
    6119      *                          to be used in printing a header,
    6120      *                          or null for none
    6121      * @param  footerFormat     a <code>MessageFormat</code> specifying the text
    6122      *                          to be used in printing a footer,
    6123      *                          or null for none
    6124      * @return true, unless printing is cancelled by the user
    6125      * @throws SecurityException if this thread is not allowed to
    6126      *                           initiate a print job request
    6127      * @throws PrinterException if an error in the print system causes the job
    6128      *                          to be aborted
    6129      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
    6130      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
    6131      * @see #getPrintable
    6132      *
    6133      * @since 1.5
    6134      */
    6135     public boolean print(PrintMode printMode,
    6136                          MessageFormat headerFormat,
    6137                          MessageFormat footerFormat) throws PrinterException {
    6138
    6139         boolean showDialogs = !GraphicsEnvironment.isHeadless();
    6140         return print(printMode, headerFormat, footerFormat,
    6141                      showDialogs, null, showDialogs);
    6142     }
    6143
    6144     /**
    6145      * Prints this table, as specified by the fully featured
    6146      * {@link #print(JTable.PrintMode, MessageFormat, MessageFormat,
    6147      * boolean, PrintRequestAttributeSet, boolean, PrintService) print}
    6148      * method, with the default printer specified as the print service.
    6149      *
    6150      * @param  printMode        the printing mode that the printable should use
    6151      * @param  headerFormat     a <code>MessageFormat</code> specifying the text
    6152      *                          to be used in printing a header,
    6153      *                          or <code>null</code> for none
    6154      * @param  footerFormat     a <code>MessageFormat</code> specifying the text
    6155      *                          to be used in printing a footer,
    6156      *                          or <code>null</code> for none
    6157      * @param  showPrintDialog  whether or not to display a print dialog
    6158      * @param  attr             a <code>PrintRequestAttributeSet</code>
    6159      *                          specifying any printing attributes,
    6160      *                          or <code>null</code> for none
    6161      * @param  interactive      whether or not to print in an interactive mode
    6162      * @return true, unless printing is cancelled by the user
    6163      * @throws HeadlessException if the method is asked to show a printing
    6164      *                           dialog or run interactively, and
    6165      *                           <code>GraphicsEnvironment.isHeadless</code>
    6166      *                           returns <code>true</code>
    6167      * @throws SecurityException if this thread is not allowed to
    6168      *                           initiate a print job request
    6169      * @throws PrinterException if an error in the print system causes the job
    6170      *                          to be aborted
    6171      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
    6172      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
    6173      * @see #getPrintable
    6174      *
    6175      * @since 1.5
    6176      */
    6177     public boolean print(PrintMode printMode,
    6178                          MessageFormat headerFormat,
    6179                          MessageFormat footerFormat,
    6180                          boolean showPrintDialog,
    6181                          PrintRequestAttributeSet attr,
    6182                          boolean interactive) throws PrinterException,
    6183                                                      HeadlessException {
    6184
    6185         return print(printMode,
    6186                      headerFormat,
    6187                      footerFormat,
    6188                      showPrintDialog,
    6189                      attr,
    6190                      interactive,
    6191                      null);
    6192     }
    6193
    6194     /**
    6195      * Prints this <code>JTable</code>. Takes steps that the majority of
    6196      * developers would take in order to print a <code>JTable</code>.
    6197      * In short, it prepares the table, calls <code>getPrintable</code> to
    6198      * fetch an appropriate <code>Printable</code>, and then sends it to the
    6199      * printer.
    6200      * <p>
    6201      * A <code>boolean</code> parameter allows you to specify whether or not
    6202      * a printing dialog is displayed to the user. When it is, the user may
    6203      * use the dialog to change the destination printer or printing attributes,
    6204      * or even to cancel the print. Another two parameters allow for a
    6205      * <code>PrintService</code> and printing attributes to be specified.
    6206      * These parameters can be used either to provide initial values for the
    6207      * print dialog, or to specify values when the dialog is not shown.
    6208      * <p>
    6209      * A second <code>boolean</code> parameter allows you to specify whether
    6210      * or not to perform printing in an interactive mode. If <code>true</code>,
    6211      * a modal progress dialog, with an abort option, is displayed for the
    6212      * duration of printing . This dialog also prevents any user action which
    6213      * may affect the table. However, it can not prevent the table from being
    6214      * modified by code (for example, another thread that posts updates using
    6215      * <code>SwingUtilities.invokeLater</code>). It is therefore the
    6216      * responsibility of the developer to ensure that no other code modifies
    6217      * the table in any way during printing (invalid modifications include
    6218      * changes in: size, renderers, or underlying data). Printing behavior is
    6219      * undefined when the table is changed during printing.
    6220      * <p>
    6221      * If <code>false</code> is specified for this parameter, no dialog will
    6222      * be displayed and printing will begin immediately on the event-dispatch
    6223      * thread. This blocks any other events, including repaints, from being
    6224      * processed until printing is complete. Although this effectively prevents
    6225      * the table from being changed, it doesn't provide a good user experience.
    6226      * For this reason, specifying <code>false</code> is only recommended when
    6227      * printing from an application with no visible GUI.
    6228      * <p>
    6229      * Note: Attempting to show the printing dialog or run interactively, while
    6230      * in headless mode, will result in a <code>HeadlessException</code>.
    6231      * <p>
    6232      * Before fetching the printable, this method will gracefully terminate
    6233      * editing, if necessary, to prevent an editor from showing in the printed
    6234      * result. Additionally, <code>JTable</code> will prepare its renderers
    6235      * during printing such that selection and focus are not indicated.
    6236      * As far as customizing further how the table looks in the printout,
    6237      * developers can provide custom renderers or paint code that conditionalize
    6238      * on the value of {@link javax.swing.JComponent#isPaintingForPrint()}.
    6239      * <p>
    6240      * See {@link #getPrintable} for more description on how the table is
    6241      * printed.
    6242      *
    6243      * @param  printMode        the printing mode that the printable should use
    6244      * @param  headerFormat     a <code>MessageFormat</code> specifying the text
    6245      *                          to be used in printing a header,
    6246      *                          or <code>null</code> for none
    6247      * @param  footerFormat     a <code>MessageFormat</code> specifying the text
    6248      *                          to be used in printing a footer,
    6249      *                          or <code>null</code> for none
    6250      * @param  showPrintDialog  whether or not to display a print dialog
    6251      * @param  attr             a <code>PrintRequestAttributeSet</code>
    6252      *                          specifying any printing attributes,
    6253      *                          or <code>null</code> for none
    6254      * @param  interactive      whether or not to print in an interactive mode
    6255      * @param  service          the destination <code>PrintService</code>,
    6256      *                          or <code>null</code> to use the default printer
    6257      * @return true, unless printing is cancelled by the user
    6258      * @throws HeadlessException if the method is asked to show a printing
    6259      *                           dialog or run interactively, and
    6260      *                           <code>GraphicsEnvironment.isHeadless</code>
    6261      *                           returns <code>true</code>
    6262      * @throws  SecurityException if a security manager exists and its
    6263      *          {@link java.lang.SecurityManager#checkPrintJobAccess}
    6264      *          method disallows this thread from creating a print job request
    6265      * @throws PrinterException if an error in the print system causes the job
    6266      *                          to be aborted
    6267      * @see #getPrintable
    6268      * @see java.awt.GraphicsEnvironment#isHeadless
    6269      *
    6270      * @since 1.6
    6271      */
    6272     public boolean print(PrintMode printMode,
    6273                          MessageFormat headerFormat,
    6274                          MessageFormat footerFormat,
    6275                          boolean showPrintDialog,
    6276                          PrintRequestAttributeSet attr,
    6277                          boolean interactive,
    6278                          PrintService service) throws PrinterException,
    6279                                                       HeadlessException {
    6280
    6281         // complain early if an invalid parameter is specified for headless mode
    6282         boolean isHeadless = GraphicsEnvironment.isHeadless();
    6283         if (isHeadless) {
    6284             if (showPrintDialog) {
    6285                 throw new HeadlessException("Can't show print dialog.");
    6286             }
    6287
    6288             if (interactive) {
    6289                 throw new HeadlessException("Can't run interactively.");
    6290             }
    6291         }
    6292
    6293         // Get a PrinterJob.
    6294         // Do this before anything with side-effects since it may throw a
    6295         // security exception - in which case we don't want to do anything else.
    6296         final PrinterJob job = PrinterJob.getPrinterJob();
    6297
    6298         if (isEditing()) {
    6299             // try to stop cell editing, and failing that, cancel it
    6300             if (!getCellEditor().stopCellEditing()) {
    6301                 getCellEditor().cancelCellEditing();
    6302             }
    6303         }
    6304
    6305         if (attr == null) {
    6306             attr = new HashPrintRequestAttributeSet();
    6307         }
    6308
    6309         final PrintingStatus printingStatus;
    6310
    6311          // fetch the Printable
    6312         Printable printable =
    6313              getPrintable(printMode, headerFormat, footerFormat);
    6314
    6315         if (interactive) {
    6316             // wrap the Printable so that we can print on another thread
    6317             printable = new ThreadSafePrintable(printable);
    6318             printingStatus = PrintingStatus.createPrintingStatus(this, job);
    6319             printable = printingStatus.createNotificationPrintable(printable);
    6320         } else {
    6321             // to please compiler
    6322             printingStatus = null;
    6323         }
    6324
    6325         // set the printable on the PrinterJob
    6326         job.setPrintable(printable);
    6327
    6328         // if specified, set the PrintService on the PrinterJob
    6329         if (service != null) {
    6330             job.setPrintService(service);
    6331         }
    6332
    6333         // if requested, show the print dialog
    6334         if (showPrintDialog && !job.printDialog(attr)) {
    6335             // the user cancelled the print dialog
    6336             return false;
    6337         }
    6338
    6339         // if not interactive, just print on this thread (no dialog)
    6340         if (!interactive) {
    6341             // do the printing
    6342             job.print(attr);
    6343
    6344             // we're done
    6345             return true;
    6346         }
    6347
    6348         // make sure this is clear since we'll check it after
    6349         printError = null;
    6350
    6351         // to synchronize on
    6352         final Object lock = new Object();
    6353
    6354         // copied so we can access from the inner class
    6355         final PrintRequestAttributeSet copyAttr = attr;
    6356
    6357         // this runnable will be used to do the printing
    6358         // (and save any throwables) on another thread
    6359         Runnable runnable = () -> {
    6360             try {
    6361                 // do the printing
    6362                 job.print(copyAttr);
    6363             } catch (Throwable t) {
    6364                 // save any Throwable to be rethrown
    6365                 synchronized(lock) {
    6366                     printError = t;
    6367                 }
    6368             } finally {
    6369                 // we're finished - hide the dialog
    6370                 printingStatus.dispose();
    6371             }
    6372         };
    6373
    6374         // start printing on another thread
    6375         Thread th = new Thread(null, runnable, "JTablePrint", 0, false);
    6376         th.start();
    6377
    6378         printingStatus.showModal(true);
    6379
    6380         // look for any error that the printing may have generated
    6381         Throwable pe;
    6382         synchronized(lock) {
    6383             pe = printError;
    6384             printError = null;
    6385         }
    6386
    6387         // check the type of error and handle it
    6388         if (pe != null) {
    6389             // a subclass of PrinterException meaning the job was aborted,
    6390             // in this case, by the user
    6391             if (pe instanceof PrinterAbortException) {
    6392                 return false;
    6393             } else if (pe instanceof PrinterException) {
    6394                 throw (PrinterException)pe;
    6395             } else if (pe instanceof RuntimeException) {
    6396                 throw (RuntimeException)pe;
    6397             } else if (pe instanceof Error) {
    6398                 throw (Error)pe;
    6399             }
    6400
    6401             // can not happen
    6402             throw new AssertionError(pe);
    6403         }
    6404
    6405         return true;
    6406     }
    6407
    6408     /**
    6409      * Return a <code>Printable</code> for use in printing this JTable.
    6410      * <p>
    6411      * This method is meant for those wishing to customize the default
    6412      * <code>Printable</code> implementation used by <code>JTable</code>'s
    6413      * <code>print</code> methods. Developers wanting simply to print the table
    6414      * should use one of those methods directly.
    6415      * <p>
    6416      * The <code>Printable</code> can be requested in one of two printing modes.
    6417      * In both modes, it spreads table rows naturally in sequence across
    6418      * multiple pages, fitting as many rows as possible per page.
    6419      * <code>PrintMode.NORMAL</code> specifies that the table be
    6420      * printed at its current size. In this mode, there may be a need to spread
    6421      * columns across pages in a similar manner to that of the rows. When the
    6422      * need arises, columns are distributed in an order consistent with the
    6423      * table's <code>ComponentOrientation</code>.
    6424      * <code>PrintMode.FIT_WIDTH</code> specifies that the output be
    6425      * scaled smaller, if necessary, to fit the table's entire width
    6426      * (and thereby all columns) on each page. Width and height are scaled
    6427      * equally, maintaining the aspect ratio of the output.
    6428      * <p>
    6429      * The <code>Printable</code> heads the portion of table on each page
    6430      * with the appropriate section from the table's <code>JTableHeader</code>,
    6431      * if it has one.
    6432      * <p>
    6433      * Header and footer text can be added to the output by providing
    6434      * <code>MessageFormat</code> arguments. The printing code requests
    6435      * Strings from the formats, providing a single item which may be included
    6436      * in the formatted string: an <code>Integer</code> representing the current
    6437      * page number.
    6438      * <p>
    6439      * You are encouraged to read the documentation for
    6440      * <code>MessageFormat</code> as some characters, such as single-quote,
    6441      * are special and need to be escaped.
    6442      * <p>
    6443      * Here's an example of creating a <code>MessageFormat</code> that can be
    6444      * used to print "Duke's Table: Page - " and the current page number:
    6445      *
    6446      * <pre>
    6447      *     // notice the escaping of the single quote
    6448      *     // notice how the page number is included with "{0}"
    6449      *     MessageFormat format = new MessageFormat("Duke''s Table: Page - {0}");
    6450      * </pre>
    6451      * <p>
    6452      * The <code>Printable</code> constrains what it draws to the printable
    6453      * area of each page that it prints. Under certain circumstances, it may
    6454      * find it impossible to fit all of a page's content into that area. In
    6455      * these cases the output may be clipped, but the implementation
    6456      * makes an effort to do something reasonable. Here are a few situations
    6457      * where this is known to occur, and how they may be handled by this
    6458      * particular implementation:
    6459      * <ul>
    6460      *   <li>In any mode, when the header or footer text is too wide to fit
    6461      *       completely in the printable area -- print as much of the text as
    6462      *       possible starting from the beginning, as determined by the table's
    6463      *       <code>ComponentOrientation</code>.
    6464      *   <li>In any mode, when a row is too tall to fit in the
    6465      *       printable area -- print the upper-most portion of the row
    6466      *       and paint no lower border on the table.
    6467      *   <li>In <code>PrintMode.NORMAL</code> when a column
    6468      *       is too wide to fit in the printable area -- print the center
    6469      *       portion of the column and leave the left and right borders
    6470      *       off the table.
    6471      * </ul>
    6472      * <p>
    6473      * It is entirely valid for this <code>Printable</code> to be wrapped
    6474      * inside another in order to create complex reports and documents. You may
    6475      * even request that different pages be rendered into different sized
    6476      * printable areas. The implementation must be prepared to handle this
    6477      * (possibly by doing its layout calculations on the fly). However,
    6478      * providing different heights to each page will likely not work well
    6479      * with <code>PrintMode.NORMAL</code> when it has to spread columns
    6480      * across pages.
    6481      * <p>
    6482      * As far as customizing how the table looks in the printed result,
    6483      * <code>JTable</code> itself will take care of hiding the selection
    6484      * and focus during printing. For additional customizations, your
    6485      * renderers or painting code can customize the look based on the value
    6486      * of {@link javax.swing.JComponent#isPaintingForPrint()}
    6487      * <p>
    6488      * Also, <i>before</i> calling this method you may wish to <i>first</i>
    6489      * modify the state of the table, such as to cancel cell editing or
    6490      * have the user size the table appropriately. However, you must not
    6491      * modify the state of the table <i>after</i> this <code>Printable</code>
    6492      * has been fetched (invalid modifications include changes in size or
    6493      * underlying data). The behavior of the returned <code>Printable</code>
    6494      * is undefined once the table has been changed.
    6495      *
    6496      * @param  printMode     the printing mode that the printable should use
    6497      * @param  headerFormat  a <code>MessageFormat</code> specifying the text to
    6498      *                       be used in printing a header, or null for none
    6499      * @param  footerFormat  a <code>MessageFormat</code> specifying the text to
    6500      *                       be used in printing a footer, or null for none
    6501      * @return a <code>Printable</code> for printing this JTable
    6502      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
    6503      *             boolean, PrintRequestAttributeSet, boolean)
    6504      * @see Printable
    6505      * @see PrinterJob
    6506      *
    6507      * @since 1.5
    6508      */
    6509     public Printable getPrintable(PrintMode printMode,
    6510                                   MessageFormat headerFormat,
    6511                                   MessageFormat footerFormat) {
    6512
    6513         return new TablePrintable(this, printMode, headerFormat, footerFormat);
    6514     }
    6515
    6516
    6517     /**
    6518      * A <code>Printable</code> implementation that wraps another
    6519      * <code>Printable</code>, making it safe for printing on another thread.
    6520      */
    6521     private class ThreadSafePrintable implements Printable {
    6522
    6523         /** The delegate <code>Printable</code>. */
    6524         private Printable printDelegate;
    6525
    6526         /**
    6527          * To communicate any return value when delegating.
    6528          */
    6529         private int retVal;
    6530
    6531         /**
    6532          * To communicate any <code>Throwable</code> when delegating.
    6533          */
    6534         private Throwable retThrowable;
    6535
    6536         /**
    6537          * Construct a <code>ThreadSafePrintable</code> around the given
    6538          * delegate.
    6539          *
    6540          * @param printDelegate the <code>Printable</code> to delegate to
    6541          */
    6542         public ThreadSafePrintable(Printable printDelegate) {
    6543             this.printDelegate = printDelegate;
    6544         }
    6545
    6546         /**
    6547          * Prints the specified page into the given {@link Graphics}
    6548          * context, in the specified format.
    6549          * <p>
    6550          * Regardless of what thread this method is called on, all calls into
    6551          * the delegate will be done on the event-dispatch thread.
    6552          *
    6553          * @param   graphics    the context into which the page is drawn
    6554          * @param   pageFormat  the size and orientation of the page being drawn
    6555          * @param   pageIndex   the zero based index of the page to be drawn
    6556          * @return  PAGE_EXISTS if the page is rendered successfully, or
    6557          *          NO_SUCH_PAGE if a non-existent page index is specified
    6558          * @throws  PrinterException if an error causes printing to be aborted
    6559          */
    6560         public int print(final Graphics graphics,
    6561                          final PageFormat pageFormat,
    6562                          final int pageIndex) throws PrinterException {
    6563
    6564             // We'll use this Runnable
    6565             Runnable runnable = new Runnable() {
    6566                 public synchronized void run() {
    6567                     try {
    6568                         // call into the delegate and save the return value
    6569                         retVal = printDelegate.print(graphics, pageFormat, pageIndex);
    6570                     } catch (Throwable throwable) {
    6571                         // save any Throwable to be rethrown
    6572                         retThrowable = throwable;
    6573                     } finally {
    6574                         // notify the caller that we're done
    6575                         notifyAll();
    6576                     }
    6577                 }
    6578             };
    6579
    6580             synchronized(runnable) {
    6581                 // make sure these are initialized
    6582                 retVal = -1;
    6583                 retThrowable = null;
    6584
    6585                 // call into the EDT
    6586                 SwingUtilities.invokeLater(runnable);
    6587
    6588                 // wait for the runnable to finish
    6589                 while (retVal == -1 && retThrowable == null) {
    6590                     try {
    6591                         runnable.wait();
    6592                     } catch (InterruptedException ie) {
    6593                         // short process, safe to ignore interrupts
    6594                     }
    6595                 }
    6596
    6597                 // if the delegate threw a throwable, rethrow it here
    6598                 if (retThrowable != null) {
    6599                     if (retThrowable instanceof PrinterException) {
    6600                         throw (PrinterException)retThrowable;
    6601                     } else if (retThrowable instanceof RuntimeException) {
    6602                         throw (RuntimeException)retThrowable;
    6603                     } else if (retThrowable instanceof Error) {
    6604                         throw (Error)retThrowable;
    6605                     }
    6606
    6607                     // can not happen
    6608                     throw new AssertionError(retThrowable);
    6609                 }
    6610
    6611                 return retVal;
    6612             }
    6613         }
    6614     }
    6615
    6616 /////////////////
    6617 // Accessibility support
    6618 ////////////////
    6619
    6620     /**
    6621      * Gets the AccessibleContext associated with this JTable.
    6622      * For tables, the AccessibleContext takes the form of an
    6623      * AccessibleJTable.
    6624      * A new AccessibleJTable instance is created if necessary.
    6625      *
    6626      * @return an AccessibleJTable that serves as the
    6627      *         AccessibleContext of this JTable
    6628      */
    6629     @BeanProperty(bound = false)
    6630     public AccessibleContext getAccessibleContext() {
    6631         if (accessibleContext == null) {
    6632             accessibleContext = new AccessibleJTable();
    6633         }
    6634         return accessibleContext;
    6635     }
    6636
    6637     //
    6638     // *** should also implement AccessibleSelection?
    6639     // *** and what's up with keyboard navigation/manipulation?
    6640     //
    6641     /**
    6642      * This class implements accessibility support for the
    6643      * <code>JTable</code> class.  It provides an implementation of the
    6644      * Java Accessibility API appropriate to table user-interface elements.
    6645      * <p>
    6646      * <strong>Warning:</strong>
    6647      * Serialized objects of this class will not be compatible with
    6648      * future Swing releases. The current serialization support is
    6649      * appropriate for short term storage or RMI between applications running
    6650      * the same version of Swing.  As of 1.4, support for long term storage
    6651      * of all JavaBeans&trade;
    6652      * has been added to the <code>java.beans</code> package.
    6653      * Please see {@link java.beans.XMLEncoder}.
    6654      */
    6655     @SuppressWarnings("serial") // Same-version serialization only
    6656     protected class AccessibleJTable extends AccessibleJComponent
    6657     implements AccessibleSelection, ListSelectionListener, TableModelListener,
    6658     TableColumnModelListener, CellEditorListener, PropertyChangeListener,
    6659     AccessibleExtendedTable {
    6660
    6661         int previousFocusedRow;
    6662         int previousFocusedCol;
    6663
    6664         /**
    6665          * AccessibleJTable constructor
    6666          *
    6667          * @since 1.5
    6668          */
    6669         protected AccessibleJTable() {
    6670             super();
    6671             JTable.this.addPropertyChangeListener(this);
    6672             JTable.this.getSelectionModel().addListSelectionListener(this);
    6673             TableColumnModel tcm = JTable.this.getColumnModel();
    6674             tcm.addColumnModelListener(this);
    6675             tcm.getSelectionModel().addListSelectionListener(this);
    6676             JTable.this.getModel().addTableModelListener(this);
    6677             previousFocusedRow = JTable.this.getSelectionModel().
    6678                                         getLeadSelectionIndex();
    6679             previousFocusedCol = JTable.this.getColumnModel().
    6680                                         getSelectionModel().getLeadSelectionIndex();
    6681         }
    6682
    6683     // Listeners to track model, etc. changes to as to re-place the other
    6684     // listeners
    6685
    6686         /**
    6687          * Track changes to selection model, column model, etc. so as to
    6688          * be able to re-place listeners on those in order to pass on
    6689          * information to the Accessibility PropertyChange mechanism
    6690          */
    6691         public void propertyChange(PropertyChangeEvent e) {
    6692             String name = e.getPropertyName();
    6693             Object oldValue = e.getOldValue();
    6694             Object newValue = e.getNewValue();
    6695
    6696                 // re-set tableModel listeners
    6697             if (name.compareTo("model") == 0) {
    6698
    6699                 if (oldValue != null && oldValue instanceof TableModel) {
    6700                     ((TableModel) oldValue).removeTableModelListener(this);
    6701                 }
    6702                 if (newValue != null && newValue instanceof TableModel) {
    6703                     ((TableModel) newValue).addTableModelListener(this);
    6704                 }
    6705
    6706                 // re-set selectionModel listeners
    6707             } else if (name.compareTo("selectionModel") == 0) {
    6708
    6709                 Object source = e.getSource();
    6710                 if (source == JTable.this) {    // row selection model
    6711
    6712                     if (oldValue != null &&
    6713                         oldValue instanceof ListSelectionModel) {
    6714                         ((ListSelectionModel) oldValue).removeListSelectionListener(this);
    6715                     }
    6716                     if (newValue != null &&
    6717                         newValue instanceof ListSelectionModel) {
    6718                         ((ListSelectionModel) newValue).addListSelectionListener(this);
    6719                     }
    6720
    6721                 } else if (source == JTable.this.getColumnModel()) {
    6722
    6723                     if (oldValue != null &&
    6724                         oldValue instanceof ListSelectionModel) {
    6725                         ((ListSelectionModel) oldValue).removeListSelectionListener(this);
    6726                     }
    6727                     if (newValue != null &&
    6728                         newValue instanceof ListSelectionModel) {
    6729                         ((ListSelectionModel) newValue).addListSelectionListener(this);
    6730                     }
    6731
    6732                 } else {
    6733                   //        System.out.println("!!! Bug in source of selectionModel propertyChangeEvent");
    6734                 }
    6735
    6736                 // re-set columnModel listeners
    6737                 // and column's selection property listener as well
    6738             } else if (name.compareTo("columnModel") == 0) {
    6739
    6740                 if (oldValue != null && oldValue instanceof TableColumnModel) {
    6741                     TableColumnModel tcm = (TableColumnModel) oldValue;
    6742                     tcm.removeColumnModelListener(this);
    6743                     tcm.getSelectionModel().removeListSelectionListener(this);
    6744                 }
    6745                 if (newValue != null && newValue instanceof TableColumnModel) {
    6746                     TableColumnModel tcm = (TableColumnModel) newValue;
    6747                     tcm.addColumnModelListener(this);
    6748                     tcm.getSelectionModel().addListSelectionListener(this);
    6749                 }
    6750
    6751                 // re-se cellEditor listeners
    6752             } else if (name.compareTo("tableCellEditor") == 0) {
    6753
    6754                 if (oldValue != null && oldValue instanceof TableCellEditor) {
    6755                     ((TableCellEditor) oldValue).removeCellEditorListener(this);
    6756                 }
    6757                 if (newValue != null && newValue instanceof TableCellEditor) {
    6758                     ((TableCellEditor) newValue).addCellEditorListener(this);
    6759                 }
    6760             }
    6761         }
    6762
    6763
    6764     // Listeners to echo changes to the AccessiblePropertyChange mechanism
    6765
    6766         /**
    6767          * Describes a change in the accessible table model.
    6768          */
    6769         protected class AccessibleJTableModelChange
    6770             implements AccessibleTableModelChange {
    6771
    6772             /** The type */
    6773             protected int type;
    6774             /** The first row */
    6775             protected int firstRow;
    6776             /** The last row */
    6777             protected int lastRow;
    6778             /** The first column */
    6779             protected int firstColumn;
    6780             /** The last column */
    6781             protected int lastColumn;
    6782
    6783             /**
    6784              * Constructs an {@code AccessibleJTableModelChange}.
    6785              * @param type the type
    6786              * @param firstRow the first row
    6787              * @param lastRow the last row
    6788              * @param firstColumn the first column
    6789              * @param lastColumn the last column
    6790              */
    6791             protected AccessibleJTableModelChange(int type, int firstRow,
    6792                                                   int lastRow, int firstColumn,
    6793                                                   int lastColumn) {
    6794                 this.type = type;
    6795                 this.firstRow = firstRow;
    6796                 this.lastRow = lastRow;
    6797                 this.firstColumn = firstColumn;
    6798                 this.lastColumn = lastColumn;
    6799             }
    6800
    6801             /**
    6802              * Returns the type.
    6803              * @return the type
    6804              */
    6805             public int getType() {
    6806                 return type;
    6807             }
    6808
    6809             /**
    6810              * Returns the first row.
    6811              * @return the first row
    6812              */
    6813             public int getFirstRow() {
    6814                 return firstRow;
    6815             }
    6816
    6817             /**
    6818              * Returns the last row.
    6819              * @return the last row
    6820              */
    6821             public int getLastRow() {
    6822                 return lastRow;
    6823             }
    6824
    6825             /**
    6826              * Returns the first column.
    6827              * @return the first column
    6828              */
    6829             public int getFirstColumn() {
    6830                 return firstColumn;
    6831             }
    6832
    6833             /**
    6834              * Returns the last column.
    6835              * @return the last column
    6836              */
    6837             public int getLastColumn() {
    6838                 return lastColumn;
    6839             }
    6840         }
    6841
    6842         /**
    6843          * Track changes to the table contents
    6844          *
    6845          * @param e a {@code TableModelEvent} describing the event
    6846          */
    6847         public void tableChanged(TableModelEvent e) {
    6848            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
    6849                               null, null);
    6850            if (e != null) {
    6851                int firstColumn = e.getColumn();
    6852                int lastColumn = e.getColumn();
    6853                if (firstColumn == TableModelEvent.ALL_COLUMNS) {
    6854                    firstColumn = 0;
    6855                    lastColumn = getColumnCount() - 1;
    6856                }
    6857
    6858                // Fire a property change event indicating the table model
    6859                // has changed.
    6860                AccessibleJTableModelChange change =
    6861                    new AccessibleJTableModelChange(e.getType(),
    6862                                                    e.getFirstRow(),
    6863                                                    e.getLastRow(),
    6864                                                    firstColumn,
    6865                                                    lastColumn);
    6866                firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
    6867                                   null, change);
    6868             }
    6869         }
    6870
    6871         /**
    6872          * Track changes to the table contents (row insertions)
    6873          *
    6874          * @param e a {@code TableModelEvent} describing the event
    6875          */
    6876         public void tableRowsInserted(TableModelEvent e) {
    6877            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
    6878                               null, null);
    6879
    6880            // Fire a property change event indicating the table model
    6881            // has changed.
    6882            int firstColumn = e.getColumn();
    6883            int lastColumn = e.getColumn();
    6884            if (firstColumn == TableModelEvent.ALL_COLUMNS) {
    6885                firstColumn = 0;
    6886                lastColumn = getColumnCount() - 1;
    6887            }
    6888            AccessibleJTableModelChange change =
    6889                new AccessibleJTableModelChange(e.getType(),
    6890                                                e.getFirstRow(),
    6891                                                e.getLastRow(),
    6892                                                firstColumn,
    6893                                                lastColumn);
    6894            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
    6895                               null, change);
    6896         }
    6897
    6898         /**
    6899          * Track changes to the table contents (row deletions)
    6900          *
    6901          * @param e a {@code TableModelEvent} describing the event
    6902          */
    6903         public void tableRowsDeleted(TableModelEvent e) {
    6904            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
    6905                               null, null);
    6906
    6907            // Fire a property change event indicating the table model
    6908            // has changed.
    6909            int firstColumn = e.getColumn();
    6910            int lastColumn = e.getColumn();
    6911            if (firstColumn == TableModelEvent.ALL_COLUMNS) {
    6912                firstColumn = 0;
    6913                lastColumn = getColumnCount() - 1;
    6914            }
    6915            AccessibleJTableModelChange change =
    6916                new AccessibleJTableModelChange(e.getType(),
    6917                                                e.getFirstRow(),
    6918                                                e.getLastRow(),
    6919                                                firstColumn,
    6920                                                lastColumn);
    6921            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
    6922                               null, change);
    6923         }
    6924
    6925         /**
    6926          * Track changes to the table contents (column insertions)
    6927          */
    6928         public void columnAdded(TableColumnModelEvent 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 type = AccessibleTableModelChange.INSERT;
    6935            AccessibleJTableModelChange change =
    6936                new AccessibleJTableModelChange(type,
    6937                                                0,
    6938                                                0,
    6939                                                e.getFromIndex(),
    6940                                                e.getToIndex());
    6941            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
    6942                               null, change);
    6943         }
    6944
    6945         /**
    6946          * Track changes to the table contents (column deletions)
    6947          */
    6948         public void columnRemoved(TableColumnModelEvent e) {
    6949            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
    6950                               null, null);
    6951            // Fire a property change event indicating the table model
    6952            // has changed.
    6953            int type = AccessibleTableModelChange.DELETE;
    6954            AccessibleJTableModelChange change =
    6955                new AccessibleJTableModelChange(type,
    6956                                                0,
    6957                                                0,
    6958                                                e.getFromIndex(),
    6959                                                e.getToIndex());
    6960            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
    6961                               null, change);
    6962         }
    6963
    6964         /**
    6965          * Track changes of a column repositioning.
    6966          *
    6967          * @see TableColumnModelListener
    6968          */
    6969         public void columnMoved(TableColumnModelEvent e) {
    6970            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
    6971                               null, null);
    6972
    6973            // Fire property change events indicating the table model
    6974            // has changed.
    6975            int type = AccessibleTableModelChange.DELETE;
    6976            AccessibleJTableModelChange change =
    6977                new AccessibleJTableModelChange(type,
    6978                                                0,
    6979                                                0,
    6980                                                e.getFromIndex(),
    6981                                                e.getFromIndex());
    6982            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
    6983                               null, change);
    6984
    6985            int type2 = AccessibleTableModelChange.INSERT;
    6986            AccessibleJTableModelChange change2 =
    6987                new AccessibleJTableModelChange(type2,
    6988                                                0,
    6989                                                0,
    6990                                                e.getToIndex(),
    6991                                                e.getToIndex());
    6992            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
    6993                               null, change2);
    6994         }
    6995
    6996         /**
    6997          * Track changes of a column moving due to margin changes.
    6998          *
    6999          * @see TableColumnModelListener
    7000          */
    7001         public void columnMarginChanged(ChangeEvent e) {
    7002            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
    7003                               null, null);
    7004         }
    7005
    7006         /**
    7007          * Track that the selection model of the TableColumnModel changed.
    7008          *
    7009          * @see TableColumnModelListener
    7010          */
    7011         public void columnSelectionChanged(ListSelectionEvent e) {
    7012             // we should now re-place our TableColumn listener
    7013         }
    7014
    7015         /**
    7016          * Track changes to a cell's contents.
    7017          *
    7018          * Invoked when editing is finished. The changes are saved, the
    7019          * editor object is discarded, and the cell is rendered once again.
    7020          *
    7021          * @see CellEditorListener
    7022          */
    7023         public void editingStopped(ChangeEvent e) {
    7024            // it'd be great if we could figure out which cell, and pass that
    7025            // somehow as a parameter
    7026            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
    7027                               null, null);
    7028         }
    7029
    7030         /**
    7031          * Invoked when editing is canceled. The editor object is discarded
    7032          * and the cell is rendered once again.
    7033          *
    7034          * @see CellEditorListener
    7035          */
    7036         public void editingCanceled(ChangeEvent e) {
    7037             // nothing to report, 'cause nothing changed
    7038         }
    7039
    7040         /**
    7041          * Track changes to table cell selections
    7042          */
    7043         public void valueChanged(ListSelectionEvent e) {
    7044             firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
    7045                             Boolean.valueOf(false), Boolean.valueOf(true));
    7046
    7047             // Using lead selection index to cover both cases: node selected and node
    7048             // is focused but not selected (Ctrl+up/down)
    7049             int focusedRow = JTable.this.getSelectionModel().getLeadSelectionIndex();
    7050             int focusedCol = JTable.this.getColumnModel().getSelectionModel().
    7051                                                     getLeadSelectionIndex();
    7052
    7053             if (focusedRow != previousFocusedRow ||
    7054                 focusedCol != previousFocusedCol) {
    7055                 Accessible oldA = getAccessibleAt(previousFocusedRow, previousFocusedCol);
    7056                 Accessible newA = getAccessibleAt(focusedRow, focusedCol);
    7057                 firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
    7058                                     oldA, newA);
    7059                 previousFocusedRow = focusedRow;
    7060                 previousFocusedCol = focusedCol;
    7061             }
    7062         }
    7063
    7064
    7065
    7066
    7067     // AccessibleContext support
    7068
    7069         /**
    7070          * Get the AccessibleSelection associated with this object.  In the
    7071          * implementation of the Java Accessibility API for this class,
    7072          * return this object, which is responsible for implementing the
    7073          * AccessibleSelection interface on behalf of itself.
    7074          *
    7075          * @return this object
    7076          */
    7077         public AccessibleSelection getAccessibleSelection() {
    7078             return this;
    7079         }
    7080
    7081         /**
    7082          * Gets the role of this object.
    7083          *
    7084          * @return an instance of AccessibleRole describing the role of the
    7085          * object
    7086          * @see AccessibleRole
    7087          */
    7088         public AccessibleRole getAccessibleRole() {
    7089             return AccessibleRole.TABLE;
    7090         }
    7091
    7092         /**
    7093          * Returns the <code>Accessible</code> child, if one exists,
    7094          * contained at the local coordinate <code>Point</code>.
    7095          *
    7096          * @param p the point defining the top-left corner of the
    7097          *    <code>Accessible</code>, given in the coordinate space
    7098          *    of the object's parent
    7099          * @return the <code>Accessible</code>, if it exists,
    7100          *    at the specified location; else <code>null</code>
    7101          */
    7102         public Accessible getAccessibleAt(Point p) {
    7103             int column = columnAtPoint(p);
    7104             int row = rowAtPoint(p);
    7105
    7106             if ((column != -1) && (row != -1)) {
    7107                 TableColumn aColumn = getColumnModel().getColumn(column);
    7108                 TableCellRenderer renderer = aColumn.getCellRenderer();
    7109                 if (renderer == null) {
    7110                     Class<?> columnClass = getColumnClass(column);
    7111                     renderer = getDefaultRenderer(columnClass);
    7112                 }
    7113                 Component component = renderer.getTableCellRendererComponent(
    7114                                   JTable.this, null, false, false,
    7115                                   row, column);
    7116                 return new AccessibleJTableCell(JTable.this, row, column,
    7117                       getAccessibleIndexAt(row, column));
    7118             }
    7119             return null;
    7120         }
    7121
    7122         /**
    7123          * Returns the number of accessible children in the object.  If all
    7124          * of the children of this object implement <code>Accessible</code>,
    7125          * then this method should return the number of children of this object.
    7126          *
    7127          * @return the number of accessible children in the object
    7128          */
    7129         public int getAccessibleChildrenCount() {
    7130             return (JTable.this.getColumnCount() * JTable.this.getRowCount());
    7131         }
    7132
    7133         /**
    7134          * Returns the nth <code>Accessible</code> child of the object.
    7135          *
    7136          * @param i zero-based index of child
    7137          * @return the nth Accessible child of the object
    7138          */
    7139         public Accessible getAccessibleChild(int i) {
    7140             if (i < 0 || i >= getAccessibleChildrenCount()) {
    7141                 return null;
    7142             } else {
    7143                 // children increase across, and then down, for tables
    7144                 // (arbitrary decision)
    7145                 int column = getAccessibleColumnAtIndex(i);
    7146                 int row = getAccessibleRowAtIndex(i);
    7147
    7148                 TableColumn aColumn = getColumnModel().getColumn(column);
    7149                 TableCellRenderer renderer = aColumn.getCellRenderer();
    7150                 if (renderer == null) {
    7151                     Class<?> columnClass = getColumnClass(column);
    7152                     renderer = getDefaultRenderer(columnClass);
    7153                 }
    7154                 Component component = renderer.getTableCellRendererComponent(
    7155                                   JTable.this, null, false, false,
    7156                                   row, column);
    7157                 return new AccessibleJTableCell(JTable.this, row, column,
    7158                       getAccessibleIndexAt(row, column));
    7159             }
    7160         }
    7161
    7162     // AccessibleSelection support
    7163
    7164         /**
    7165          * Returns the number of <code>Accessible</code> children
    7166          * currently selected.
    7167          * If no children are selected, the return value will be 0.
    7168          *
    7169          * @return the number of items currently selected
    7170          */
    7171         public int getAccessibleSelectionCount() {
    7172             int rowsSel = JTable.this.getSelectedRowCount();
    7173             int colsSel = JTable.this.getSelectedColumnCount();
    7174
    7175             if (JTable.this.cellSelectionEnabled) { // a contiguous block
    7176                 return rowsSel * colsSel;
    7177
    7178             } else {
    7179                 // a column swath and a row swath, with a shared block
    7180                 if (JTable.this.getRowSelectionAllowed() &&
    7181                     JTable.this.getColumnSelectionAllowed()) {
    7182                     return rowsSel * JTable.this.getColumnCount() +
    7183                            colsSel * JTable.this.getRowCount() -
    7184                            rowsSel * colsSel;
    7185
    7186                 // just one or more rows in selection
    7187                 } else if (JTable.this.getRowSelectionAllowed()) {
    7188                     return rowsSel * JTable.this.getColumnCount();
    7189
    7190                 // just one or more rows in selection
    7191                 } else if (JTable.this.getColumnSelectionAllowed()) {
    7192                     return colsSel * JTable.this.getRowCount();
    7193
    7194                 } else {
    7195                     return 0;    // JTable doesn't allow selections
    7196                 }
    7197             }
    7198         }
    7199
    7200         /**
    7201          * Returns an <code>Accessible</code> representing the
    7202          * specified selected child in the object.  If there
    7203          * isn't a selection, or there are fewer children selected
    7204          * than the integer passed in, the return
    7205          * value will be <code>null</code>.
    7206          * <p>Note that the index represents the i-th selected child, which
    7207          * is different from the i-th child.
    7208          *
    7209          * @param i the zero-based index of selected children
    7210          * @return the i-th selected child
    7211          * @see #getAccessibleSelectionCount
    7212          */
    7213         public Accessible getAccessibleSelection(int i) {
    7214             if (i < 0 || i > getAccessibleSelectionCount()) {
    7215                 return null;
    7216             }
    7217
    7218             int rowsSel = JTable.this.getSelectedRowCount();
    7219             int colsSel = JTable.this.getSelectedColumnCount();
    7220             int rowIndicies[] = getSelectedRows();
    7221             int colIndicies[] = getSelectedColumns();
    7222             int ttlCols = JTable.this.getColumnCount();
    7223             int ttlRows = JTable.this.getRowCount();
    7224             int r;
    7225             int c;
    7226
    7227             if (JTable.this.cellSelectionEnabled) { // a contiguous block
    7228                 r = rowIndicies[i / colsSel];
    7229                 c = colIndicies[i % colsSel];
    7230                 return getAccessibleChild((r * ttlCols) + c);
    7231             } else {
    7232
    7233                 // a column swath and a row swath, with a shared block
    7234                 if (JTable.this.getRowSelectionAllowed() &&
    7235                     JTable.this.getColumnSelectionAllowed()) {
    7236
    7237                     // Situation:
    7238                     //   We have a table, like the 6x3 table below,
    7239                     //   wherein three colums and one row selected
    7240                     //   (selected cells marked with "*", unselected "0"):
    7241                     //
    7242                     //            0 * 0 * * 0
    7243                     //            * * * * * *
    7244                     //            0 * 0 * * 0
    7245                     //
    7246
    7247                     // State machine below walks through the array of
    7248                     // selected rows in two states: in a selected row,
    7249                     // and not in one; continuing until we are in a row
    7250                     // in which the ith selection exists.  Then we return
    7251                     // the appropriate cell.  In the state machine, we
    7252                     // always do rows above the "current" selected row first,
    7253                     // then the cells in the selected row.  If we're done
    7254                     // with the state machine before finding the requested
    7255                     // selected child, we handle the rows below the last
    7256                     // selected row at the end.
    7257                     //
    7258                     int curIndex = i;
    7259                     final int IN_ROW = 0;
    7260                     final int NOT_IN_ROW = 1;
    7261                     int state = (rowIndicies[0] == 0 ? IN_ROW : NOT_IN_ROW);
    7262                     int j = 0;
    7263                     int prevRow = -1;
    7264                     while (j < rowIndicies.length) {
    7265                         switch (state) {
    7266
    7267                         case IN_ROW:   // on individual row full of selections
    7268                             if (curIndex < ttlCols) { // it's here!
    7269                                 c = curIndex % ttlCols;
    7270                                 r = rowIndicies[j];
    7271                                 return getAccessibleChild((r * ttlCols) + c);
    7272                             } else {                               // not here
    7273                                 curIndex -= ttlCols;
    7274                             }
    7275                             // is the next row in table selected or not?
    7276                             if (j + 1 == rowIndicies.length ||
    7277                                 rowIndicies[j] != rowIndicies[j+1] - 1) {
    7278                                 state = NOT_IN_ROW;
    7279                                 prevRow = rowIndicies[j];
    7280                             }
    7281                             j++;  // we didn't return earlier, so go to next row
    7282                             break;
    7283
    7284                         case NOT_IN_ROW:  // sparse bunch of rows of selections
    7285                             if (curIndex <
    7286                                 (colsSel * (rowIndicies[j] -
    7287                                 (prevRow == -1 ? 0 : (prevRow + 1))))) {
    7288
    7289                                 // it's here!
    7290                                 c = colIndicies[curIndex % colsSel];
    7291                                 r = (j > 0 ? rowIndicies[j-1] + 1 : 0)
    7292                                     + curIndex / colsSel;
    7293                                 return getAccessibleChild((r * ttlCols) + c);
    7294                             } else {                               // not here
    7295                                 curIndex -= colsSel * (rowIndicies[j] -
    7296                                 (prevRow == -1 ? 0 : (prevRow + 1)));
    7297                             }
    7298                             state = IN_ROW;
    7299                             break;
    7300                         }
    7301                     }
    7302                     // we got here, so we didn't find it yet; find it in
    7303                     // the last sparse bunch of rows
    7304                     if (curIndex <
    7305                         (colsSel * (ttlRows -
    7306                         (prevRow == -1 ? 0 : (prevRow + 1))))) { // it's here!
    7307                         c = colIndicies[curIndex % colsSel];
    7308                         r = rowIndicies[j-1] + curIndex / colsSel + 1;
    7309                         return getAccessibleChild((r * ttlCols) + c);
    7310                     } else {                               // not here
    7311                         // we shouldn't get to this spot in the code!
    7312 //                      System.out.println("Bug in AccessibleJTable.getAccessibleSelection()");
    7313                     }
    7314
    7315                 // one or more rows selected
    7316                 } else if (JTable.this.getRowSelectionAllowed()) {
    7317                     c = i % ttlCols;
    7318                     r = rowIndicies[i / ttlCols];
    7319                     return getAccessibleChild((r * ttlCols) + c);
    7320
    7321                 // one or more columns selected
    7322                 } else if (JTable.this.getColumnSelectionAllowed()) {
    7323                     c = colIndicies[i % colsSel];
    7324                     r = i / colsSel;
    7325                     return getAccessibleChild((r * ttlCols) + c);
    7326                 }
    7327             }
    7328             return null;
    7329         }
    7330
    7331         /**
    7332          * Determines if the current child of this object is selected.
    7333          *
    7334          * @param i the zero-based index of the child in this
    7335          *    <code>Accessible</code> object
    7336          * @return true if the current child of this object is selected
    7337          * @see AccessibleContext#getAccessibleChild
    7338          */
    7339         public boolean isAccessibleChildSelected(int i) {
    7340             int column = getAccessibleColumnAtIndex(i);
    7341             int row = getAccessibleRowAtIndex(i);
    7342             return JTable.this.isCellSelected(row, column);
    7343         }
    7344
    7345         /**
    7346          * Adds the specified <code>Accessible</code> child of the
    7347          * object to the object's selection.  If the object supports
    7348          * multiple selections, the specified child is added to
    7349          * any existing selection, otherwise
    7350          * it replaces any existing selection in the object.  If the
    7351          * specified child is already selected, this method has no effect.
    7352          * <p>
    7353          * This method only works on <code>JTable</code>s which have
    7354          * individual cell selection enabled.
    7355          *
    7356          * @param i the zero-based index of the child
    7357          * @see AccessibleContext#getAccessibleChild
    7358          */
    7359         public void addAccessibleSelection(int i) {
    7360             // TIGER - 4495286
    7361             int column = getAccessibleColumnAtIndex(i);
    7362             int row = getAccessibleRowAtIndex(i);
    7363             JTable.this.changeSelection(row, column, true, false);
    7364         }
    7365
    7366         /**
    7367          * Removes the specified child of the object from the object's
    7368          * selection.  If the specified item isn't currently selected, this
    7369          * method has no effect.
    7370          * <p>
    7371          * This method only works on <code>JTables</code> which have
    7372          * individual cell selection enabled.
    7373          *
    7374          * @param i the zero-based index of the child
    7375          * @see AccessibleContext#getAccessibleChild
    7376          */
    7377         public void removeAccessibleSelection(int i) {
    7378             if (JTable.this.cellSelectionEnabled) {
    7379                 int column = getAccessibleColumnAtIndex(i);
    7380                 int row = getAccessibleRowAtIndex(i);
    7381                 JTable.this.removeRowSelectionInterval(row, row);
    7382                 JTable.this.removeColumnSelectionInterval(column, column);
    7383             }
    7384         }
    7385
    7386         /**
    7387          * Clears the selection in the object, so that no children in the
    7388          * object are selected.
    7389          */
    7390         public void clearAccessibleSelection() {
    7391             JTable.this.clearSelection();
    7392         }
    7393
    7394         /**
    7395          * Causes every child of the object to be selected, but only
    7396          * if the <code>JTable</code> supports multiple selections,
    7397          * and if individual cell selection is enabled.
    7398          */
    7399         public void selectAllAccessibleSelection() {
    7400             if (JTable.this.cellSelectionEnabled) {
    7401                 JTable.this.selectAll();
    7402             }
    7403         }
    7404
    7405         // begin AccessibleExtendedTable implementation -------------
    7406
    7407         /**
    7408          * Returns the row number of an index in the table.
    7409          *
    7410          * @param index the zero-based index in the table
    7411          * @return the zero-based row of the table if one exists;
    7412          * otherwise -1.
    7413          * @since 1.4
    7414          */
    7415         public int getAccessibleRow(int index) {
    7416             return getAccessibleRowAtIndex(index);
    7417         }
    7418
    7419         /**
    7420          * Returns the column number of an index in the table.
    7421          *
    7422          * @param index the zero-based index in the table
    7423          * @return the zero-based column of the table if one exists;
    7424          * otherwise -1.
    7425          * @since 1.4
    7426          */
    7427         public int getAccessibleColumn(int index) {
    7428             return getAccessibleColumnAtIndex(index);
    7429         }
    7430
    7431         /**
    7432          * Returns the index at a row and column in the table.
    7433          *
    7434          * @param r zero-based row of the table
    7435          * @param c zero-based column of the table
    7436          * @return the zero-based index in the table if one exists;
    7437          * otherwise -1.
    7438          * @since 1.4
    7439          */
    7440         public int getAccessibleIndex(int r, int c) {
    7441             return getAccessibleIndexAt(r, c);
    7442         }
    7443
    7444         // end of AccessibleExtendedTable implementation ------------
    7445
    7446         // start of AccessibleTable implementation ------------------
    7447
    7448         private Accessible caption;
    7449         private Accessible summary;
    7450         private Accessible [] rowDescription;
    7451         private Accessible [] columnDescription;
    7452
    7453         /**
    7454          * Gets the <code>AccessibleTable</code> associated with this
    7455          * object.  In the implementation of the Java Accessibility
    7456          * API for this class, return this object, which is responsible
    7457          * for implementing the <code>AccessibleTables</code> interface
    7458          * on behalf of itself.
    7459          *
    7460          * @return this object
    7461          * @since 1.3
    7462          */
    7463         public AccessibleTable getAccessibleTable() {
    7464             return this;
    7465         }
    7466
    7467         /**
    7468          * Returns the caption for the table.
    7469          *
    7470          * @return the caption for the table
    7471          * @since 1.3
    7472          */
    7473         public Accessible getAccessibleCaption() {
    7474             return this.caption;
    7475         }
    7476
    7477         /**
    7478          * Sets the caption for the table.
    7479          *
    7480          * @param a the caption for the table
    7481          * @since 1.3
    7482          */
    7483         public void setAccessibleCaption(Accessible a) {
    7484             Accessible oldCaption = caption;
    7485             this.caption = a;
    7486             firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_CAPTION_CHANGED,
    7487                                oldCaption, this.caption);
    7488         }
    7489
    7490         /**
    7491          * Returns the summary description of the table.
    7492          *
    7493          * @return the summary description of the table
    7494          * @since 1.3
    7495          */
    7496         public Accessible getAccessibleSummary() {
    7497             return this.summary;
    7498         }
    7499
    7500         /**
    7501          * Sets the summary description of the table.
    7502          *
    7503          * @param a the summary description of the table
    7504          * @since 1.3
    7505          */
    7506         public void setAccessibleSummary(Accessible a) {
    7507             Accessible oldSummary = summary;
    7508             this.summary = a;
    7509             firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_SUMMARY_CHANGED,
    7510                                oldSummary, this.summary);
    7511         }
    7512
    7513         /*
    7514          * Returns the total number of rows in this table.
    7515          *
    7516          * @return the total number of rows in this table
    7517          */
    7518         public int getAccessibleRowCount() {
    7519             return JTable.this.getRowCount();
    7520         }
    7521
    7522         /*
    7523          * Returns the total number of columns in the table.
    7524          *
    7525          * @return the total number of columns in the table
    7526          */
    7527         public int getAccessibleColumnCount() {
    7528             return JTable.this.getColumnCount();
    7529         }
    7530
    7531         /*
    7532          * Returns the <code>Accessible</code> at a specified row
    7533          * and column in the table.
    7534          *
    7535          * @param r zero-based row of the table
    7536          * @param c zero-based column of the table
    7537          * @return the <code>Accessible</code> at the specified row and column
    7538          * in the table
    7539          */
    7540         public Accessible getAccessibleAt(int r, int c) {
    7541             return getAccessibleChild((r * getAccessibleColumnCount()) + c);
    7542         }
    7543
    7544         /**
    7545          * Returns the number of rows occupied by the <code>Accessible</code>
    7546          * at a specified row and column in the table.
    7547          *
    7548          * @return the number of rows occupied by the <code>Accessible</code>
    7549          *     at a specified row and column in the table
    7550          * @since 1.3
    7551          */
    7552         public int getAccessibleRowExtentAt(int r, int c) {
    7553             return 1;
    7554         }
    7555
    7556         /**
    7557          * Returns the number of columns occupied by the
    7558          * <code>Accessible</code> at a given (row, column).
    7559          *
    7560          * @return the number of columns occupied by the <code>Accessible</code>
    7561          *     at a specified row and column in the table
    7562          * @since 1.3
    7563          */
    7564         public int getAccessibleColumnExtentAt(int r, int c) {
    7565             return 1;
    7566         }
    7567
    7568         /**
    7569          * Returns the row headers as an <code>AccessibleTable</code>.
    7570          *
    7571          * @return an <code>AccessibleTable</code> representing the row
    7572          * headers
    7573          * @since 1.3
    7574          */
    7575         public AccessibleTable getAccessibleRowHeader() {
    7576             // row headers are not supported
    7577             return null;
    7578         }
    7579
    7580         /**
    7581          * Sets the row headers as an <code>AccessibleTable</code>.
    7582          *
    7583          * @param a an <code>AccessibleTable</code> representing the row
    7584          *  headers
    7585          * @since 1.3
    7586          */
    7587         public void setAccessibleRowHeader(AccessibleTable a) {
    7588             // row headers are not supported
    7589         }
    7590
    7591         /**
    7592          * Returns the column headers as an <code>AccessibleTable</code>.
    7593          *
    7594          *  @return an <code>AccessibleTable</code> representing the column
    7595          *          headers, or <code>null</code> if the table header is
    7596          *          <code>null</code>
    7597          * @since 1.3
    7598          */
    7599         public AccessibleTable getAccessibleColumnHeader() {
    7600             JTableHeader header = JTable.this.getTableHeader();
    7601             return header == null ? null : new AccessibleTableHeader(header);
    7602         }
    7603
    7604         /*
    7605          * Private class representing a table column header
    7606          */
    7607         private class AccessibleTableHeader implements AccessibleTable {
    7608             private JTableHeader header;
    7609             private TableColumnModel headerModel;
    7610
    7611             AccessibleTableHeader(JTableHeader header) {
    7612                 this.header = header;
    7613                 this.headerModel = header.getColumnModel();
    7614             }
    7615
    7616             /**
    7617              * Returns the caption for the table.
    7618              *
    7619              * @return the caption for the table
    7620              */
    7621             public Accessible getAccessibleCaption() { return null; }
    7622
    7623
    7624             /**
    7625              * Sets the caption for the table.
    7626              *
    7627              * @param a the caption for the table
    7628              */
    7629             public void setAccessibleCaption(Accessible a) {}
    7630
    7631             /**
    7632              * Returns the summary description of the table.
    7633              *
    7634              * @return the summary description of the table
    7635              */
    7636             public Accessible getAccessibleSummary() { return null; }
    7637
    7638             /**
    7639              * Sets the summary description of the table
    7640              *
    7641              * @param a the summary description of the table
    7642              */
    7643             public void setAccessibleSummary(Accessible a) {}
    7644
    7645             /**
    7646              * Returns the number of rows in the table.
    7647              *
    7648              * @return the number of rows in the table
    7649              */
    7650             public int getAccessibleRowCount() { return 1; }
    7651
    7652             /**
    7653              * Returns the number of columns in the table.
    7654              *
    7655              * @return the number of columns in the table
    7656              */
    7657             public int getAccessibleColumnCount() {
    7658                 return headerModel.getColumnCount();
    7659             }
    7660
    7661             /**
    7662              * Returns the Accessible at a specified row and column
    7663              * in the table.
    7664              *
    7665              * @param row zero-based row of the table
    7666              * @param column zero-based column of the table
    7667              * @return the Accessible at the specified row and column
    7668              */
    7669             public Accessible getAccessibleAt(int row, int column) {
    7670
    7671
    7672                 // TIGER - 4715503
    7673                 TableColumn aColumn = headerModel.getColumn(column);
    7674                 TableCellRenderer renderer = aColumn.getHeaderRenderer();
    7675                 if (renderer == null) {
    7676                     renderer = header.getDefaultRenderer();
    7677                 }
    7678                 Component component = renderer.getTableCellRendererComponent(
    7679                                   header.getTable(),
    7680                                   aColumn.getHeaderValue(), false, false,
    7681                                   -1, column);
    7682
    7683                 return new AccessibleJTableHeaderCell(row, column,
    7684                                                       JTable.this.getTableHeader(),
    7685                                                       component);
    7686             }
    7687
    7688             /**
    7689              * Returns the number of rows occupied by the Accessible at
    7690              * a specified row and column in the table.
    7691              *
    7692              * @return the number of rows occupied by the Accessible at a
    7693              * given specified (row, column)
    7694              */
    7695             public int getAccessibleRowExtentAt(int r, int c) { return 1; }
    7696
    7697             /**
    7698              * Returns the number of columns occupied by the Accessible at
    7699              * a specified row and column in the table.
    7700              *
    7701              * @return the number of columns occupied by the Accessible at a
    7702              * given specified row and column
    7703              */
    7704             public int getAccessibleColumnExtentAt(int r, int c) { return 1; }
    7705
    7706             /**
    7707              * Returns the row headers as an AccessibleTable.
    7708              *
    7709              * @return an AccessibleTable representing the row
    7710              * headers
    7711              */
    7712             public AccessibleTable getAccessibleRowHeader() { return null; }
    7713
    7714             /**
    7715              * Sets the row headers.
    7716              *
    7717              * @param table an AccessibleTable representing the
    7718              * row headers
    7719              */
    7720             public void setAccessibleRowHeader(AccessibleTable table) {}
    7721
    7722             /**
    7723              * Returns the column headers as an AccessibleTable.
    7724              *
    7725              * @return an AccessibleTable representing the column
    7726              * headers
    7727              */
    7728             public AccessibleTable getAccessibleColumnHeader() { return null; }
    7729
    7730             /**
    7731              * Sets the column headers.
    7732              *
    7733              * @param table an AccessibleTable representing the
    7734              * column headers
    7735              * @since 1.3
    7736              */
    7737             public void setAccessibleColumnHeader(AccessibleTable table) {}
    7738
    7739             /**
    7740              * Returns the description of the specified row in the table.
    7741              *
    7742              * @param r zero-based row of the table
    7743              * @return the description of the row
    7744              * @since 1.3
    7745              */
    7746             public Accessible getAccessibleRowDescription(int r) { return null; }
    7747
    7748             /**
    7749              * Sets the description text of the specified row of the table.
    7750              *
    7751              * @param r zero-based row of the table
    7752              * @param a the description of the row
    7753              * @since 1.3
    7754              */
    7755             public void setAccessibleRowDescription(int r, Accessible a) {}
    7756
    7757             /**
    7758              * Returns the description text of the specified column in the table.
    7759              *
    7760              * @param c zero-based column of the table
    7761              * @return the text description of the column
    7762              * @since 1.3
    7763              */
    7764             public Accessible getAccessibleColumnDescription(int c) { return null; }
    7765
    7766             /**
    7767              * Sets the description text of the specified column in the table.
    7768              *
    7769              * @param c zero-based column of the table
    7770              * @param a the text description of the column
    7771              * @since 1.3
    7772              */
    7773             public void setAccessibleColumnDescription(int c, Accessible a) {}
    7774
    7775             /**
    7776              * Returns a boolean value indicating whether the accessible at
    7777              * a specified row and column is selected.
    7778              *
    7779              * @param r zero-based row of the table
    7780              * @param c zero-based column of the table
    7781              * @return the boolean value true if the accessible at the
    7782              * row and column is selected. Otherwise, the boolean value
    7783              * false
    7784              * @since 1.3
    7785              */
    7786             public boolean isAccessibleSelected(int r, int c) { return false; }
    7787
    7788             /**
    7789              * Returns a boolean value indicating whether the specified row
    7790              * is selected.
    7791              *
    7792              * @param r zero-based row of the table
    7793              * @return the boolean value true if the specified row is selected.
    7794              * Otherwise, false.
    7795              * @since 1.3
    7796              */
    7797             public boolean isAccessibleRowSelected(int r) { return false; }
    7798
    7799             /**
    7800              * Returns a boolean value indicating whether the specified column
    7801              * is selected.
    7802              *
    7803              * @param c zero-based column of the table
    7804              * @return the boolean value true if the specified column is selected.
    7805              * Otherwise, false.
    7806              * @since 1.3
    7807              */
    7808             public boolean isAccessibleColumnSelected(int c) { return false; }
    7809
    7810             /**
    7811              * Returns the selected rows in a table.
    7812              *
    7813              * @return an array of selected rows where each element is a
    7814              * zero-based row of the table
    7815              * @since 1.3
    7816              */
    7817             public int [] getSelectedAccessibleRows() { return new int[0]; }
    7818
    7819             /**
    7820              * Returns the selected columns in a table.
    7821              *
    7822              * @return an array of selected columns where each element is a
    7823              * zero-based column of the table
    7824              * @since 1.3
    7825              */
    7826             public int [] getSelectedAccessibleColumns() { return new int[0]; }
    7827         }
    7828
    7829
    7830         /**
    7831          * Sets the column headers as an <code>AccessibleTable</code>.
    7832          *
    7833          * @param a an <code>AccessibleTable</code> representing the
    7834          * column headers
    7835          * @since 1.3
    7836          */
    7837         public void setAccessibleColumnHeader(AccessibleTable a) {
    7838             // XXX not implemented
    7839         }
    7840
    7841         /**
    7842          * Returns the description of the specified row in the table.
    7843          *
    7844          * @param r zero-based row of the table
    7845          * @return the description of the row
    7846          * @since 1.3
    7847          */
    7848         public Accessible getAccessibleRowDescription(int r) {
    7849             if (r < 0 || r >= getAccessibleRowCount()) {
    7850                 throw new IllegalArgumentException(Integer.toString(r));
    7851             }
    7852             if (rowDescription == null) {
    7853                 return null;
    7854             } else {
    7855                 return rowDescription[r];
    7856             }
    7857         }
    7858
    7859         /**
    7860          * Sets the description text of the specified row of the table.
    7861          *
    7862          * @param r zero-based row of the table
    7863          * @param a the description of the row
    7864          * @since 1.3
    7865          */
    7866         public void setAccessibleRowDescription(int r, Accessible a) {
    7867             if (r < 0 || r >= getAccessibleRowCount()) {
    7868                 throw new IllegalArgumentException(Integer.toString(r));
    7869             }
    7870             if (rowDescription == null) {
    7871                 int numRows = getAccessibleRowCount();
    7872                 rowDescription = new Accessible[numRows];
    7873             }
    7874             rowDescription[r] = a;
    7875         }
    7876
    7877         /**
    7878          * Returns the description of the specified column in the table.
    7879          *
    7880          * @param c zero-based column of the table
    7881          * @return the description of the column
    7882          * @since 1.3
    7883          */
    7884         public Accessible getAccessibleColumnDescription(int c) {
    7885             if (c < 0 || c >= getAccessibleColumnCount()) {
    7886                 throw new IllegalArgumentException(Integer.toString(c));
    7887             }
    7888             if (columnDescription == null) {
    7889                 return null;
    7890             } else {
    7891                 return columnDescription[c];
    7892             }
    7893         }
    7894
    7895         /**
    7896          * Sets the description text of the specified column of the table.
    7897          *
    7898          * @param c zero-based column of the table
    7899          * @param a the description of the column
    7900          * @since 1.3
    7901          */
    7902         public void setAccessibleColumnDescription(int c, Accessible a) {
    7903             if (c < 0 || c >= getAccessibleColumnCount()) {
    7904                 throw new IllegalArgumentException(Integer.toString(c));
    7905             }
    7906             if (columnDescription == null) {
    7907                 int numColumns = getAccessibleColumnCount();
    7908                 columnDescription = new Accessible[numColumns];
    7909             }
    7910             columnDescription[c] = a;
    7911         }
    7912
    7913         /**
    7914          * Returns a boolean value indicating whether the accessible at a
    7915          * given (row, column) is selected.
    7916          *
    7917          * @param r zero-based row of the table
    7918          * @param c zero-based column of the table
    7919          * @return the boolean value true if the accessible at (row, column)
    7920          *     is selected; otherwise, the boolean value false
    7921          * @since 1.3
    7922          */
    7923         public boolean isAccessibleSelected(int r, int c) {
    7924             return JTable.this.isCellSelected(r, c);
    7925         }
    7926
    7927         /**
    7928          * Returns a boolean value indicating whether the specified row
    7929          * is selected.
    7930          *
    7931          * @param r zero-based row of the table
    7932          * @return the boolean value true if the specified row is selected;
    7933          *     otherwise, false
    7934          * @since 1.3
    7935          */
    7936         public boolean isAccessibleRowSelected(int r) {
    7937             return JTable.this.isRowSelected(r);
    7938         }
    7939
    7940         /**
    7941          * Returns a boolean value indicating whether the specified column
    7942          * is selected.
    7943          *
    7944          * @param c zero-based column of the table
    7945          * @return the boolean value true if the specified column is selected;
    7946          *     otherwise, false
    7947          * @since 1.3
    7948          */
    7949         public boolean isAccessibleColumnSelected(int c) {
    7950             return JTable.this.isColumnSelected(c);
    7951         }
    7952
    7953         /**
    7954          * Returns the selected rows in a table.
    7955          *
    7956          * @return an array of selected rows where each element is a
    7957          *     zero-based row of the table
    7958          * @since 1.3
    7959          */
    7960         public int [] getSelectedAccessibleRows() {
    7961             return JTable.this.getSelectedRows();
    7962         }
    7963
    7964         /**
    7965          * Returns the selected columns in a table.
    7966          *
    7967          * @return an array of selected columns where each element is a
    7968          *     zero-based column of the table
    7969          * @since 1.3
    7970          */
    7971         public int [] getSelectedAccessibleColumns() {
    7972             return JTable.this.getSelectedColumns();
    7973         }
    7974
    7975         /**
    7976          * Returns the row at a given index into the table.
    7977          *
    7978          * @param i zero-based index into the table
    7979          * @return the row at a given index
    7980          * @since 1.3
    7981          */
    7982         public int getAccessibleRowAtIndex(int i) {
    7983             int columnCount = getAccessibleColumnCount();
    7984             if (columnCount == 0) {
    7985                 return -1;
    7986             } else {
    7987                 return (i / columnCount);
    7988             }
    7989         }
    7990
    7991         /**
    7992          * Returns the column at a given index into the table.
    7993          *
    7994          * @param i zero-based index into the table
    7995          * @return the column at a given index
    7996          * @since 1.3
    7997          */
    7998         public int getAccessibleColumnAtIndex(int i) {
    7999             int columnCount = getAccessibleColumnCount();
    8000             if (columnCount == 0) {
    8001                 return -1;
    8002             } else {
    8003                 return (i % columnCount);
    8004             }
    8005         }
    8006
    8007         /**
    8008          * Returns the index at a given (row, column) in the table.
    8009          *
    8010          * @param r zero-based row of the table
    8011          * @param c zero-based column of the table
    8012          * @return the index into the table
    8013          * @since 1.3
    8014          */
    8015         public int getAccessibleIndexAt(int r, int c) {
    8016             return ((r * getAccessibleColumnCount()) + c);
    8017         }
    8018
    8019         // end of AccessibleTable implementation --------------------
    8020
    8021         /**
    8022          * The class provides an implementation of the Java Accessibility
    8023          * API appropriate to table cells.
    8024          */
    8025         protected class AccessibleJTableCell extends AccessibleContext
    8026             implements Accessible, AccessibleComponent {
    8027
    8028             private JTable parent;
    8029             private int row;
    8030             private int column;
    8031             private int index;
    8032
    8033             /**
    8034              *  Constructs an <code>AccessibleJTableHeaderEntry</code>.
    8035              *
    8036              * @param t a {@code JTable}
    8037              * @param r an {@code int} specifying a row
    8038              * @param c an {@code int} specifying a column
    8039              * @param i an {@code int} specifying the index to this cell
    8040              * @since 1.4
    8041              */
    8042             public AccessibleJTableCell(JTable t, int r, int c, int i) {
    8043                 parent = t;
    8044                 row = r;
    8045                 column = c;
    8046                 index = i;
    8047                 this.setAccessibleParent(parent);
    8048             }
    8049
    8050             /**
    8051              * Gets the <code>AccessibleContext</code> associated with this
    8052              * component. In the implementation of the Java Accessibility
    8053              * API for this class, return this object, which is its own
    8054              * <code>AccessibleContext</code>.
    8055              *
    8056              * @return this object
    8057              */
    8058             public AccessibleContext getAccessibleContext() {
    8059                 return this;
    8060             }
    8061
    8062             /**
    8063              * Gets the AccessibleContext for the table cell renderer.
    8064              *
    8065              * @return the <code>AccessibleContext</code> for the table
    8066              * cell renderer if one exists;
    8067              * otherwise, returns <code>null</code>.
    8068              * @since 1.6
    8069              */
    8070             protected AccessibleContext getCurrentAccessibleContext() {
    8071                 TableColumn aColumn = getColumnModel().getColumn(column);
    8072                 TableCellRenderer renderer = aColumn.getCellRenderer();
    8073                 if (renderer == null) {
    8074                     Class<?> columnClass = getColumnClass(column);
    8075                     renderer = getDefaultRenderer(columnClass);
    8076                 }
    8077                 Component component = renderer.getTableCellRendererComponent(
    8078                                   JTable.this, getValueAt(row, column),
    8079                                   false, false, row, column);
    8080                 if (component instanceof Accessible) {
    8081                     return component.getAccessibleContext();
    8082                 } else {
    8083                     return null;
    8084                 }
    8085             }
    8086
    8087             /**
    8088              * Gets the table cell renderer component.
    8089              *
    8090              * @return the table cell renderer component if one exists;
    8091              * otherwise, returns <code>null</code>.
    8092              * @since 1.6
    8093              */
    8094             protected Component getCurrentComponent() {
    8095                 TableColumn aColumn = getColumnModel().getColumn(column);
    8096                 TableCellRenderer renderer = aColumn.getCellRenderer();
    8097                 if (renderer == null) {
    8098                     Class<?> columnClass = getColumnClass(column);
    8099                     renderer = getDefaultRenderer(columnClass);
    8100                 }
    8101                 return renderer.getTableCellRendererComponent(
    8102                                   JTable.this, null, false, false,
    8103                                   row, column);
    8104             }
    8105
    8106         // AccessibleContext methods
    8107
    8108             /**
    8109              * Gets the accessible name of this object.
    8110              *
    8111              * @return the localized name of the object; <code>null</code>
    8112              *     if this object does not have a name
    8113              */
    8114             public String getAccessibleName() {
    8115                 AccessibleContext ac = getCurrentAccessibleContext();
    8116                 if (ac != null) {
    8117                     String name = ac.getAccessibleName();
    8118                     if ((name != null) && (name != "")) {
    8119                         // return the cell renderer's AccessibleName
    8120                         return name;
    8121                     }
    8122                 }
    8123                 if ((accessibleName != null) && (accessibleName != "")) {
    8124                     return accessibleName;
    8125                 } else {
    8126                     // fall back to the client property
    8127                     return (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
    8128                 }
    8129             }
    8130
    8131             /**
    8132              * Sets the localized accessible name of this object.
    8133              *
    8134              * @param s the new localized name of the object
    8135              */
    8136             public void setAccessibleName(String s) {
    8137                 AccessibleContext ac = getCurrentAccessibleContext();
    8138                 if (ac != null) {
    8139                     ac.setAccessibleName(s);
    8140                 } else {
    8141                     super.setAccessibleName(s);
    8142                 }
    8143             }
    8144
    8145             //
    8146             // *** should check toolTip text for desc. (needs MouseEvent)
    8147             //
    8148             /**
    8149              * Gets the accessible description of this object.
    8150              *
    8151              * @return the localized description of the object;
    8152              *     <code>null</code> if this object does not have
    8153              *     a description
    8154              */
    8155             public String getAccessibleDescription() {
    8156                 AccessibleContext ac = getCurrentAccessibleContext();
    8157                 if (ac != null) {
    8158                     return ac.getAccessibleDescription();
    8159                 } else {
    8160                     return super.getAccessibleDescription();
    8161                 }
    8162             }
    8163
    8164             /**
    8165              * Sets the accessible description of this object.
    8166              *
    8167              * @param s the new localized description of the object
    8168              */
    8169             public void setAccessibleDescription(String s) {
    8170                 AccessibleContext ac = getCurrentAccessibleContext();
    8171                 if (ac != null) {
    8172                     ac.setAccessibleDescription(s);
    8173                 } else {
    8174                     super.setAccessibleDescription(s);
    8175                 }
    8176             }
    8177
    8178             /**
    8179              * Gets the role of this object.
    8180              *
    8181              * @return an instance of <code>AccessibleRole</code>
    8182              *      describing the role of the object
    8183              * @see AccessibleRole
    8184              */
    8185             public AccessibleRole getAccessibleRole() {
    8186                 AccessibleContext ac = getCurrentAccessibleContext();
    8187                 if (ac != null) {
    8188                     return ac.getAccessibleRole();
    8189                 } else {
    8190                     return AccessibleRole.UNKNOWN;
    8191                 }
    8192             }
    8193
    8194             /**
    8195              * Gets the state set of this object.
    8196              *
    8197              * @return an instance of <code>AccessibleStateSet</code>
    8198              *     containing the current state set of the object
    8199              * @see AccessibleState
    8200              */
    8201             public AccessibleStateSet getAccessibleStateSet() {
    8202                 AccessibleContext ac = getCurrentAccessibleContext();
    8203                 AccessibleStateSet as = null;
    8204
    8205                 if (ac != null) {
    8206                     as = ac.getAccessibleStateSet();
    8207                 }
    8208                 if (as == null) {
    8209                     as = new AccessibleStateSet();
    8210                 }
    8211                 Rectangle rjt = JTable.this.getVisibleRect();
    8212                 Rectangle rcell = JTable.this.getCellRect(row, column, false);
    8213                 if (rjt.intersects(rcell)) {
    8214                     as.add(AccessibleState.SHOWING);
    8215                 } else {
    8216                     if (as.contains(AccessibleState.SHOWING)) {
    8217                          as.remove(AccessibleState.SHOWING);
    8218                     }
    8219                 }
    8220                 if (parent.isCellSelected(row, column)) {
    8221                     as.add(AccessibleState.SELECTED);
    8222                 } else if (as.contains(AccessibleState.SELECTED)) {
    8223                     as.remove(AccessibleState.SELECTED);
    8224                 }
    8225                 if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
    8226                     as.add(AccessibleState.ACTIVE);
    8227                 }
    8228                 as.add(AccessibleState.TRANSIENT);
    8229                 return as;
    8230             }
    8231
    8232             /**
    8233              * Gets the <code>Accessible</code> parent of this object.
    8234              *
    8235              * @return the Accessible parent of this object;
    8236              *     <code>null</code> if this object does not
    8237              *     have an <code>Accessible</code> parent
    8238              */
    8239             public Accessible getAccessibleParent() {
    8240                 return parent;
    8241             }
    8242
    8243             /**
    8244              * Gets the index of this object in its accessible parent.
    8245              *
    8246              * @return the index of this object in its parent; -1 if this
    8247              *     object does not have an accessible parent
    8248              * @see #getAccessibleParent
    8249              */
    8250             public int getAccessibleIndexInParent() {
    8251                 return index;
    8252             }
    8253
    8254             /**
    8255              * Returns the number of accessible children in the object.
    8256              *
    8257              * @return the number of accessible children in the object
    8258              */
    8259             public int getAccessibleChildrenCount() {
    8260                 AccessibleContext ac = getCurrentAccessibleContext();
    8261                 if (ac != null) {
    8262                     return ac.getAccessibleChildrenCount();
    8263                 } else {
    8264                     return 0;
    8265                 }
    8266             }
    8267
    8268             /**
    8269              * Returns the specified <code>Accessible</code> child of the
    8270              * object.
    8271              *
    8272              * @param i zero-based index of child
    8273              * @return the <code>Accessible</code> child of the object
    8274              */
    8275             public Accessible getAccessibleChild(int i) {
    8276                 AccessibleContext ac = getCurrentAccessibleContext();
    8277                 if (ac != null) {
    8278                     Accessible accessibleChild = ac.getAccessibleChild(i);
    8279                     ac.setAccessibleParent(this);
    8280                     return accessibleChild;
    8281                 } else {
    8282                     return null;
    8283                 }
    8284             }
    8285
    8286             /**
    8287              * Gets the locale of the component. If the component
    8288              * does not have a locale, then the locale of its parent
    8289              * is returned.
    8290              *
    8291              * @return this component's locale; if this component does
    8292              *    not have a locale, the locale of its parent is returned
    8293              * @exception IllegalComponentStateException if the
    8294              *    <code>Component</code> does not have its own locale
    8295              *    and has not yet been added to a containment hierarchy
    8296              *    such that the locale can be determined from the
    8297              *    containing parent
    8298              * @see #setLocale
    8299              */
    8300             public Locale getLocale() {
    8301                 AccessibleContext ac = getCurrentAccessibleContext();
    8302                 if (ac != null) {
    8303                     return ac.getLocale();
    8304                 } else {
    8305                     return null;
    8306                 }
    8307             }
    8308
    8309             /**
    8310              * Adds a <code>PropertyChangeListener</code> to the listener list.
    8311              * The listener is registered for all properties.
    8312              *
    8313              * @param l  the <code>PropertyChangeListener</code>
    8314              *     to be added
    8315              */
    8316             public void addPropertyChangeListener(PropertyChangeListener l) {
    8317                 AccessibleContext ac = getCurrentAccessibleContext();
    8318                 if (ac != null) {
    8319                     ac.addPropertyChangeListener(l);
    8320                 } else {
    8321                     super.addPropertyChangeListener(l);
    8322                 }
    8323             }
    8324
    8325             /**
    8326              * Removes a <code>PropertyChangeListener</code> from the
    8327              * listener list. This removes a <code>PropertyChangeListener</code>
    8328              * that was registered for all properties.
    8329              *
    8330              * @param l  the <code>PropertyChangeListener</code>
    8331              *    to be removed
    8332              */
    8333             public void removePropertyChangeListener(PropertyChangeListener l) {
    8334                 AccessibleContext ac = getCurrentAccessibleContext();
    8335                 if (ac != null) {
    8336                     ac.removePropertyChangeListener(l);
    8337                 } else {
    8338                     super.removePropertyChangeListener(l);
    8339                 }
    8340             }
    8341
    8342             /**
    8343              * Gets the <code>AccessibleAction</code> associated with this
    8344              * object if one exists.  Otherwise returns <code>null</code>.
    8345              *
    8346              * @return the <code>AccessibleAction</code>, or <code>null</code>
    8347              */
    8348             public AccessibleAction getAccessibleAction() {
    8349                 return getCurrentAccessibleContext().getAccessibleAction();
    8350             }
    8351
    8352             /**
    8353              * Gets the <code>AccessibleComponent</code> associated with
    8354              * this object if one exists.  Otherwise returns <code>null</code>.
    8355              *
    8356              * @return the <code>AccessibleComponent</code>, or
    8357              *    <code>null</code>
    8358              */
    8359             public AccessibleComponent getAccessibleComponent() {
    8360                 return this; // to override getBounds()
    8361             }
    8362
    8363             /**
    8364              * Gets the <code>AccessibleSelection</code> associated with
    8365              * this object if one exists.  Otherwise returns <code>null</code>.
    8366              *
    8367              * @return the <code>AccessibleSelection</code>, or
    8368              *    <code>null</code>
    8369              */
    8370             public AccessibleSelection getAccessibleSelection() {
    8371                 return getCurrentAccessibleContext().getAccessibleSelection();
    8372             }
    8373
    8374             /**
    8375              * Gets the <code>AccessibleText</code> associated with this
    8376              * object if one exists.  Otherwise returns <code>null</code>.
    8377              *
    8378              * @return the <code>AccessibleText</code>, or <code>null</code>
    8379              */
    8380             public AccessibleText getAccessibleText() {
    8381                 return getCurrentAccessibleContext().getAccessibleText();
    8382             }
    8383
    8384             /**
    8385              * Gets the <code>AccessibleValue</code> associated with
    8386              * this object if one exists.  Otherwise returns <code>null</code>.
    8387              *
    8388              * @return the <code>AccessibleValue</code>, or <code>null</code>
    8389              */
    8390             public AccessibleValue getAccessibleValue() {
    8391                 return getCurrentAccessibleContext().getAccessibleValue();
    8392             }
    8393
    8394
    8395         // AccessibleComponent methods
    8396
    8397             /**
    8398              * Gets the background color of this object.
    8399              *
    8400              * @return the background color, if supported, of the object;
    8401              *     otherwise, <code>null</code>
    8402              */
    8403             public Color getBackground() {
    8404                 AccessibleContext ac = getCurrentAccessibleContext();
    8405                 if (ac instanceof AccessibleComponent) {
    8406                     return ((AccessibleComponent) ac).getBackground();
    8407                 } else {
    8408                     Component c = getCurrentComponent();
    8409                     if (c != null) {
    8410                         return c.getBackground();
    8411                     } else {
    8412                         return null;
    8413                     }
    8414                 }
    8415             }
    8416
    8417             /**
    8418              * Sets the background color of this object.
    8419              *
    8420              * @param c the new <code>Color</code> for the background
    8421              */
    8422             public void setBackground(Color c) {
    8423                 AccessibleContext ac = getCurrentAccessibleContext();
    8424                 if (ac instanceof AccessibleComponent) {
    8425                     ((AccessibleComponent) ac).setBackground(c);
    8426                 } else {
    8427                     Component cp = getCurrentComponent();
    8428                     if (cp != null) {
    8429                         cp.setBackground(c);
    8430                     }
    8431                 }
    8432             }
    8433
    8434             /**
    8435              * Gets the foreground color of this object.
    8436              *
    8437              * @return the foreground color, if supported, of the object;
    8438              *     otherwise, <code>null</code>
    8439              */
    8440             public Color getForeground() {
    8441                 AccessibleContext ac = getCurrentAccessibleContext();
    8442                 if (ac instanceof AccessibleComponent) {
    8443                     return ((AccessibleComponent) ac).getForeground();
    8444                 } else {
    8445                     Component c = getCurrentComponent();
    8446                     if (c != null) {
    8447                         return c.getForeground();
    8448                     } else {
    8449                         return null;
    8450                     }
    8451                 }
    8452             }
    8453
    8454             /**
    8455              * Sets the foreground color of this object.
    8456              *
    8457              * @param c the new <code>Color</code> for the foreground
    8458              */
    8459             public void setForeground(Color c) {
    8460                 AccessibleContext ac = getCurrentAccessibleContext();
    8461                 if (ac instanceof AccessibleComponent) {
    8462                     ((AccessibleComponent) ac).setForeground(c);
    8463                 } else {
    8464                     Component cp = getCurrentComponent();
    8465                     if (cp != null) {
    8466                         cp.setForeground(c);
    8467                     }
    8468                 }
    8469             }
    8470
    8471             /**
    8472              * Gets the <code>Cursor</code> of this object.
    8473              *
    8474              * @return the <code>Cursor</code>, if supported,
    8475              *    of the object; otherwise, <code>null</code>
    8476              */
    8477             public Cursor getCursor() {
    8478                 AccessibleContext ac = getCurrentAccessibleContext();
    8479                 if (ac instanceof AccessibleComponent) {
    8480                     return ((AccessibleComponent) ac).getCursor();
    8481                 } else {
    8482                     Component c = getCurrentComponent();
    8483                     if (c != null) {
    8484                         return c.getCursor();
    8485                     } else {
    8486                         Accessible ap = getAccessibleParent();
    8487                         if (ap instanceof AccessibleComponent) {
    8488                             return ((AccessibleComponent) ap).getCursor();
    8489                         } else {
    8490                             return null;
    8491                         }
    8492                     }
    8493                 }
    8494             }
    8495
    8496             /**
    8497              * Sets the <code>Cursor</code> of this object.
    8498              *
    8499              * @param c the new <code>Cursor</code> for the object
    8500              */
    8501             public void setCursor(Cursor c) {
    8502                 AccessibleContext ac = getCurrentAccessibleContext();
    8503                 if (ac instanceof AccessibleComponent) {
    8504                     ((AccessibleComponent) ac).setCursor(c);
    8505                 } else {
    8506                     Component cp = getCurrentComponent();
    8507                     if (cp != null) {
    8508                         cp.setCursor(c);
    8509                     }
    8510                 }
    8511             }
    8512
    8513             /**
    8514              * Gets the <code>Font</code> of this object.
    8515              *
    8516              * @return the <code>Font</code>,if supported,
    8517              *   for the object; otherwise, <code>null</code>
    8518              */
    8519             public Font getFont() {
    8520                 AccessibleContext ac = getCurrentAccessibleContext();
    8521                 if (ac instanceof AccessibleComponent) {
    8522                     return ((AccessibleComponent) ac).getFont();
    8523                 } else {
    8524                     Component c = getCurrentComponent();
    8525                     if (c != null) {
    8526                         return c.getFont();
    8527                     } else {
    8528                         return null;
    8529                     }
    8530                 }
    8531             }
    8532
    8533             /**
    8534              * Sets the <code>Font</code> of this object.
    8535              *
    8536              * @param f the new <code>Font</code> for the object
    8537              */
    8538             public void setFont(Font f) {
    8539                 AccessibleContext ac = getCurrentAccessibleContext();
    8540                 if (ac instanceof AccessibleComponent) {
    8541                     ((AccessibleComponent) ac).setFont(f);
    8542                 } else {
    8543                     Component c = getCurrentComponent();
    8544                     if (c != null) {
    8545                         c.setFont(f);
    8546                     }
    8547                 }
    8548             }
    8549
    8550             /**
    8551              * Gets the <code>FontMetrics</code> of this object.
    8552              *
    8553              * @param f the <code>Font</code>
    8554              * @return the <code>FontMetrics</code> object, if supported;
    8555              *    otherwise <code>null</code>
    8556              * @see #getFont
    8557              */
    8558             public FontMetrics getFontMetrics(Font f) {
    8559                 AccessibleContext ac = getCurrentAccessibleContext();
    8560                 if (ac instanceof AccessibleComponent) {
    8561                     return ((AccessibleComponent) ac).getFontMetrics(f);
    8562                 } else {
    8563                     Component c = getCurrentComponent();
    8564                     if (c != null) {
    8565                         return c.getFontMetrics(f);
    8566                     } else {
    8567                         return null;
    8568                     }
    8569                 }
    8570             }
    8571
    8572             /**
    8573              * Determines if the object is enabled.
    8574              *
    8575              * @return true if object is enabled; otherwise, false
    8576              */
    8577             public boolean isEnabled() {
    8578                 AccessibleContext ac = getCurrentAccessibleContext();
    8579                 if (ac instanceof AccessibleComponent) {
    8580                     return ((AccessibleComponent) ac).isEnabled();
    8581                 } else {
    8582                     Component c = getCurrentComponent();
    8583                     if (c != null) {
    8584                         return c.isEnabled();
    8585                     } else {
    8586                         return false;
    8587                     }
    8588                 }
    8589             }
    8590
    8591             /**
    8592              * Sets the enabled state of the object.
    8593              *
    8594              * @param b if true, enables this object; otherwise, disables it
    8595              */
    8596             public void setEnabled(boolean b) {
    8597                 AccessibleContext ac = getCurrentAccessibleContext();
    8598                 if (ac instanceof AccessibleComponent) {
    8599                     ((AccessibleComponent) ac).setEnabled(b);
    8600                 } else {
    8601                     Component c = getCurrentComponent();
    8602                     if (c != null) {
    8603                         c.setEnabled(b);
    8604                     }
    8605                 }
    8606             }
    8607
    8608             /**
    8609              * Determines if this object is visible.  Note: this means that the
    8610              * object intends to be visible; however, it may not in fact be
    8611              * showing on the screen because one of the objects that this object
    8612              * is contained by is not visible.  To determine if an object is
    8613              * showing on the screen, use <code>isShowing</code>.
    8614              *
    8615              * @return true if object is visible; otherwise, false
    8616              */
    8617             public boolean isVisible() {
    8618                 AccessibleContext ac = getCurrentAccessibleContext();
    8619                 if (ac instanceof AccessibleComponent) {
    8620                     return ((AccessibleComponent) ac).isVisible();
    8621                 } else {
    8622                     Component c = getCurrentComponent();
    8623                     if (c != null) {
    8624                         return c.isVisible();
    8625                     } else {
    8626                         return false;
    8627                     }
    8628                 }
    8629             }
    8630
    8631             /**
    8632              * Sets the visible state of the object.
    8633              *
    8634              * @param b if true, shows this object; otherwise, hides it
    8635              */
    8636             public void setVisible(boolean b) {
    8637                 AccessibleContext ac = getCurrentAccessibleContext();
    8638                 if (ac instanceof AccessibleComponent) {
    8639                     ((AccessibleComponent) ac).setVisible(b);
    8640                 } else {
    8641                     Component c = getCurrentComponent();
    8642                     if (c != null) {
    8643                         c.setVisible(b);
    8644                     }
    8645                 }
    8646             }
    8647
    8648             /**
    8649              * Determines if the object is showing.  This is determined
    8650              * by checking the visibility of the object and ancestors
    8651              * of the object.  Note: this will return true even if the
    8652              * object is obscured by another (for example,
    8653              * it happens to be underneath a menu that was pulled down).
    8654              *
    8655              * @return true if the object is showing; otherwise, false
    8656              */
    8657             public boolean isShowing() {
    8658                 AccessibleContext ac = getCurrentAccessibleContext();
    8659                 if (ac instanceof AccessibleComponent) {
    8660                     if (ac.getAccessibleParent() != null) {
    8661                         return ((AccessibleComponent) ac).isShowing();
    8662                     } else {
    8663                         // Fixes 4529616 - AccessibleJTableCell.isShowing()
    8664                         // returns false when the cell on the screen
    8665                         // if no parent
    8666                         return isVisible();
    8667                     }
    8668                 } else {
    8669                     Component c = getCurrentComponent();
    8670                     if (c != null) {
    8671                         return c.isShowing();
    8672                     } else {
    8673                         return false;
    8674                     }
    8675                 }
    8676             }
    8677
    8678             /**
    8679              * Checks whether the specified point is within this
    8680              * object's bounds, where the point's x and y coordinates
    8681              * are defined to be relative to the coordinate system of
    8682              * the object.
    8683              *
    8684              * @param p the <code>Point</code> relative to the
    8685              *    coordinate system of the object
    8686              * @return true if object contains <code>Point</code>;
    8687              *    otherwise false
    8688              */
    8689             public boolean contains(Point p) {
    8690                 AccessibleContext ac = getCurrentAccessibleContext();
    8691                 if (ac instanceof AccessibleComponent) {
    8692                     Rectangle r = ((AccessibleComponent) ac).getBounds();
    8693                     return r.contains(p);
    8694                 } else {
    8695                     Component c = getCurrentComponent();
    8696                     if (c != null) {
    8697                         Rectangle r = c.getBounds();
    8698                         return r.contains(p);
    8699                     } else {
    8700                         return getBounds().contains(p);
    8701                     }
    8702                 }
    8703             }
    8704
    8705             /**
    8706              * Returns the location of the object on the screen.
    8707              *
    8708              * @return location of object on screen -- can be
    8709              *    <code>null</code> if this object is not on the screen
    8710              */
    8711             public Point getLocationOnScreen() {
    8712                 if (parent != null && parent.isShowing()) {
    8713                     Point parentLocation = parent.getLocationOnScreen();
    8714                     Point componentLocation = getLocation();
    8715                     componentLocation.translate(parentLocation.x, parentLocation.y);
    8716                     return componentLocation;
    8717                 } else {
    8718                     return null;
    8719                 }
    8720             }
    8721
    8722             /**
    8723              * Gets the location of the object relative to the parent
    8724              * in the form of a point specifying the object's
    8725              * top-left corner in the screen's coordinate space.
    8726              *
    8727              * @return an instance of <code>Point</code> representing
    8728              *    the top-left corner of the object's bounds in the
    8729              *    coordinate space of the screen; <code>null</code> if
    8730              *    this object or its parent are not on the screen
    8731              */
    8732             public Point getLocation() {
    8733                 if (parent != null) {
    8734                     Rectangle r = parent.getCellRect(row, column, false);
    8735                     if (r != null) {
    8736                         return r.getLocation();
    8737                     }
    8738                 }
    8739                 return null;
    8740             }
    8741
    8742             /**
    8743              * Sets the location of the object relative to the parent.
    8744              */
    8745             public void setLocation(Point p) {
    8746 //              if ((parent != null)  && (parent.contains(p))) {
    8747 //                  ensureIndexIsVisible(indexInParent);
    8748 //              }
    8749             }
    8750
    8751             public Rectangle getBounds() {
    8752                 if (parent != null) {
    8753                     return parent.getCellRect(row, column, false);
    8754                 } else {
    8755                     return null;
    8756                 }
    8757             }
    8758
    8759             public void setBounds(Rectangle r) {
    8760                 AccessibleContext ac = getCurrentAccessibleContext();
    8761                 if (ac instanceof AccessibleComponent) {
    8762                     ((AccessibleComponent) ac).setBounds(r);
    8763                 } else {
    8764                     Component c = getCurrentComponent();
    8765                     if (c != null) {
    8766                         c.setBounds(r);
    8767                     }
    8768                 }
    8769             }
    8770
    8771             public Dimension getSize() {
    8772                 if (parent != null) {
    8773                     Rectangle r = parent.getCellRect(row, column, false);
    8774                     if (r != null) {
    8775                         return r.getSize();
    8776                     }
    8777                 }
    8778                 return null;
    8779             }
    8780
    8781             public void setSize (Dimension d) {
    8782                 AccessibleContext ac = getCurrentAccessibleContext();
    8783                 if (ac instanceof AccessibleComponent) {
    8784                     ((AccessibleComponent) ac).setSize(d);
    8785                 } else {
    8786                     Component c = getCurrentComponent();
    8787                     if (c != null) {
    8788                         c.setSize(d);
    8789                     }
    8790                 }
    8791             }
    8792
    8793             public Accessible getAccessibleAt(Point p) {
    8794                 AccessibleContext ac = getCurrentAccessibleContext();
    8795                 if (ac instanceof AccessibleComponent) {
    8796                     return ((AccessibleComponent) ac).getAccessibleAt(p);
    8797                 } else {
    8798                     return null;
    8799                 }
    8800             }
    8801
    8802             @SuppressWarnings("deprecation")
    8803             public boolean isFocusTraversable() {
    8804                 AccessibleContext ac = getCurrentAccessibleContext();
    8805                 if (ac instanceof AccessibleComponent) {
    8806                     return ((AccessibleComponent) ac).isFocusTraversable();
    8807                 } else {
    8808                     Component c = getCurrentComponent();
    8809                     if (c != null) {
    8810                         return c.isFocusTraversable();
    8811                     } else {
    8812                         return false;
    8813                     }
    8814                 }
    8815             }
    8816
    8817             public void requestFocus() {
    8818                 AccessibleContext ac = getCurrentAccessibleContext();
    8819                 if (ac instanceof AccessibleComponent) {
    8820                     ((AccessibleComponent) ac).requestFocus();
    8821                 } else {
    8822                     Component c = getCurrentComponent();
    8823                     if (c != null) {
    8824                         c.requestFocus();
    8825                     }
    8826                 }
    8827             }
    8828
    8829             public void addFocusListener(FocusListener l) {
    8830                 AccessibleContext ac = getCurrentAccessibleContext();
    8831                 if (ac instanceof AccessibleComponent) {
    8832                     ((AccessibleComponent) ac).addFocusListener(l);
    8833                 } else {
    8834                     Component c = getCurrentComponent();
    8835                     if (c != null) {
    8836                         c.addFocusListener(l);
    8837                     }
    8838                 }
    8839             }
    8840
    8841             public void removeFocusListener(FocusListener l) {
    8842                 AccessibleContext ac = getCurrentAccessibleContext();
    8843                 if (ac instanceof AccessibleComponent) {
    8844                     ((AccessibleComponent) ac).removeFocusListener(l);
    8845                 } else {
    8846                     Component c = getCurrentComponent();
    8847                     if (c != null) {
    8848                         c.removeFocusListener(l);
    8849                     }
    8850                 }
    8851             }
    8852
    8853         } // inner class AccessibleJTableCell
    8854
    8855         // Begin AccessibleJTableHeader ========== // TIGER - 4715503
    8856
    8857         /**
    8858          * This class implements accessibility for JTable header cells.
    8859          */
    8860         private class AccessibleJTableHeaderCell extends AccessibleContext
    8861             implements Accessible, AccessibleComponent {
    8862
    8863             private int row;
    8864             private int column;
    8865             private JTableHeader parent;
    8866             private Component rendererComponent;
    8867
    8868             /**
    8869              * Constructs an <code>AccessibleJTableHeaderEntry</code> instance.
    8870              *
    8871              * @param row header cell row index
    8872              * @param column header cell column index
    8873              * @param parent header cell parent
    8874              * @param rendererComponent component that renders the header cell
    8875              */
    8876             public AccessibleJTableHeaderCell(int row, int column,
    8877                                               JTableHeader parent,
    8878                                               Component rendererComponent) {
    8879                 this.row = row;
    8880                 this.column = column;
    8881                 this.parent = parent;
    8882                 this.rendererComponent = rendererComponent;
    8883                 this.setAccessibleParent(parent);
    8884             }
    8885
    8886             /**
    8887              * Gets the <code>AccessibleContext</code> associated with this
    8888              * component. In the implementation of the Java Accessibility
    8889              * API for this class, return this object, which is its own
    8890              * <code>AccessibleContext</code>.
    8891              *
    8892              * @return this object
    8893              */
    8894             public AccessibleContext getAccessibleContext() {
    8895                 return this;
    8896             }
    8897
    8898             /*
    8899              * Returns the AccessibleContext for the header cell
    8900              * renderer.
    8901              */
    8902             private AccessibleContext getCurrentAccessibleContext() {
    8903                 return rendererComponent.getAccessibleContext();
    8904             }
    8905
    8906             /*
    8907              * Returns the component that renders the header cell.
    8908              */
    8909             private Component getCurrentComponent() {
    8910                 return rendererComponent;
    8911             }
    8912
    8913             // AccessibleContext methods ==========
    8914
    8915             /**
    8916              * Gets the accessible name of this object.
    8917              *
    8918              * @return the localized name of the object; <code>null</code>
    8919              *     if this object does not have a name
    8920              */
    8921             public String getAccessibleName() {
    8922                 AccessibleContext ac = getCurrentAccessibleContext();
    8923                 if (ac != null) {
    8924                     String name = ac.getAccessibleName();
    8925                     if ((name != null) && (name != "")) {
    8926                         return ac.getAccessibleName();
    8927                     }
    8928                 }
    8929                 if ((accessibleName != null) && (accessibleName != "")) {
    8930                     return accessibleName;
    8931                 } else {
    8932                     return null;
    8933                 }
    8934             }
    8935
    8936             /**
    8937              * Sets the localized accessible name of this object.
    8938              *
    8939              * @param s the new localized name of the object
    8940              */
    8941             public void setAccessibleName(String s) {
    8942                 AccessibleContext ac = getCurrentAccessibleContext();
    8943                 if (ac != null) {
    8944                     ac.setAccessibleName(s);
    8945                 } else {
    8946                     super.setAccessibleName(s);
    8947                 }
    8948             }
    8949
    8950             /**
    8951              * Gets the accessible description of this object.
    8952              *
    8953              * @return the localized description of the object;
    8954              *     <code>null</code> if this object does not have
    8955              *     a description
    8956              */
    8957             public String getAccessibleDescription() {
    8958                 AccessibleContext ac = getCurrentAccessibleContext();
    8959                 if (ac != null) {
    8960                     return ac.getAccessibleDescription();
    8961                 } else {
    8962                     return super.getAccessibleDescription();
    8963                 }
    8964             }
    8965
    8966             /**
    8967              * Sets the accessible description of this object.
    8968              *
    8969              * @param s the new localized description of the object
    8970              */
    8971             public void setAccessibleDescription(String s) {
    8972                 AccessibleContext ac = getCurrentAccessibleContext();
    8973                 if (ac != null) {
    8974                     ac.setAccessibleDescription(s);
    8975                 } else {
    8976                     super.setAccessibleDescription(s);
    8977                 }
    8978             }
    8979
    8980             /**
    8981              * Gets the role of this object.
    8982              *
    8983              * @return an instance of <code>AccessibleRole</code>
    8984              *      describing the role of the object
    8985              * @see AccessibleRole
    8986              */
    8987             public AccessibleRole getAccessibleRole() {
    8988                 AccessibleContext ac = getCurrentAccessibleContext();
    8989                 if (ac != null) {
    8990                     return ac.getAccessibleRole();
    8991                 } else {
    8992                     return AccessibleRole.UNKNOWN;
    8993                 }
    8994             }
    8995
    8996             /**
    8997              * Gets the state set of this object.
    8998              *
    8999              * @return an instance of <code>AccessibleStateSet</code>
    9000              *     containing the current state set of the object
    9001              * @see AccessibleState
    9002              */
    9003             public AccessibleStateSet getAccessibleStateSet() {
    9004                 AccessibleContext ac = getCurrentAccessibleContext();
    9005                 AccessibleStateSet as = null;
    9006
    9007                 if (ac != null) {
    9008                     as = ac.getAccessibleStateSet();
    9009                 }
    9010                 if (as == null) {
    9011                     as = new AccessibleStateSet();
    9012                 }
    9013                 Rectangle rjt = JTable.this.getVisibleRect();
    9014                 Rectangle rcell = JTable.this.getCellRect(row, column, false);
    9015                 if (rjt.intersects(rcell)) {
    9016                     as.add(AccessibleState.SHOWING);
    9017                 } else {
    9018                     if (as.contains(AccessibleState.SHOWING)) {
    9019                          as.remove(AccessibleState.SHOWING);
    9020                     }
    9021                 }
    9022                 if (JTable.this.isCellSelected(row, column)) {
    9023                     as.add(AccessibleState.SELECTED);
    9024                 } else if (as.contains(AccessibleState.SELECTED)) {
    9025                     as.remove(AccessibleState.SELECTED);
    9026                 }
    9027                 if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
    9028                     as.add(AccessibleState.ACTIVE);
    9029                 }
    9030                 as.add(AccessibleState.TRANSIENT);
    9031                 return as;
    9032             }
    9033
    9034             /**
    9035              * Gets the <code>Accessible</code> parent of this object.
    9036              *
    9037              * @return the Accessible parent of this object;
    9038              *     <code>null</code> if this object does not
    9039              *     have an <code>Accessible</code> parent
    9040              */
    9041             public Accessible getAccessibleParent() {
    9042                 return parent;
    9043             }
    9044
    9045             /**
    9046              * Gets the index of this object in its accessible parent.
    9047              *
    9048              * @return the index of this object in its parent; -1 if this
    9049              *     object does not have an accessible parent
    9050              * @see #getAccessibleParent
    9051              */
    9052             public int getAccessibleIndexInParent() {
    9053                 return column;
    9054             }
    9055
    9056             /**
    9057              * Returns the number of accessible children in the object.
    9058              *
    9059              * @return the number of accessible children in the object
    9060              */
    9061             public int getAccessibleChildrenCount() {
    9062                 AccessibleContext ac = getCurrentAccessibleContext();
    9063                 if (ac != null) {
    9064                     return ac.getAccessibleChildrenCount();
    9065                 } else {
    9066                     return 0;
    9067                 }
    9068             }
    9069
    9070             /**
    9071              * Returns the specified <code>Accessible</code> child of the
    9072              * object.
    9073              *
    9074              * @param i zero-based index of child
    9075              * @return the <code>Accessible</code> child of the object
    9076              */
    9077             public Accessible getAccessibleChild(int i) {
    9078                 AccessibleContext ac = getCurrentAccessibleContext();
    9079                 if (ac != null) {
    9080                     Accessible accessibleChild = ac.getAccessibleChild(i);
    9081                     ac.setAccessibleParent(this);
    9082                     return accessibleChild;
    9083                 } else {
    9084                     return null;
    9085                 }
    9086             }
    9087
    9088             /**
    9089              * Gets the locale of the component. If the component
    9090              * does not have a locale, then the locale of its parent
    9091              * is returned.
    9092              *
    9093              * @return this component's locale; if this component does
    9094              *    not have a locale, the locale of its parent is returned
    9095              * @exception IllegalComponentStateException if the
    9096              *    <code>Component</code> does not have its own locale
    9097              *    and has not yet been added to a containment hierarchy
    9098              *    such that the locale can be determined from the
    9099              *    containing parent
    9100              * @see #setLocale
    9101              */
    9102             public Locale getLocale() {
    9103                 AccessibleContext ac = getCurrentAccessibleContext();
    9104                 if (ac != null) {
    9105                     return ac.getLocale();
    9106                 } else {
    9107                     return null;
    9108                 }
    9109             }
    9110
    9111             /**
    9112              * Adds a <code>PropertyChangeListener</code> to the listener list.
    9113              * The listener is registered for all properties.
    9114              *
    9115              * @param l  the <code>PropertyChangeListener</code>
    9116              *     to be added
    9117              */
    9118             public void addPropertyChangeListener(PropertyChangeListener l) {
    9119                 AccessibleContext ac = getCurrentAccessibleContext();
    9120                 if (ac != null) {
    9121                     ac.addPropertyChangeListener(l);
    9122                 } else {
    9123                     super.addPropertyChangeListener(l);
    9124                 }
    9125             }
    9126
    9127             /**
    9128              * Removes a <code>PropertyChangeListener</code> from the
    9129              * listener list. This removes a <code>PropertyChangeListener</code>
    9130              * that was registered for all properties.
    9131              *
    9132              * @param l  the <code>PropertyChangeListener</code>
    9133              *    to be removed
    9134              */
    9135             public void removePropertyChangeListener(PropertyChangeListener l) {
    9136                 AccessibleContext ac = getCurrentAccessibleContext();
    9137                 if (ac != null) {
    9138                     ac.removePropertyChangeListener(l);
    9139                 } else {
    9140                     super.removePropertyChangeListener(l);
    9141                 }
    9142             }
    9143
    9144             /**
    9145              * Gets the <code>AccessibleAction</code> associated with this
    9146              * object if one exists.  Otherwise returns <code>null</code>.
    9147              *
    9148              * @return the <code>AccessibleAction</code>, or <code>null</code>
    9149              */
    9150             public AccessibleAction getAccessibleAction() {
    9151                 return getCurrentAccessibleContext().getAccessibleAction();
    9152             }
    9153
    9154             /**
    9155              * Gets the <code>AccessibleComponent</code> associated with
    9156              * this object if one exists.  Otherwise returns <code>null</code>.
    9157              *
    9158              * @return the <code>AccessibleComponent</code>, or
    9159              *    <code>null</code>
    9160              */
    9161             public AccessibleComponent getAccessibleComponent() {
    9162                 return this; // to override getBounds()
    9163             }
    9164
    9165             /**
    9166              * Gets the <code>AccessibleSelection</code> associated with
    9167              * this object if one exists.  Otherwise returns <code>null</code>.
    9168              *
    9169              * @return the <code>AccessibleSelection</code>, or
    9170              *    <code>null</code>
    9171              */
    9172             public AccessibleSelection getAccessibleSelection() {
    9173                 return getCurrentAccessibleContext().getAccessibleSelection();
    9174             }
    9175
    9176             /**
    9177              * Gets the <code>AccessibleText</code> associated with this
    9178              * object if one exists.  Otherwise returns <code>null</code>.
    9179              *
    9180              * @return the <code>AccessibleText</code>, or <code>null</code>
    9181              */
    9182             public AccessibleText getAccessibleText() {
    9183                 return getCurrentAccessibleContext().getAccessibleText();
    9184             }
    9185
    9186             /**
    9187              * Gets the <code>AccessibleValue</code> associated with
    9188              * this object if one exists.  Otherwise returns <code>null</code>.
    9189              *
    9190              * @return the <code>AccessibleValue</code>, or <code>null</code>
    9191              */
    9192             public AccessibleValue getAccessibleValue() {
    9193                 return getCurrentAccessibleContext().getAccessibleValue();
    9194             }
    9195
    9196
    9197             // AccessibleComponent methods ==========
    9198
    9199             /**
    9200              * Gets the background color of this object.
    9201              *
    9202              * @return the background color, if supported, of the object;
    9203              *     otherwise, <code>null</code>
    9204              */
    9205             public Color getBackground() {
    9206                 AccessibleContext ac = getCurrentAccessibleContext();
    9207                 if (ac instanceof AccessibleComponent) {
    9208                     return ((AccessibleComponent) ac).getBackground();
    9209                 } else {
    9210                     Component c = getCurrentComponent();
    9211                     if (c != null) {
    9212                         return c.getBackground();
    9213                     } else {
    9214                         return null;
    9215                     }
    9216                 }
    9217             }
    9218
    9219             /**
    9220              * Sets the background color of this object.
    9221              *
    9222              * @param c the new <code>Color</code> for the background
    9223              */
    9224             public void setBackground(Color c) {
    9225                 AccessibleContext ac = getCurrentAccessibleContext();
    9226                 if (ac instanceof AccessibleComponent) {
    9227                     ((AccessibleComponent) ac).setBackground(c);
    9228                 } else {
    9229                     Component cp = getCurrentComponent();
    9230                     if (cp != null) {
    9231                         cp.setBackground(c);
    9232                     }
    9233                 }
    9234             }
    9235
    9236             /**
    9237              * Gets the foreground color of this object.
    9238              *
    9239              * @return the foreground color, if supported, of the object;
    9240              *     otherwise, <code>null</code>
    9241              */
    9242             public Color getForeground() {
    9243                 AccessibleContext ac = getCurrentAccessibleContext();
    9244                 if (ac instanceof AccessibleComponent) {
    9245                     return ((AccessibleComponent) ac).getForeground();
    9246                 } else {
    9247                     Component c = getCurrentComponent();
    9248                     if (c != null) {
    9249                         return c.getForeground();
    9250                     } else {
    9251                         return null;
    9252                     }
    9253                 }
    9254             }
    9255
    9256             /**
    9257              * Sets the foreground color of this object.
    9258              *
    9259              * @param c the new <code>Color</code> for the foreground
    9260              */
    9261             public void setForeground(Color c) {
    9262                 AccessibleContext ac = getCurrentAccessibleContext();
    9263                 if (ac instanceof AccessibleComponent) {
    9264                     ((AccessibleComponent) ac).setForeground(c);
    9265                 } else {
    9266                     Component cp = getCurrentComponent();
    9267                     if (cp != null) {
    9268                         cp.setForeground(c);
    9269                     }
    9270                 }
    9271             }
    9272
    9273             /**
    9274              * Gets the <code>Cursor</code> of this object.
    9275              *
    9276              * @return the <code>Cursor</code>, if supported,
    9277              *    of the object; otherwise, <code>null</code>
    9278              */
    9279             public Cursor getCursor() {
    9280                 AccessibleContext ac = getCurrentAccessibleContext();
    9281                 if (ac instanceof AccessibleComponent) {
    9282                     return ((AccessibleComponent) ac).getCursor();
    9283                 } else {
    9284                     Component c = getCurrentComponent();
    9285                     if (c != null) {
    9286                         return c.getCursor();
    9287                     } else {
    9288                         Accessible ap = getAccessibleParent();
    9289                         if (ap instanceof AccessibleComponent) {
    9290                             return ((AccessibleComponent) ap).getCursor();
    9291                         } else {
    9292                             return null;
    9293                         }
    9294                     }
    9295                 }
    9296             }
    9297
    9298             /**
    9299              * Sets the <code>Cursor</code> of this object.
    9300              *
    9301              * @param c the new <code>Cursor</code> for the object
    9302              */
    9303             public void setCursor(Cursor c) {
    9304                 AccessibleContext ac = getCurrentAccessibleContext();
    9305                 if (ac instanceof AccessibleComponent) {
    9306                     ((AccessibleComponent) ac).setCursor(c);
    9307                 } else {
    9308                     Component cp = getCurrentComponent();
    9309                     if (cp != null) {
    9310                         cp.setCursor(c);
    9311                     }
    9312                 }
    9313             }
    9314
    9315             /**
    9316              * Gets the <code>Font</code> of this object.
    9317              *
    9318              * @return the <code>Font</code>,if supported,
    9319              *   for the object; otherwise, <code>null</code>
    9320              */
    9321             public Font getFont() {
    9322                 AccessibleContext ac = getCurrentAccessibleContext();
    9323                 if (ac instanceof AccessibleComponent) {
    9324                     return ((AccessibleComponent) ac).getFont();
    9325                 } else {
    9326                     Component c = getCurrentComponent();
    9327                     if (c != null) {
    9328                         return c.getFont();
    9329                     } else {
    9330                         return null;
    9331                     }
    9332                 }
    9333             }
    9334
    9335             /**
    9336              * Sets the <code>Font</code> of this object.
    9337              *
    9338              * @param f the new <code>Font</code> for the object
    9339              */
    9340             public void setFont(Font f) {
    9341                 AccessibleContext ac = getCurrentAccessibleContext();
    9342                 if (ac instanceof AccessibleComponent) {
    9343                     ((AccessibleComponent) ac).setFont(f);
    9344                 } else {
    9345                     Component c = getCurrentComponent();
    9346                     if (c != null) {
    9347                         c.setFont(f);
    9348                     }
    9349                 }
    9350             }
    9351
    9352             /**
    9353              * Gets the <code>FontMetrics</code> of this object.
    9354              *
    9355              * @param f the <code>Font</code>
    9356              * @return the <code>FontMetrics</code> object, if supported;
    9357              *    otherwise <code>null</code>
    9358              * @see #getFont
    9359              */
    9360             public FontMetrics getFontMetrics(Font f) {
    9361                 AccessibleContext ac = getCurrentAccessibleContext();
    9362                 if (ac instanceof AccessibleComponent) {
    9363                     return ((AccessibleComponent) ac).getFontMetrics(f);
    9364                 } else {
    9365                     Component c = getCurrentComponent();
    9366                     if (c != null) {
    9367                         return c.getFontMetrics(f);
    9368                     } else {
    9369                         return null;
    9370                     }
    9371                 }
    9372             }
    9373
    9374             /**
    9375              * Determines if the object is enabled.
    9376              *
    9377              * @return true if object is enabled; otherwise, false
    9378              */
    9379             public boolean isEnabled() {
    9380                 AccessibleContext ac = getCurrentAccessibleContext();
    9381                 if (ac instanceof AccessibleComponent) {
    9382                     return ((AccessibleComponent) ac).isEnabled();
    9383                 } else {
    9384                     Component c = getCurrentComponent();
    9385                     if (c != null) {
    9386                         return c.isEnabled();
    9387                     } else {
    9388                         return false;
    9389                     }
    9390                 }
    9391             }
    9392
    9393             /**
    9394              * Sets the enabled state of the object.
    9395              *
    9396              * @param b if true, enables this object; otherwise, disables it
    9397              */
    9398             public void setEnabled(boolean b) {
    9399                 AccessibleContext ac = getCurrentAccessibleContext();
    9400                 if (ac instanceof AccessibleComponent) {
    9401                     ((AccessibleComponent) ac).setEnabled(b);
    9402                 } else {
    9403                     Component c = getCurrentComponent();
    9404                     if (c != null) {
    9405                         c.setEnabled(b);
    9406                     }
    9407                 }
    9408             }
    9409
    9410             /**
    9411              * Determines if this object is visible.  Note: this means that the
    9412              * object intends to be visible; however, it may not in fact be
    9413              * showing on the screen because one of the objects that this object
    9414              * is contained by is not visible.  To determine if an object is
    9415              * showing on the screen, use <code>isShowing</code>.
    9416              *
    9417              * @return true if object is visible; otherwise, false
    9418              */
    9419             public boolean isVisible() {
    9420                 AccessibleContext ac = getCurrentAccessibleContext();
    9421                 if (ac instanceof AccessibleComponent) {
    9422                     return ((AccessibleComponent) ac).isVisible();
    9423                 } else {
    9424                     Component c = getCurrentComponent();
    9425                     if (c != null) {
    9426                         return c.isVisible();
    9427                     } else {
    9428                         return false;
    9429                     }
    9430                 }
    9431             }
    9432
    9433             /**
    9434              * Sets the visible state of the object.
    9435              *
    9436              * @param b if true, shows this object; otherwise, hides it
    9437              */
    9438             public void setVisible(boolean b) {
    9439                 AccessibleContext ac = getCurrentAccessibleContext();
    9440                 if (ac instanceof AccessibleComponent) {
    9441                     ((AccessibleComponent) ac).setVisible(b);
    9442                 } else {
    9443                     Component c = getCurrentComponent();
    9444                     if (c != null) {
    9445                         c.setVisible(b);
    9446                     }
    9447                 }
    9448             }
    9449
    9450             /**
    9451              * Determines if the object is showing.  This is determined
    9452              * by checking the visibility of the object and ancestors
    9453              * of the object.  Note: this will return true even if the
    9454              * object is obscured by another (for example,
    9455              * it happens to be underneath a menu that was pulled down).
    9456              *
    9457              * @return true if the object is showing; otherwise, false
    9458              */
    9459             public boolean isShowing() {
    9460                 AccessibleContext ac = getCurrentAccessibleContext();
    9461                 if (ac instanceof AccessibleComponent) {
    9462                     if (ac.getAccessibleParent() != null) {
    9463                         return ((AccessibleComponent) ac).isShowing();
    9464                     } else {
    9465                         // Fixes 4529616 - AccessibleJTableCell.isShowing()
    9466                         // returns false when the cell on the screen
    9467                         // if no parent
    9468                         return isVisible();
    9469                     }
    9470                 } else {
    9471                     Component c = getCurrentComponent();
    9472                     if (c != null) {
    9473                         return c.isShowing();
    9474                     } else {
    9475                         return false;
    9476                     }
    9477                 }
    9478             }
    9479
    9480             /**
    9481              * Checks whether the specified point is within this
    9482              * object's bounds, where the point's x and y coordinates
    9483              * are defined to be relative to the coordinate system of
    9484              * the object.
    9485              *
    9486              * @param p the <code>Point</code> relative to the
    9487              *    coordinate system of the object
    9488              * @return true if object contains <code>Point</code>;
    9489              *    otherwise false
    9490              */
    9491             public boolean contains(Point p) {
    9492                 AccessibleContext ac = getCurrentAccessibleContext();
    9493                 if (ac instanceof AccessibleComponent) {
    9494                     Rectangle r = ((AccessibleComponent) ac).getBounds();
    9495                     return r.contains(p);
    9496                 } else {
    9497                     Component c = getCurrentComponent();
    9498                     if (c != null) {
    9499                         Rectangle r = c.getBounds();
    9500                         return r.contains(p);
    9501                     } else {
    9502                         return getBounds().contains(p);
    9503                     }
    9504                 }
    9505             }
    9506
    9507             /**
    9508              * Returns the location of the object on the screen.
    9509              *
    9510              * @return location of object on screen -- can be
    9511              *    <code>null</code> if this object is not on the screen
    9512              */
    9513             public Point getLocationOnScreen() {
    9514                 if (parent != null && parent.isShowing()) {
    9515                     Point parentLocation = parent.getLocationOnScreen();
    9516                     Point componentLocation = getLocation();
    9517                     componentLocation.translate(parentLocation.x, parentLocation.y);
    9518                     return componentLocation;
    9519                 } else {
    9520                     return null;
    9521                 }
    9522             }
    9523
    9524             /**
    9525              * Gets the location of the object relative to the parent
    9526              * in the form of a point specifying the object's
    9527              * top-left corner in the screen's coordinate space.
    9528              *
    9529              * @return an instance of <code>Point</code> representing
    9530              *    the top-left corner of the object's bounds in the
    9531              *    coordinate space of the screen; <code>null</code> if
    9532              *    this object or its parent are not on the screen
    9533              */
    9534             public Point getLocation() {
    9535                 if (parent != null) {
    9536                     Rectangle r = parent.getHeaderRect(column);
    9537                     if (r != null) {
    9538                         return r.getLocation();
    9539                     }
    9540                 }
    9541                 return null;
    9542             }
    9543
    9544             /**
    9545              * Sets the location of the object relative to the parent.
    9546              * @param p the new position for the top-left corner
    9547              * @see #getLocation
    9548              */
    9549             public void setLocation(Point p) {
    9550             }
    9551
    9552             /**
    9553              * Gets the bounds of this object in the form of a Rectangle object.
    9554              * The bounds specify this object's width, height, and location
    9555              * relative to its parent.
    9556              *
    9557              * @return A rectangle indicating this component's bounds; null if
    9558              * this object is not on the screen.
    9559              * @see #contains
    9560              */
    9561             public Rectangle getBounds() {
    9562                 if (parent != null) {
    9563                     return parent.getHeaderRect(column);
    9564                 } else {
    9565                     return null;
    9566                 }
    9567             }
    9568
    9569             /**
    9570              * Sets the bounds of this object in the form of a Rectangle object.
    9571              * The bounds specify this object's width, height, and location
    9572              * relative to its parent.
    9573              *
    9574              * @param r rectangle indicating this component's bounds
    9575              * @see #getBounds
    9576              */
    9577             public void setBounds(Rectangle r) {
    9578                 AccessibleContext ac = getCurrentAccessibleContext();
    9579                 if (ac instanceof AccessibleComponent) {
    9580                     ((AccessibleComponent) ac).setBounds(r);
    9581                 } else {
    9582                     Component c = getCurrentComponent();
    9583                     if (c != null) {
    9584                         c.setBounds(r);
    9585                     }
    9586                 }
    9587             }
    9588
    9589             /**
    9590              * Returns the size of this object in the form of a Dimension object.
    9591              * The height field of the Dimension object contains this object's
    9592              * height, and the width field of the Dimension object contains this
    9593              * object's width.
    9594              *
    9595              * @return A Dimension object that indicates the size of this component;
    9596              * null if this object is not on the screen
    9597              * @see #setSize
    9598              */
    9599             public Dimension getSize() {
    9600                 if (parent != null) {
    9601                     Rectangle r = parent.getHeaderRect(column);
    9602                     if (r != null) {
    9603                         return r.getSize();
    9604                     }
    9605                 }
    9606                 return null;
    9607             }
    9608
    9609             /**
    9610              * Resizes this object so that it has width and height.
    9611              *
    9612              * @param d The dimension specifying the new size of the object.
    9613              * @see #getSize
    9614              */
    9615             public void setSize (Dimension d) {
    9616                 AccessibleContext ac = getCurrentAccessibleContext();
    9617                 if (ac instanceof AccessibleComponent) {
    9618                     ((AccessibleComponent) ac).setSize(d);
    9619                 } else {
    9620                     Component c = getCurrentComponent();
    9621                     if (c != null) {
    9622                         c.setSize(d);
    9623                     }
    9624                 }
    9625             }
    9626
    9627             /**
    9628              * Returns the Accessible child, if one exists, contained at the local
    9629              * coordinate Point.
    9630              *
    9631              * @param p The point relative to the coordinate system of this object.
    9632              * @return the Accessible, if it exists, at the specified location;
    9633              * otherwise null
    9634              */
    9635             public Accessible getAccessibleAt(Point p) {
    9636                 AccessibleContext ac = getCurrentAccessibleContext();
    9637                 if (ac instanceof AccessibleComponent) {
    9638                     return ((AccessibleComponent) ac).getAccessibleAt(p);
    9639                 } else {
    9640                     return null;
    9641                 }
    9642             }
    9643
    9644             /**
    9645              * Returns whether this object can accept focus or not.   Objects that
    9646              * can accept focus will also have the AccessibleState.FOCUSABLE state
    9647              * set in their AccessibleStateSets.
    9648              *
    9649              * @return true if object can accept focus; otherwise false
    9650              * @see AccessibleContext#getAccessibleStateSet
    9651              * @see AccessibleState#FOCUSABLE
    9652              * @see AccessibleState#FOCUSED
    9653              * @see AccessibleStateSet
    9654              */
    9655             @SuppressWarnings("deprecation")
    9656             public boolean isFocusTraversable() {
    9657                 AccessibleContext ac = getCurrentAccessibleContext();
    9658                 if (ac instanceof AccessibleComponent) {
    9659                     return ((AccessibleComponent) ac).isFocusTraversable();
    9660                 } else {
    9661                     Component c = getCurrentComponent();
    9662                     if (c != null) {
    9663                         return c.isFocusTraversable();
    9664                     } else {
    9665                         return false;
    9666                     }
    9667                 }
    9668             }
    9669
    9670             /**
    9671              * Requests focus for this object.  If this object cannot accept focus,
    9672              * nothing will happen.  Otherwise, the object will attempt to take
    9673              * focus.
    9674              * @see #isFocusTraversable
    9675              */
    9676             public void requestFocus() {
    9677                 AccessibleContext ac = getCurrentAccessibleContext();
    9678                 if (ac instanceof AccessibleComponent) {
    9679                     ((AccessibleComponent) ac).requestFocus();
    9680                 } else {
    9681                     Component c = getCurrentComponent();
    9682                     if (c != null) {
    9683                         c.requestFocus();
    9684                     }
    9685                 }
    9686             }
    9687
    9688             /**
    9689              * Adds the specified focus listener to receive focus events from this
    9690              * component.
    9691              *
    9692              * @param l the focus listener
    9693              * @see #removeFocusListener
    9694              */
    9695             public void addFocusListener(FocusListener l) {
    9696                 AccessibleContext ac = getCurrentAccessibleContext();
    9697                 if (ac instanceof AccessibleComponent) {
    9698                     ((AccessibleComponent) ac).addFocusListener(l);
    9699                 } else {
    9700                     Component c = getCurrentComponent();
    9701                     if (c != null) {
    9702                         c.addFocusListener(l);
    9703                     }
    9704                 }
    9705             }
    9706
    9707             /**
    9708              * Removes the specified focus listener so it no longer receives focus
    9709              * events from this component.
    9710              *
    9711              * @param l the focus listener
    9712              * @see #addFocusListener
    9713              */
    9714             public void removeFocusListener(FocusListener l) {
    9715                 AccessibleContext ac = getCurrentAccessibleContext();
    9716                 if (ac instanceof AccessibleComponent) {
    9717                     ((AccessibleComponent) ac).removeFocusListener(l);
    9718                 } else {
    9719                     Component c = getCurrentComponent();
    9720                     if (c != null) {
    9721                         c.removeFocusListener(l);
    9722                     }
    9723                 }
    9724             }
    9725
    9726         } // inner class AccessibleJTableHeaderCell
    9727
    9728     }  // inner class AccessibleJTable
    9729
    9730 }  // End of Class JTable