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