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