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