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