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