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

Save This Page
Home » openjdk-7 » javax » swing » [javadoc | source]