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     public Component prepareEditor(TableCellEditor editor, int row, int column) {
5814         Object value = getValueAt(row, column);
5815         boolean isSelected = isCellSelected(row, column);
5816         Component comp = editor.getTableCellEditorComponent(this, value, isSelected,
5817                                                   row, column);
5818         if (comp instanceof JComponent) {
5819             JComponent jComp = (JComponent)comp;
5820             if (jComp.getNextFocusableComponent() == null) {
5821                 jComp.setNextFocusableComponent(this);
5822             }
5823         }
5824         return comp;
5825     }
5826 
5827     /**
5828      * Discards the editor object and frees the real estate it used for
5829      * cell rendering.
5830      */
5831     public void removeEditor() {
5832         KeyboardFocusManager.getCurrentKeyboardFocusManager().
5833             removePropertyChangeListener("permanentFocusOwner", editorRemover);
5834         editorRemover = null;
5835 
5836         TableCellEditor editor = getCellEditor();
5837         if(editor != null) {
5838             editor.removeCellEditorListener(this);
5839             if (editorComp != null) {
5840                 Component focusOwner =
5841                         KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
5842                 boolean isFocusOwnerInTheTable = focusOwner != null?
5843                         SwingUtilities.isDescendingFrom(focusOwner, this):false;
5844                 remove(editorComp);
5845                 if(isFocusOwnerInTheTable) {
5846                     requestFocusInWindow();
5847                 }
5848             }
5849 
5850             Rectangle cellRect = getCellRect(editingRow, editingColumn, false);
5851 
5852             setCellEditor(null);
5853             setEditingColumn(-1);
5854             setEditingRow(-1);
5855             editorComp = null;
5856 
5857             repaint(cellRect);
5858         }
5859     }
5860 
5861 //
5862 // Serialization
5863 //
5864 
5865     /**
5866      * See readObject() and writeObject() in JComponent for more
5867      * information about serialization in Swing.
5868      */
5869     private void writeObject(ObjectOutputStream s) throws IOException {
5870         s.defaultWriteObject();
5871         if (getUIClassID().equals(uiClassID)) {
5872             byte count = JComponent.getWriteObjCounter(this);
5873             JComponent.setWriteObjCounter(this, --count);
5874             if (count == 0 && ui != null) {
5875                 ui.installUI(this);
5876             }
5877         }
5878     }
5879 
5880     private void readObject(ObjectInputStream s)
5881         throws IOException, ClassNotFoundException
5882     {
5883         ObjectInputStream.GetField f = s.readFields();
5884 
5885         TableModel newDataModel = (TableModel) f.get("dataModel", null);
5886         if (newDataModel == null) {
5887             throw new InvalidObjectException("Null dataModel");
5888         }
5889         dataModel = newDataModel;
5890 
5891         TableColumnModel newColumnModel = (TableColumnModel) f.get("columnModel", null);
5892         if (newColumnModel == null) {
5893             throw new InvalidObjectException("Null columnModel");
5894         }
5895         columnModel = newColumnModel;
5896 
5897         ListSelectionModel newSelectionModel = (ListSelectionModel) f.get("selectionModel", null);
5898         if (newSelectionModel == null) {
5899             throw new InvalidObjectException("Null selectionModel");
5900         }
5901         selectionModel = newSelectionModel;
5902 
5903         tableHeader = (JTableHeader) f.get("tableHeader", null);
5904         int newRowHeight = f.get("rowHeight", 0);
5905         if (newRowHeight <= 0) {
5906             throw new InvalidObjectException("Row height less than 1");
5907         }
5908         rowHeight = newRowHeight;
5909 
5910         rowMargin = f.get("rowMargin", 0);
5911         Color newGridColor = (Color) f.get("gridColor", null);
5912         if (newGridColor == null) {
5913             throw new InvalidObjectException("Null gridColor");
5914         }
5915         gridColor = newGridColor;
5916 
5917         showHorizontalLines = f.get("showHorizontalLines", false);
5918         showVerticalLines = f.get("showVerticalLines", false);
5919         int newAutoResizeMode = f.get("autoResizeMode", 0);
5920         if (!isValidAutoResizeMode(newAutoResizeMode)) {
5921             throw new InvalidObjectException("autoResizeMode is not valid");
5922         }
5923         autoResizeMode = newAutoResizeMode;
5924         autoCreateColumnsFromModel = f.get("autoCreateColumnsFromModel", false);
5925         preferredViewportSize = (Dimension) f.get("preferredViewportSize", null);
5926         rowSelectionAllowed = f.get("rowSelectionAllowed", false);
5927         cellSelectionEnabled = f.get("cellSelectionEnabled", false);
5928         selectionForeground = (Color) f.get("selectionForeground", null);
5929         selectionBackground = (Color) f.get("selectionBackground", null);
5930         rowModel = (SizeSequence) f.get("rowModel", null);
5931 
5932         boolean newDragEnabled = f.get("dragEnabled", false);
5933         checkDragEnabled(newDragEnabled);
5934         dragEnabled = newDragEnabled;
5935 
5936         surrendersFocusOnKeystroke = f.get("surrendersFocusOnKeystroke", false);
5937         editorRemover = (PropertyChangeListener) f.get("editorRemover", null);
5938         columnSelectionAdjusting = f.get("columnSelectionAdjusting", false);
5939         rowSelectionAdjusting = f.get("rowSelectionAdjusting", false);
5940         printError = (Throwable) f.get("printError", null);
5941         isRowHeightSet = f.get("isRowHeightSet", false);
5942         updateSelectionOnSort = f.get("updateSelectionOnSort", false);
5943         ignoreSortChange = f.get("ignoreSortChange", false);
5944         sorterChanged = f.get("sorterChanged", false);
5945         autoCreateRowSorter = f.get("autoCreateRowSorter", false);
5946         fillsViewportHeight = f.get("fillsViewportHeight", false);
5947         DropMode newDropMode = (DropMode) f.get("dropMode",
5948                 DropMode.USE_SELECTION);
5949         checkDropMode(newDropMode);
5950         dropMode = newDropMode;
5951 
5952         if ((ui != null) && (getUIClassID().equals(uiClassID))) {
5953             ui.installUI(this);
5954         }
5955         createDefaultRenderers();
5956         createDefaultEditors();
5957 
5958         // If ToolTipText != null, then the tooltip has already been
5959         // registered by JComponent.readObject() and we don't want
5960         // to re-register here
5961         if (getToolTipText() == null) {
5962             ToolTipManager.sharedInstance().registerComponent(this);
5963          }
5964     }
5965 
5966     /* Called from the JComponent's EnableSerializationFocusListener to
5967      * do any Swing-specific pre-serialization configuration.
5968      */
5969     void compWriteObjectNotify() {
5970         super.compWriteObjectNotify();
5971         // If ToolTipText != null, then the tooltip has already been
5972         // unregistered by JComponent.compWriteObjectNotify()
5973         if (getToolTipText() == null) {
5974             ToolTipManager.sharedInstance().unregisterComponent(this);
5975         }
5976     }
5977 
5978     /**
5979      * Returns a string representation of this table. This method
5980      * is intended to be used only for debugging purposes, and the
5981      * content and format of the returned string may vary between
5982      * implementations. The returned string may be empty but may not
5983      * be <code>null</code>.
5984      *
5985      * @return  a string representation of this table
5986      */
5987     protected String paramString() {
5988         String gridColorString = (gridColor != null ?
5989                                   gridColor.toString() : "");
5990         String showHorizontalLinesString = (showHorizontalLines ?
5991                                             "true" : "false");
5992         String showVerticalLinesString = (showVerticalLines ?
5993                                           "true" : "false");
5994         String autoResizeModeString;
5995         if (autoResizeMode == AUTO_RESIZE_OFF) {
5996             autoResizeModeString = "AUTO_RESIZE_OFF";
5997         } else if (autoResizeMode == AUTO_RESIZE_NEXT_COLUMN) {
5998             autoResizeModeString = "AUTO_RESIZE_NEXT_COLUMN";
5999         } else if (autoResizeMode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) {
6000             autoResizeModeString = "AUTO_RESIZE_SUBSEQUENT_COLUMNS";
6001         } else if (autoResizeMode == AUTO_RESIZE_LAST_COLUMN) {
6002             autoResizeModeString = "AUTO_RESIZE_LAST_COLUMN";
6003         } else if (autoResizeMode == AUTO_RESIZE_ALL_COLUMNS)  {
6004             autoResizeModeString = "AUTO_RESIZE_ALL_COLUMNS";
6005         } else autoResizeModeString = "";
6006         String autoCreateColumnsFromModelString = (autoCreateColumnsFromModel ?
6007                                                    "true" : "false");
6008         String preferredViewportSizeString = (preferredViewportSize != null ?
6009                                               preferredViewportSize.toString()
6010                                               : "");
6011         String rowSelectionAllowedString = (rowSelectionAllowed ?
6012                                             "true" : "false");
6013         String cellSelectionEnabledString = (cellSelectionEnabled ?
6014                                             "true" : "false");
6015         String selectionForegroundString = (selectionForeground != null ?
6016                                             selectionForeground.toString() :
6017                                             "");
6018         String selectionBackgroundString = (selectionBackground != null ?
6019                                             selectionBackground.toString() :
6020                                             "");
6021 
6022         return super.paramString() +
6023         ",autoCreateColumnsFromModel=" + autoCreateColumnsFromModelString +
6024         ",autoResizeMode=" + autoResizeModeString +
6025         ",cellSelectionEnabled=" + cellSelectionEnabledString +
6026         ",editingColumn=" + editingColumn +
6027         ",editingRow=" + editingRow +
6028         ",gridColor=" + gridColorString +
6029         ",preferredViewportSize=" + preferredViewportSizeString +
6030         ",rowHeight=" + rowHeight +
6031         ",rowMargin=" + rowMargin +
6032         ",rowSelectionAllowed=" + rowSelectionAllowedString +
6033         ",selectionBackground=" + selectionBackgroundString +
6034         ",selectionForeground=" + selectionForegroundString +
6035         ",showHorizontalLines=" + showHorizontalLinesString +
6036         ",showVerticalLines=" + showVerticalLinesString;
6037     }
6038 
6039     // This class tracks changes in the keyboard focus state. It is used
6040     // when the JTable is editing to determine when to cancel the edit.
6041     // If focus switches to a component outside of the jtable, but in the
6042     // same window, this will cancel editing.
6043     class CellEditorRemover implements PropertyChangeListener {
6044         KeyboardFocusManager focusManager;
6045 
6046         public CellEditorRemover(KeyboardFocusManager fm) {
6047             this.focusManager = fm;
6048         }
6049 
6050         public void propertyChange(PropertyChangeEvent ev) {
6051             if (!isEditing() || getClientProperty("terminateEditOnFocusLost") != Boolean.TRUE) {
6052                 return;
6053             }
6054 
6055             Component c = focusManager.getPermanentFocusOwner();
6056             while (c != null) {
6057                 if (c == JTable.this) {
6058                     // focus remains inside the table
6059                     return;
6060                 } else if ((c instanceof Window) ||
6061                            (c instanceof Applet && c.getParent() == null)) {
6062                     if (c == SwingUtilities.getRoot(JTable.this)) {
6063                         if (!getCellEditor().stopCellEditing()) {
6064                             getCellEditor().cancelCellEditing();
6065                         }
6066                     }
6067                     break;
6068                 }
6069                 c = c.getParent();
6070             }
6071         }
6072     }
6073 
6074 /////////////////
6075 // Printing Support
6076 /////////////////
6077 
6078     /**
6079      * A convenience method that displays a printing dialog, and then prints
6080      * this <code>JTable</code> in mode <code>PrintMode.FIT_WIDTH</code>,
6081      * with no header or footer text. A modal progress dialog, with an abort
6082      * option, will be shown for the duration of printing.
6083      * <p>
6084      * Note: In headless mode, no dialogs are shown and printing
6085      * occurs on the default printer.
6086      *
6087      * @return true, unless printing is cancelled by the user
6088      * @throws SecurityException if this thread is not allowed to
6089      *                           initiate a print job request
6090      * @throws PrinterException if an error in the print system causes the job
6091      *                          to be aborted
6092      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6093      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
6094      * @see #getPrintable
6095      *
6096      * @since 1.5
6097      */
6098     public boolean print() throws PrinterException {
6099 
6100         return print(PrintMode.FIT_WIDTH);
6101     }
6102 
6103     /**
6104      * A convenience method that displays a printing dialog, and then prints
6105      * this <code>JTable</code> in the given printing mode,
6106      * with no header or footer text. A modal progress dialog, with an abort
6107      * option, will be shown for the duration of printing.
6108      * <p>
6109      * Note: In headless mode, no dialogs are shown and printing
6110      * occurs on the default printer.
6111      *
6112      * @param  printMode        the printing mode that the printable should use
6113      * @return true, unless printing is cancelled by the user
6114      * @throws SecurityException if this thread is not allowed to
6115      *                           initiate a print job request
6116      * @throws PrinterException if an error in the print system causes the job
6117      *                          to be aborted
6118      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6119      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
6120      * @see #getPrintable
6121      *
6122      * @since 1.5
6123      */
6124     public boolean print(PrintMode printMode) throws PrinterException {
6125 
6126         return print(printMode, null, null);
6127     }
6128 
6129     /**
6130      * A convenience method that displays a printing dialog, and then prints
6131      * this <code>JTable</code> in the given printing mode,
6132      * with the specified header and footer text. A modal progress dialog,
6133      * with an abort option, will be shown for the duration of printing.
6134      * <p>
6135      * Note: In headless mode, no dialogs are shown and printing
6136      * occurs on the default printer.
6137      *
6138      * @param  printMode        the printing mode that the printable should use
6139      * @param  headerFormat     a <code>MessageFormat</code> specifying the text
6140      *                          to be used in printing a header,
6141      *                          or null for none
6142      * @param  footerFormat     a <code>MessageFormat</code> specifying the text
6143      *                          to be used in printing a footer,
6144      *                          or null for none
6145      * @return true, unless printing is cancelled by the user
6146      * @throws SecurityException if this thread is not allowed to
6147      *                           initiate a print job request
6148      * @throws PrinterException if an error in the print system causes the job
6149      *                          to be aborted
6150      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6151      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
6152      * @see #getPrintable
6153      *
6154      * @since 1.5
6155      */
6156     public boolean print(PrintMode printMode,
6157                          MessageFormat headerFormat,
6158                          MessageFormat footerFormat) throws PrinterException {
6159 
6160         boolean showDialogs = !GraphicsEnvironment.isHeadless();
6161         return print(printMode, headerFormat, footerFormat,
6162                      showDialogs, null, showDialogs);
6163     }
6164 
6165     /**
6166      * Prints this table, as specified by the fully featured
6167      * {@link #print(JTable.PrintMode, MessageFormat, MessageFormat,
6168      * boolean, PrintRequestAttributeSet, boolean, PrintService) print}
6169      * method, with the default printer specified as the print service.
6170      *
6171      * @param  printMode        the printing mode that the printable should use
6172      * @param  headerFormat     a <code>MessageFormat</code> specifying the text
6173      *                          to be used in printing a header,
6174      *                          or <code>null</code> for none
6175      * @param  footerFormat     a <code>MessageFormat</code> specifying the text
6176      *                          to be used in printing a footer,
6177      *                          or <code>null</code> for none
6178      * @param  showPrintDialog  whether or not to display a print dialog
6179      * @param  attr             a <code>PrintRequestAttributeSet</code>
6180      *                          specifying any printing attributes,
6181      *                          or <code>null</code> for none
6182      * @param  interactive      whether or not to print in an interactive mode
6183      * @return true, unless printing is cancelled by the user
6184      * @throws HeadlessException if the method is asked to show a printing
6185      *                           dialog or run interactively, and
6186      *                           <code>GraphicsEnvironment.isHeadless</code>
6187      *                           returns <code>true</code>
6188      * @throws SecurityException if this thread is not allowed to
6189      *                           initiate a print job request
6190      * @throws PrinterException if an error in the print system causes the job
6191      *                          to be aborted
6192      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6193      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
6194      * @see #getPrintable
6195      *
6196      * @since 1.5
6197      */
6198     public boolean print(PrintMode printMode,
6199                          MessageFormat headerFormat,
6200                          MessageFormat footerFormat,
6201                          boolean showPrintDialog,
6202                          PrintRequestAttributeSet attr,
6203                          boolean interactive) throws PrinterException,
6204                                                      HeadlessException {
6205 
6206         return print(printMode,
6207                      headerFormat,
6208                      footerFormat,
6209                      showPrintDialog,
6210                      attr,
6211                      interactive,
6212                      null);
6213     }
6214 
6215     /**
6216      * Prints this <code>JTable</code>. Takes steps that the majority of
6217      * developers would take in order to print a <code>JTable</code>.
6218      * In short, it prepares the table, calls <code>getPrintable</code> to
6219      * fetch an appropriate <code>Printable</code>, and then sends it to the
6220      * printer.
6221      * <p>
6222      * A <code>boolean</code> parameter allows you to specify whether or not
6223      * a printing dialog is displayed to the user. When it is, the user may
6224      * use the dialog to change the destination printer or printing attributes,
6225      * or even to cancel the print. Another two parameters allow for a
6226      * <code>PrintService</code> and printing attributes to be specified.
6227      * These parameters can be used either to provide initial values for the
6228      * print dialog, or to specify values when the dialog is not shown.
6229      * <p>
6230      * A second <code>boolean</code> parameter allows you to specify whether
6231      * or not to perform printing in an interactive mode. If <code>true</code>,
6232      * a modal progress dialog, with an abort option, is displayed for the
6233      * duration of printing . This dialog also prevents any user action which
6234      * may affect the table. However, it can not prevent the table from being
6235      * modified by code (for example, another thread that posts updates using
6236      * <code>SwingUtilities.invokeLater</code>). It is therefore the
6237      * responsibility of the developer to ensure that no other code modifies
6238      * the table in any way during printing (invalid modifications include
6239      * changes in: size, renderers, or underlying data). Printing behavior is
6240      * undefined when the table is changed during printing.
6241      * <p>
6242      * If <code>false</code> is specified for this parameter, no dialog will
6243      * be displayed and printing will begin immediately on the event-dispatch
6244      * thread. This blocks any other events, including repaints, from being
6245      * processed until printing is complete. Although this effectively prevents
6246      * the table from being changed, it doesn't provide a good user experience.
6247      * For this reason, specifying <code>false</code> is only recommended when
6248      * printing from an application with no visible GUI.
6249      * <p>
6250      * Note: Attempting to show the printing dialog or run interactively, while
6251      * in headless mode, will result in a <code>HeadlessException</code>.
6252      * <p>
6253      * Before fetching the printable, this method will gracefully terminate
6254      * editing, if necessary, to prevent an editor from showing in the printed
6255      * result. Additionally, <code>JTable</code> will prepare its renderers
6256      * during printing such that selection and focus are not indicated.
6257      * As far as customizing further how the table looks in the printout,
6258      * developers can provide custom renderers or paint code that conditionalize
6259      * on the value of {@link javax.swing.JComponent#isPaintingForPrint()}.
6260      * <p>
6261      * See {@link #getPrintable} for more description on how the table is
6262      * printed.
6263      *
6264      * @param  printMode        the printing mode that the printable should use
6265      * @param  headerFormat     a <code>MessageFormat</code> specifying the text
6266      *                          to be used in printing a header,
6267      *                          or <code>null</code> for none
6268      * @param  footerFormat     a <code>MessageFormat</code> specifying the text
6269      *                          to be used in printing a footer,
6270      *                          or <code>null</code> for none
6271      * @param  showPrintDialog  whether or not to display a print dialog
6272      * @param  attr             a <code>PrintRequestAttributeSet</code>
6273      *                          specifying any printing attributes,
6274      *                          or <code>null</code> for none
6275      * @param  interactive      whether or not to print in an interactive mode
6276      * @param  service          the destination <code>PrintService</code>,
6277      *                          or <code>null</code> to use the default printer
6278      * @return true, unless printing is cancelled by the user
6279      * @throws HeadlessException if the method is asked to show a printing
6280      *                           dialog or run interactively, and
6281      *                           <code>GraphicsEnvironment.isHeadless</code>
6282      *                           returns <code>true</code>
6283      * @throws  SecurityException if a security manager exists and its
6284      *          {@link java.lang.SecurityManager#checkPrintJobAccess}
6285      *          method disallows this thread from creating a print job request
6286      * @throws PrinterException if an error in the print system causes the job
6287      *                          to be aborted
6288      * @see #getPrintable
6289      * @see java.awt.GraphicsEnvironment#isHeadless
6290      *
6291      * @since 1.6
6292      */
6293     public boolean print(PrintMode printMode,
6294                          MessageFormat headerFormat,
6295                          MessageFormat footerFormat,
6296                          boolean showPrintDialog,
6297                          PrintRequestAttributeSet attr,
6298                          boolean interactive,
6299                          PrintService service) throws PrinterException,
6300                                                       HeadlessException {
6301 
6302         // complain early if an invalid parameter is specified for headless mode
6303         boolean isHeadless = GraphicsEnvironment.isHeadless();
6304         if (isHeadless) {
6305             if (showPrintDialog) {
6306                 throw new HeadlessException("Can't show print dialog.");
6307             }
6308 
6309             if (interactive) {
6310                 throw new HeadlessException("Can't run interactively.");
6311             }
6312         }
6313 
6314         // Get a PrinterJob.
6315         // Do this before anything with side-effects since it may throw a
6316         // security exception - in which case we don't want to do anything else.
6317         final PrinterJob job = PrinterJob.getPrinterJob();
6318 
6319         if (isEditing()) {
6320             // try to stop cell editing, and failing that, cancel it
6321             if (!getCellEditor().stopCellEditing()) {
6322                 getCellEditor().cancelCellEditing();
6323             }
6324         }
6325 
6326         if (attr == null) {
6327             attr = new HashPrintRequestAttributeSet();
6328         }
6329 
6330         final PrintingStatus printingStatus;
6331 
6332          // fetch the Printable
6333         Printable printable =
6334              getPrintable(printMode, headerFormat, footerFormat);
6335 
6336         if (interactive) {
6337             // wrap the Printable so that we can print on another thread
6338             printable = new ThreadSafePrintable(printable);
6339             printingStatus = PrintingStatus.createPrintingStatus(this, job);
6340             printable = printingStatus.createNotificationPrintable(printable);
6341         } else {
6342             // to please compiler
6343             printingStatus = null;
6344         }
6345 
6346         // set the printable on the PrinterJob
6347         job.setPrintable(printable);
6348 
6349         // if specified, set the PrintService on the PrinterJob
6350         if (service != null) {
6351             job.setPrintService(service);
6352         }
6353 
6354         // if requested, show the print dialog
6355         if (showPrintDialog && !job.printDialog(attr)) {
6356             // the user cancelled the print dialog
6357             return false;
6358         }
6359 
6360         // if not interactive, just print on this thread (no dialog)
6361         if (!interactive) {
6362             // do the printing
6363             job.print(attr);
6364 
6365             // we're done
6366             return true;
6367         }
6368 
6369         // make sure this is clear since we'll check it after
6370         printError = null;
6371 
6372         // to synchronize on
6373         final Object lock = new Object();
6374 
6375         // copied so we can access from the inner class
6376         final PrintRequestAttributeSet copyAttr = attr;
6377 
6378         // this runnable will be used to do the printing
6379         // (and save any throwables) on another thread
6380         Runnable runnable = new Runnable() {
6381             public void run() {
6382                 try {
6383                     // do the printing
6384                     job.print(copyAttr);
6385                 } catch (Throwable t) {
6386                     // save any Throwable to be rethrown
6387                     synchronized(lock) {
6388                         printError = t;
6389                     }
6390                 } finally {
6391                     // we're finished - hide the dialog
6392                     printingStatus.dispose();
6393                 }
6394             }
6395         };
6396 
6397         // start printing on another thread
6398         Thread th = new Thread(runnable);
6399         th.start();
6400 
6401         printingStatus.showModal(true);
6402 
6403         // look for any error that the printing may have generated
6404         Throwable pe;
6405         synchronized(lock) {
6406             pe = printError;
6407             printError = null;
6408         }
6409 
6410         // check the type of error and handle it
6411         if (pe != null) {
6412             // a subclass of PrinterException meaning the job was aborted,
6413             // in this case, by the user
6414             if (pe instanceof PrinterAbortException) {
6415                 return false;
6416             } else if (pe instanceof PrinterException) {
6417                 throw (PrinterException)pe;
6418             } else if (pe instanceof RuntimeException) {
6419                 throw (RuntimeException)pe;
6420             } else if (pe instanceof Error) {
6421                 throw (Error)pe;
6422             }
6423 
6424             // can not happen
6425             throw new AssertionError(pe);
6426         }
6427 
6428         return true;
6429     }
6430 
6431     /**
6432      * Return a <code>Printable</code> for use in printing this JTable.
6433      * <p>
6434      * This method is meant for those wishing to customize the default
6435      * <code>Printable</code> implementation used by <code>JTable</code>'s
6436      * <code>print</code> methods. Developers wanting simply to print the table
6437      * should use one of those methods directly.
6438      * <p>
6439      * The <code>Printable</code> can be requested in one of two printing modes.
6440      * In both modes, it spreads table rows naturally in sequence across
6441      * multiple pages, fitting as many rows as possible per page.
6442      * <code>PrintMode.NORMAL</code> specifies that the table be
6443      * printed at its current size. In this mode, there may be a need to spread
6444      * columns across pages in a similar manner to that of the rows. When the
6445      * need arises, columns are distributed in an order consistent with the
6446      * table's <code>ComponentOrientation</code>.
6447      * <code>PrintMode.FIT_WIDTH</code> specifies that the output be
6448      * scaled smaller, if necessary, to fit the table's entire width
6449      * (and thereby all columns) on each page. Width and height are scaled
6450      * equally, maintaining the aspect ratio of the output.
6451      * <p>
6452      * The <code>Printable</code> heads the portion of table on each page
6453      * with the appropriate section from the table's <code>JTableHeader</code>,
6454      * if it has one.
6455      * <p>
6456      * Header and footer text can be added to the output by providing
6457      * <code>MessageFormat</code> arguments. The printing code requests
6458      * Strings from the formats, providing a single item which may be included
6459      * in the formatted string: an <code>Integer</code> representing the current
6460      * page number.
6461      * <p>
6462      * You are encouraged to read the documentation for
6463      * <code>MessageFormat</code> as some characters, such as single-quote,
6464      * are special and need to be escaped.
6465      * <p>
6466      * Here's an example of creating a <code>MessageFormat</code> that can be
6467      * used to print "Duke's Table: Page - " and the current page number:
6468      *
6469      * <pre>
6470      *     // notice the escaping of the single quote
6471      *     // notice how the page number is included with "{0}"
6472      *     MessageFormat format = new MessageFormat("Duke''s Table: Page - {0}");
6473      * </pre>
6474      * <p>
6475      * The <code>Printable</code> constrains what it draws to the printable
6476      * area of each page that it prints. Under certain circumstances, it may
6477      * find it impossible to fit all of a page's content into that area. In
6478      * these cases the output may be clipped, but the implementation
6479      * makes an effort to do something reasonable. Here are a few situations
6480      * where this is known to occur, and how they may be handled by this
6481      * particular implementation:
6482      * <ul>
6483      *   <li>In any mode, when the header or footer text is too wide to fit
6484      *       completely in the printable area -- print as much of the text as
6485      *       possible starting from the beginning, as determined by the table's
6486      *       <code>ComponentOrientation</code>.
6487      *   <li>In any mode, when a row is too tall to fit in the
6488      *       printable area -- print the upper-most portion of the row
6489      *       and paint no lower border on the table.
6490      *   <li>In <code>PrintMode.NORMAL</code> when a column
6491      *       is too wide to fit in the printable area -- print the center
6492      *       portion of the column and leave the left and right borders
6493      *       off the table.
6494      * </ul>
6495      * <p>
6496      * It is entirely valid for this <code>Printable</code> to be wrapped
6497      * inside another in order to create complex reports and documents. You may
6498      * even request that different pages be rendered into different sized
6499      * printable areas. The implementation must be prepared to handle this
6500      * (possibly by doing its layout calculations on the fly). However,
6501      * providing different heights to each page will likely not work well
6502      * with <code>PrintMode.NORMAL</code> when it has to spread columns
6503      * across pages.
6504      * <p>
6505      * As far as customizing how the table looks in the printed result,
6506      * <code>JTable</code> itself will take care of hiding the selection
6507      * and focus during printing. For additional customizations, your
6508      * renderers or painting code can customize the look based on the value
6509      * of {@link javax.swing.JComponent#isPaintingForPrint()}
6510      * <p>
6511      * Also, <i>before</i> calling this method you may wish to <i>first</i>
6512      * modify the state of the table, such as to cancel cell editing or
6513      * have the user size the table appropriately. However, you must not
6514      * modify the state of the table <i>after</i> this <code>Printable</code>
6515      * has been fetched (invalid modifications include changes in size or
6516      * underlying data). The behavior of the returned <code>Printable</code>
6517      * is undefined once the table has been changed.
6518      *
6519      * @param  printMode     the printing mode that the printable should use
6520      * @param  headerFormat  a <code>MessageFormat</code> specifying the text to
6521      *                       be used in printing a header, or null for none
6522      * @param  footerFormat  a <code>MessageFormat</code> specifying the text to
6523      *                       be used in printing a footer, or null for none
6524      * @return a <code>Printable</code> for printing this JTable
6525      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6526      *             boolean, PrintRequestAttributeSet, boolean)
6527      * @see Printable
6528      * @see PrinterJob
6529      *
6530      * @since 1.5
6531      */
6532     public Printable getPrintable(PrintMode printMode,
6533                                   MessageFormat headerFormat,
6534                                   MessageFormat footerFormat) {
6535 
6536         return new TablePrintable(this, printMode, headerFormat, footerFormat);
6537     }
6538 
6539 
6540     /**
6541      * A <code>Printable</code> implementation that wraps another
6542      * <code>Printable</code>, making it safe for printing on another thread.
6543      */
6544     private class ThreadSafePrintable implements Printable {
6545 
6546         /** The delegate <code>Printable</code>. */
6547         private Printable printDelegate;
6548 
6549         /**
6550          * To communicate any return value when delegating.
6551          */
6552         private int retVal;
6553 
6554         /**
6555          * To communicate any <code>Throwable</code> when delegating.
6556          */
6557         private Throwable retThrowable;
6558 
6559         /**
6560          * Construct a <code>ThreadSafePrintable</code> around the given
6561          * delegate.
6562          *
6563          * @param printDelegate the <code>Printable</code> to delegate to
6564          */
6565         public ThreadSafePrintable(Printable printDelegate) {
6566             this.printDelegate = printDelegate;
6567         }
6568 
6569         /**
6570          * Prints the specified page into the given {@link Graphics}
6571          * context, in the specified format.
6572          * <p>
6573          * Regardless of what thread this method is called on, all calls into
6574          * the delegate will be done on the event-dispatch thread.
6575          *
6576          * @param   graphics    the context into which the page is drawn
6577          * @param   pageFormat  the size and orientation of the page being drawn
6578          * @param   pageIndex   the zero based index of the page to be drawn
6579          * @return  PAGE_EXISTS if the page is rendered successfully, or
6580          *          NO_SUCH_PAGE if a non-existent page index is specified
6581          * @throws  PrinterException if an error causes printing to be aborted
6582          */
6583         public int print(final Graphics graphics,
6584                          final PageFormat pageFormat,
6585                          final int pageIndex) throws PrinterException {
6586 
6587             // We'll use this Runnable
6588             Runnable runnable = new Runnable() {
6589                 public synchronized void run() {
6590                     try {
6591                         // call into the delegate and save the return value
6592                         retVal = printDelegate.print(graphics, pageFormat, pageIndex);
6593                     } catch (Throwable throwable) {
6594                         // save any Throwable to be rethrown
6595                         retThrowable = throwable;
6596                     } finally {
6597                         // notify the caller that we're done
6598                         notifyAll();
6599                     }
6600                 }
6601             };
6602 
6603             synchronized(runnable) {
6604                 // make sure these are initialized
6605                 retVal = -1;
6606                 retThrowable = null;
6607 
6608                 // call into the EDT
6609                 SwingUtilities.invokeLater(runnable);
6610 
6611                 // wait for the runnable to finish
6612                 while (retVal == -1 && retThrowable == null) {
6613                     try {
6614                         runnable.wait();
6615                     } catch (InterruptedException ie) {
6616                         // short process, safe to ignore interrupts
6617                     }
6618                 }
6619 
6620                 // if the delegate threw a throwable, rethrow it here
6621                 if (retThrowable != null) {
6622                     if (retThrowable instanceof PrinterException) {
6623                         throw (PrinterException)retThrowable;
6624                     } else if (retThrowable instanceof RuntimeException) {
6625                         throw (RuntimeException)retThrowable;
6626                     } else if (retThrowable instanceof Error) {
6627                         throw (Error)retThrowable;
6628                     }
6629 
6630                     // can not happen
6631                     throw new AssertionError(retThrowable);
6632                 }
6633 
6634                 return retVal;
6635             }
6636         }
6637     }
6638 
6639 /////////////////
6640 // Accessibility support
6641 ////////////////
6642 
6643     /**
6644      * Gets the AccessibleContext associated with this JTable.
6645      * For tables, the AccessibleContext takes the form of an
6646      * AccessibleJTable.
6647      * A new AccessibleJTable instance is created if necessary.
6648      *
6649      * @return an AccessibleJTable that serves as the
6650      *         AccessibleContext of this JTable
6651      */
6652     public AccessibleContext getAccessibleContext() {
6653         if (accessibleContext == null) {
6654             accessibleContext = new AccessibleJTable();
6655         }
6656         return accessibleContext;
6657     }
6658 
6659     //
6660     // *** should also implement AccessibleSelection?
6661     // *** and what's up with keyboard navigation/manipulation?
6662     //
6663     /**
6664      * This class implements accessibility support for the
6665      * <code>JTable</code> class.  It provides an implementation of the
6666      * Java Accessibility API appropriate to table user-interface elements.
6667      * <p>
6668      * <strong>Warning:</strong>
6669      * Serialized objects of this class will not be compatible with
6670      * future Swing releases. The current serialization support is
6671      * appropriate for short term storage or RMI between applications running
6672      * the same version of Swing.  As of 1.4, support for long term storage
6673      * of all JavaBeans&trade;
6674      * has been added to the <code>java.beans</code> package.
6675      * Please see {@link java.beans.XMLEncoder}.
6676      */
6677     @SuppressWarnings("serial") // Same-version serialization only
6678     protected class AccessibleJTable extends AccessibleJComponent
6679     implements AccessibleSelection, ListSelectionListener, TableModelListener,
6680     TableColumnModelListener, CellEditorListener, PropertyChangeListener,
6681     AccessibleExtendedTable {
6682 
6683         int previousFocusedRow;
6684         int previousFocusedCol;
6685 
6686         /**
6687          * AccessibleJTable constructor
6688          *
6689          * @since 1.5
6690          */
6691         protected AccessibleJTable() {
6692             super();
6693             JTable.this.addPropertyChangeListener(this);
6694             JTable.this.getSelectionModel().addListSelectionListener(this);
6695             TableColumnModel tcm = JTable.this.getColumnModel();
6696             tcm.addColumnModelListener(this);
6697             tcm.getSelectionModel().addListSelectionListener(this);
6698             JTable.this.getModel().addTableModelListener(this);
6699             previousFocusedRow = JTable.this.getSelectionModel().
6700                                         getLeadSelectionIndex();
6701             previousFocusedCol = JTable.this.getColumnModel().
6702                                         getSelectionModel().getLeadSelectionIndex();
6703         }
6704 
6705     // Listeners to track model, etc. changes to as to re-place the other
6706     // listeners
6707 
6708         /**
6709          * Track changes to selection model, column model, etc. so as to
6710          * be able to re-place listeners on those in order to pass on
6711          * information to the Accessibility PropertyChange mechanism
6712          */
6713         public void propertyChange(PropertyChangeEvent e) {
6714             String name = e.getPropertyName();
6715             Object oldValue = e.getOldValue();
6716             Object newValue = e.getNewValue();
6717 
6718                 // re-set tableModel listeners
6719             if (name.compareTo("model") == 0) {
6720 
6721                 if (oldValue != null && oldValue instanceof TableModel) {
6722                     ((TableModel) oldValue).removeTableModelListener(this);
6723                 }
6724                 if (newValue != null && newValue instanceof TableModel) {
6725                     ((TableModel) newValue).addTableModelListener(this);
6726                 }
6727 
6728                 // re-set selectionModel listeners
6729             } else if (name.compareTo("selectionModel") == 0) {
6730 
6731                 Object source = e.getSource();
6732                 if (source == JTable.this) {    // row selection model
6733 
6734                     if (oldValue != null &&
6735                         oldValue instanceof ListSelectionModel) {
6736                         ((ListSelectionModel) oldValue).removeListSelectionListener(this);
6737                     }
6738                     if (newValue != null &&
6739                         newValue instanceof ListSelectionModel) {
6740                         ((ListSelectionModel) newValue).addListSelectionListener(this);
6741                     }
6742 
6743                 } else if (source == JTable.this.getColumnModel()) {
6744 
6745                     if (oldValue != null &&
6746                         oldValue instanceof ListSelectionModel) {
6747                         ((ListSelectionModel) oldValue).removeListSelectionListener(this);
6748                     }
6749                     if (newValue != null &&
6750                         newValue instanceof ListSelectionModel) {
6751                         ((ListSelectionModel) newValue).addListSelectionListener(this);
6752                     }
6753 
6754                 } else {
6755                   //        System.out.println("!!! Bug in source of selectionModel propertyChangeEvent");
6756                 }
6757 
6758                 // re-set columnModel listeners
6759                 // and column's selection property listener as well
6760             } else if (name.compareTo("columnModel") == 0) {
6761 
6762                 if (oldValue != null && oldValue instanceof TableColumnModel) {
6763                     TableColumnModel tcm = (TableColumnModel) oldValue;
6764                     tcm.removeColumnModelListener(this);
6765                     tcm.getSelectionModel().removeListSelectionListener(this);
6766                 }
6767                 if (newValue != null && newValue instanceof TableColumnModel) {
6768                     TableColumnModel tcm = (TableColumnModel) newValue;
6769                     tcm.addColumnModelListener(this);
6770                     tcm.getSelectionModel().addListSelectionListener(this);
6771                 }
6772 
6773                 // re-se cellEditor listeners
6774             } else if (name.compareTo("tableCellEditor") == 0) {
6775 
6776                 if (oldValue != null && oldValue instanceof TableCellEditor) {
6777                     ((TableCellEditor) oldValue).removeCellEditorListener(this);
6778                 }
6779                 if (newValue != null && newValue instanceof TableCellEditor) {
6780                     ((TableCellEditor) newValue).addCellEditorListener(this);
6781                 }
6782             }
6783         }
6784 
6785 
6786     // Listeners to echo changes to the AccessiblePropertyChange mechanism
6787 
6788         /**
6789          * Describes a change in the accessible table model.
6790          */
6791         protected class AccessibleJTableModelChange
6792             implements AccessibleTableModelChange {
6793 
6794             protected int type;
6795             protected int firstRow;
6796             protected int lastRow;
6797             protected int firstColumn;
6798             protected int lastColumn;
6799 
6800             protected AccessibleJTableModelChange(int type, int firstRow,
6801                                                   int lastRow, int firstColumn,
6802                                                   int lastColumn) {
6803                 this.type = type;
6804                 this.firstRow = firstRow;
6805                 this.lastRow = lastRow;
6806                 this.firstColumn = firstColumn;
6807                 this.lastColumn = lastColumn;
6808             }
6809 
6810             public int getType() {
6811                 return type;
6812             }
6813 
6814             public int getFirstRow() {
6815                 return firstRow;
6816             }
6817 
6818             public int getLastRow() {
6819                 return lastRow;
6820             }
6821 
6822             public int getFirstColumn() {
6823                 return firstColumn;
6824             }
6825 
6826             public int getLastColumn() {
6827                 return lastColumn;
6828             }
6829         }
6830 
6831         /**
6832          * Track changes to the table contents
6833          *
6834          * @param e a {@code TableModelEvent} describing the event
6835          */
6836         public void tableChanged(TableModelEvent e) {
6837            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6838                               null, null);
6839            if (e != null) {
6840                int firstColumn = e.getColumn();
6841                int lastColumn = e.getColumn();
6842                if (firstColumn == TableModelEvent.ALL_COLUMNS) {
6843                    firstColumn = 0;
6844                    lastColumn = getColumnCount() - 1;
6845                }
6846 
6847                // Fire a property change event indicating the table model
6848                // has changed.
6849                AccessibleJTableModelChange change =
6850                    new AccessibleJTableModelChange(e.getType(),
6851                                                    e.getFirstRow(),
6852                                                    e.getLastRow(),
6853                                                    firstColumn,
6854                                                    lastColumn);
6855                firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6856                                   null, change);
6857             }
6858         }
6859 
6860         /**
6861          * Track changes to the table contents (row insertions)
6862          *
6863          * @param e a {@code TableModelEvent} describing the event
6864          */
6865         public void tableRowsInserted(TableModelEvent e) {
6866            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6867                               null, null);
6868 
6869            // Fire a property change event indicating the table model
6870            // has changed.
6871            int firstColumn = e.getColumn();
6872            int lastColumn = e.getColumn();
6873            if (firstColumn == TableModelEvent.ALL_COLUMNS) {
6874                firstColumn = 0;
6875                lastColumn = getColumnCount() - 1;
6876            }
6877            AccessibleJTableModelChange change =
6878                new AccessibleJTableModelChange(e.getType(),
6879                                                e.getFirstRow(),
6880                                                e.getLastRow(),
6881                                                firstColumn,
6882                                                lastColumn);
6883            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6884                               null, change);
6885         }
6886 
6887         /**
6888          * Track changes to the table contents (row deletions)
6889          *
6890          * @param e a {@code TableModelEvent} describing the event
6891          */
6892         public void tableRowsDeleted(TableModelEvent e) {
6893            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6894                               null, null);
6895 
6896            // Fire a property change event indicating the table model
6897            // has changed.
6898            int firstColumn = e.getColumn();
6899            int lastColumn = e.getColumn();
6900            if (firstColumn == TableModelEvent.ALL_COLUMNS) {
6901                firstColumn = 0;
6902                lastColumn = getColumnCount() - 1;
6903            }
6904            AccessibleJTableModelChange change =
6905                new AccessibleJTableModelChange(e.getType(),
6906                                                e.getFirstRow(),
6907                                                e.getLastRow(),
6908                                                firstColumn,
6909                                                lastColumn);
6910            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6911                               null, change);
6912         }
6913 
6914         /**
6915          * Track changes to the table contents (column insertions)
6916          */
6917         public void columnAdded(TableColumnModelEvent e) {
6918            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6919                               null, null);
6920 
6921            // Fire a property change event indicating the table model
6922            // has changed.
6923            int type = AccessibleTableModelChange.INSERT;
6924            AccessibleJTableModelChange change =
6925                new AccessibleJTableModelChange(type,
6926                                                0,
6927                                                0,
6928                                                e.getFromIndex(),
6929                                                e.getToIndex());
6930            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6931                               null, change);
6932         }
6933 
6934         /**
6935          * Track changes to the table contents (column deletions)
6936          */
6937         public void columnRemoved(TableColumnModelEvent e) {
6938            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6939                               null, null);
6940            // Fire a property change event indicating the table model
6941            // has changed.
6942            int type = AccessibleTableModelChange.DELETE;
6943            AccessibleJTableModelChange change =
6944                new AccessibleJTableModelChange(type,
6945                                                0,
6946                                                0,
6947                                                e.getFromIndex(),
6948                                                e.getToIndex());
6949            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6950                               null, change);
6951         }
6952 
6953         /**
6954          * Track changes of a column repositioning.
6955          *
6956          * @see TableColumnModelListener
6957          */
6958         public void columnMoved(TableColumnModelEvent e) {
6959            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6960                               null, null);
6961 
6962            // Fire property change events indicating the table model
6963            // has changed.
6964            int type = AccessibleTableModelChange.DELETE;
6965            AccessibleJTableModelChange change =
6966                new AccessibleJTableModelChange(type,
6967                                                0,
6968                                                0,
6969                                                e.getFromIndex(),
6970                                                e.getFromIndex());
6971            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6972                               null, change);
6973 
6974            int type2 = AccessibleTableModelChange.INSERT;
6975            AccessibleJTableModelChange change2 =
6976                new AccessibleJTableModelChange(type2,
6977                                                0,
6978                                                0,
6979                                                e.getToIndex(),
6980                                                e.getToIndex());
6981            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6982                               null, change2);
6983         }
6984 
6985         /**
6986          * Track changes of a column moving due to margin changes.
6987          *
6988          * @see TableColumnModelListener
6989          */
6990         public void columnMarginChanged(ChangeEvent e) {
6991            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6992                               null, null);
6993         }
6994 
6995         /**
6996          * Track that the selection model of the TableColumnModel changed.
6997          *
6998          * @see TableColumnModelListener
6999          */
7000         public void columnSelectionChanged(ListSelectionEvent e) {
7001             // we should now re-place our TableColumn listener
7002         }
7003 
7004         /**
7005          * Track changes to a cell's contents.
7006          *
7007          * Invoked when editing is finished. The changes are saved, the
7008          * editor object is discarded, and the cell is rendered once again.
7009          *
7010          * @see CellEditorListener
7011          */
7012         public void editingStopped(ChangeEvent e) {
7013            // it'd be great if we could figure out which cell, and pass that
7014            // somehow as a parameter
7015            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
7016                               null, null);
7017         }
7018 
7019         /**
7020          * Invoked when editing is canceled. The editor object is discarded
7021          * and the cell is rendered once again.
7022          *
7023          * @see CellEditorListener
7024          */
7025         public void editingCanceled(ChangeEvent e) {
7026             // nothing to report, 'cause nothing changed
7027         }
7028 
7029         /**
7030          * Track changes to table cell selections
7031          */
7032         public void valueChanged(ListSelectionEvent e) {
7033             firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
7034                             Boolean.valueOf(false), Boolean.valueOf(true));
7035 
7036             // Using lead selection index to cover both cases: node selected and node
7037             // is focused but not selected (Ctrl+up/down)
7038             int focusedRow = JTable.this.getSelectionModel().getLeadSelectionIndex();
7039             int focusedCol = JTable.this.getColumnModel().getSelectionModel().
7040                                                     getLeadSelectionIndex();
7041 
7042             if (focusedRow != previousFocusedRow ||
7043                 focusedCol != previousFocusedCol) {
7044                 Accessible oldA = getAccessibleAt(previousFocusedRow, previousFocusedCol);
7045                 Accessible newA = getAccessibleAt(focusedRow, focusedCol);
7046                 firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
7047                                     oldA, newA);
7048                 previousFocusedRow = focusedRow;
7049                 previousFocusedCol = focusedCol;
7050             }
7051         }
7052 
7053 
7054 
7055 
7056     // AccessibleContext support
7057 
7058         /**
7059          * Get the AccessibleSelection associated with this object.  In the
7060          * implementation of the Java Accessibility API for this class,
7061          * return this object, which is responsible for implementing the
7062          * AccessibleSelection interface on behalf of itself.
7063          *
7064          * @return this object
7065          */
7066         public AccessibleSelection getAccessibleSelection() {
7067             return this;
7068         }
7069 
7070         /**
7071          * Gets the role of this object.
7072          *
7073          * @return an instance of AccessibleRole describing the role of the
7074          * object
7075          * @see AccessibleRole
7076          */
7077         public AccessibleRole getAccessibleRole() {
7078             return AccessibleRole.TABLE;
7079         }
7080 
7081         /**
7082          * Returns the <code>Accessible</code> child, if one exists,
7083          * contained at the local coordinate <code>Point</code>.
7084          *
7085          * @param p the point defining the top-left corner of the
7086          *    <code>Accessible</code>, given in the coordinate space
7087          *    of the object's parent
7088          * @return the <code>Accessible</code>, if it exists,
7089          *    at the specified location; else <code>null</code>
7090          */
7091         public Accessible getAccessibleAt(Point p) {
7092             int column = columnAtPoint(p);
7093             int row = rowAtPoint(p);
7094 
7095             if ((column != -1) && (row != -1)) {
7096                 TableColumn aColumn = getColumnModel().getColumn(column);
7097                 TableCellRenderer renderer = aColumn.getCellRenderer();
7098                 if (renderer == null) {
7099                     Class<?> columnClass = getColumnClass(column);
7100                     renderer = getDefaultRenderer(columnClass);
7101                 }
7102                 Component component = renderer.getTableCellRendererComponent(
7103                                   JTable.this, null, false, false,
7104                                   row, column);
7105                 return new AccessibleJTableCell(JTable.this, row, column,
7106                       getAccessibleIndexAt(row, column));
7107             }
7108             return null;
7109         }
7110 
7111         /**
7112          * Returns the number of accessible children in the object.  If all
7113          * of the children of this object implement <code>Accessible</code>,
7114          * then this method should return the number of children of this object.
7115          *
7116          * @return the number of accessible children in the object
7117          */
7118         public int getAccessibleChildrenCount() {
7119             return (JTable.this.getColumnCount() * JTable.this.getRowCount());
7120         }
7121 
7122         /**
7123          * Returns the nth <code>Accessible</code> child of the object.
7124          *
7125          * @param i zero-based index of child
7126          * @return the nth Accessible child of the object
7127          */
7128         public Accessible getAccessibleChild(int i) {
7129             if (i < 0 || i >= getAccessibleChildrenCount()) {
7130                 return null;
7131             } else {
7132                 // children increase across, and then down, for tables
7133                 // (arbitrary decision)
7134                 int column = getAccessibleColumnAtIndex(i);
7135                 int row = getAccessibleRowAtIndex(i);
7136 
7137                 TableColumn aColumn = getColumnModel().getColumn(column);
7138                 TableCellRenderer renderer = aColumn.getCellRenderer();
7139                 if (renderer == null) {
7140                     Class<?> columnClass = getColumnClass(column);
7141                     renderer = getDefaultRenderer(columnClass);
7142                 }
7143                 Component component = renderer.getTableCellRendererComponent(
7144                                   JTable.this, null, false, false,
7145                                   row, column);
7146                 return new AccessibleJTableCell(JTable.this, row, column,
7147                       getAccessibleIndexAt(row, column));
7148             }
7149         }
7150 
7151     // AccessibleSelection support
7152 
7153         /**
7154          * Returns the number of <code>Accessible</code> children
7155          * currently selected.
7156          * If no children are selected, the return value will be 0.
7157          *
7158          * @return the number of items currently selected
7159          */
7160         public int getAccessibleSelectionCount() {
7161             int rowsSel = JTable.this.getSelectedRowCount();
7162             int colsSel = JTable.this.getSelectedColumnCount();
7163 
7164             if (JTable.this.cellSelectionEnabled) { // a contiguous block
7165                 return rowsSel * colsSel;
7166 
7167             } else {
7168                 // a column swath and a row swath, with a shared block
7169                 if (JTable.this.getRowSelectionAllowed() &&
7170                     JTable.this.getColumnSelectionAllowed()) {
7171                     return rowsSel * JTable.this.getColumnCount() +
7172                            colsSel * JTable.this.getRowCount() -
7173                            rowsSel * colsSel;
7174 
7175                 // just one or more rows in selection
7176                 } else if (JTable.this.getRowSelectionAllowed()) {
7177                     return rowsSel * JTable.this.getColumnCount();
7178 
7179                 // just one or more rows in selection
7180                 } else if (JTable.this.getColumnSelectionAllowed()) {
7181                     return colsSel * JTable.this.getRowCount();
7182 
7183                 } else {
7184                     return 0;    // JTable doesn't allow selections
7185                 }
7186             }
7187         }
7188 
7189         /**
7190          * Returns an <code>Accessible</code> representing the
7191          * specified selected child in the object.  If there
7192          * isn't a selection, or there are fewer children selected
7193          * than the integer passed in, the return
7194          * value will be <code>null</code>.
7195          * <p>Note that the index represents the i-th selected child, which
7196          * is different from the i-th child.
7197          *
7198          * @param i the zero-based index of selected children
7199          * @return the i-th selected child
7200          * @see #getAccessibleSelectionCount
7201          */
7202         public Accessible getAccessibleSelection(int i) {
7203             if (i < 0 || i > getAccessibleSelectionCount()) {
7204                 return null;
7205             }
7206 
7207             int rowsSel = JTable.this.getSelectedRowCount();
7208             int colsSel = JTable.this.getSelectedColumnCount();
7209             int rowIndicies[] = getSelectedRows();
7210             int colIndicies[] = getSelectedColumns();
7211             int ttlCols = JTable.this.getColumnCount();
7212             int ttlRows = JTable.this.getRowCount();
7213             int r;
7214             int c;
7215 
7216             if (JTable.this.cellSelectionEnabled) { // a contiguous block
7217                 r = rowIndicies[i / colsSel];
7218                 c = colIndicies[i % colsSel];
7219                 return getAccessibleChild((r * ttlCols) + c);
7220             } else {
7221 
7222                 // a column swath and a row swath, with a shared block
7223                 if (JTable.this.getRowSelectionAllowed() &&
7224                     JTable.this.getColumnSelectionAllowed()) {
7225 
7226                     // Situation:
7227                     //   We have a table, like the 6x3 table below,
7228                     //   wherein three colums and one row selected
7229                     //   (selected cells marked with "*", unselected "0"):
7230                     //
7231                     //            0 * 0 * * 0
7232                     //            * * * * * *
7233                     //            0 * 0 * * 0
7234                     //
7235 
7236                     // State machine below walks through the array of
7237                     // selected rows in two states: in a selected row,
7238                     // and not in one; continuing until we are in a row
7239                     // in which the ith selection exists.  Then we return
7240                     // the appropriate cell.  In the state machine, we
7241                     // always do rows above the "current" selected row first,
7242                     // then the cells in the selected row.  If we're done
7243                     // with the state machine before finding the requested
7244                     // selected child, we handle the rows below the last
7245                     // selected row at the end.
7246                     //
7247                     int curIndex = i;
7248                     final int IN_ROW = 0;
7249                     final int NOT_IN_ROW = 1;
7250                     int state = (rowIndicies[0] == 0 ? IN_ROW : NOT_IN_ROW);
7251                     int j = 0;
7252                     int prevRow = -1;
7253                     while (j < rowIndicies.length) {
7254                         switch (state) {
7255 
7256                         case IN_ROW:   // on individual row full of selections
7257                             if (curIndex < ttlCols) { // it's here!
7258                                 c = curIndex % ttlCols;
7259                                 r = rowIndicies[j];
7260                                 return getAccessibleChild((r * ttlCols) + c);
7261                             } else {                               // not here
7262                                 curIndex -= ttlCols;
7263                             }
7264                             // is the next row in table selected or not?
7265                             if (j + 1 == rowIndicies.length ||
7266                                 rowIndicies[j] != rowIndicies[j+1] - 1) {
7267                                 state = NOT_IN_ROW;
7268                                 prevRow = rowIndicies[j];
7269                             }
7270                             j++;  // we didn't return earlier, so go to next row
7271                             break;
7272 
7273                         case NOT_IN_ROW:  // sparse bunch of rows of selections
7274                             if (curIndex <
7275                                 (colsSel * (rowIndicies[j] -
7276                                 (prevRow == -1 ? 0 : (prevRow + 1))))) {
7277 
7278                                 // it's here!
7279                                 c = colIndicies[curIndex % colsSel];
7280                                 r = (j > 0 ? rowIndicies[j-1] + 1 : 0)
7281                                     + curIndex / colsSel;
7282                                 return getAccessibleChild((r * ttlCols) + c);
7283                             } else {                               // not here
7284                                 curIndex -= colsSel * (rowIndicies[j] -
7285                                 (prevRow == -1 ? 0 : (prevRow + 1)));
7286                             }
7287                             state = IN_ROW;
7288                             break;
7289                         }
7290                     }
7291                     // we got here, so we didn't find it yet; find it in
7292                     // the last sparse bunch of rows
7293                     if (curIndex <
7294                         (colsSel * (ttlRows -
7295                         (prevRow == -1 ? 0 : (prevRow + 1))))) { // it's here!
7296                         c = colIndicies[curIndex % colsSel];
7297                         r = rowIndicies[j-1] + curIndex / colsSel + 1;
7298                         return getAccessibleChild((r * ttlCols) + c);
7299                     } else {                               // not here
7300                         // we shouldn't get to this spot in the code!
7301 //                      System.out.println("Bug in AccessibleJTable.getAccessibleSelection()");
7302                     }
7303 
7304                 // one or more rows selected
7305                 } else if (JTable.this.getRowSelectionAllowed()) {
7306                     c = i % ttlCols;
7307                     r = rowIndicies[i / ttlCols];
7308                     return getAccessibleChild((r * ttlCols) + c);
7309 
7310                 // one or more columns selected
7311                 } else if (JTable.this.getColumnSelectionAllowed()) {
7312                     c = colIndicies[i % colsSel];
7313                     r = i / colsSel;
7314                     return getAccessibleChild((r * ttlCols) + c);
7315                 }
7316             }
7317             return null;
7318         }
7319 
7320         /**
7321          * Determines if the current child of this object is selected.
7322          *
7323          * @param i the zero-based index of the child in this
7324          *    <code>Accessible</code> object
7325          * @return true if the current child of this object is selected
7326          * @see AccessibleContext#getAccessibleChild
7327          */
7328         public boolean isAccessibleChildSelected(int i) {
7329             int column = getAccessibleColumnAtIndex(i);
7330             int row = getAccessibleRowAtIndex(i);
7331             return JTable.this.isCellSelected(row, column);
7332         }
7333 
7334         /**
7335          * Adds the specified <code>Accessible</code> child of the
7336          * object to the object's selection.  If the object supports
7337          * multiple selections, the specified child is added to
7338          * any existing selection, otherwise
7339          * it replaces any existing selection in the object.  If the
7340          * specified child is already selected, this method has no effect.
7341          * <p>
7342          * This method only works on <code>JTable</code>s which have
7343          * individual cell selection enabled.
7344          *
7345          * @param i the zero-based index of the child
7346          * @see AccessibleContext#getAccessibleChild
7347          */
7348         public void addAccessibleSelection(int i) {
7349             // TIGER - 4495286
7350             int column = getAccessibleColumnAtIndex(i);
7351             int row = getAccessibleRowAtIndex(i);
7352             JTable.this.changeSelection(row, column, true, false);
7353         }
7354 
7355         /**
7356          * Removes the specified child of the object from the object's
7357          * selection.  If the specified item isn't currently selected, this
7358          * method has no effect.
7359          * <p>
7360          * This method only works on <code>JTables</code> which have
7361          * individual cell selection enabled.
7362          *
7363          * @param i the zero-based index of the child
7364          * @see AccessibleContext#getAccessibleChild
7365          */
7366         public void removeAccessibleSelection(int i) {
7367             if (JTable.this.cellSelectionEnabled) {
7368                 int column = getAccessibleColumnAtIndex(i);
7369                 int row = getAccessibleRowAtIndex(i);
7370                 JTable.this.removeRowSelectionInterval(row, row);
7371                 JTable.this.removeColumnSelectionInterval(column, column);
7372             }
7373         }
7374 
7375         /**
7376          * Clears the selection in the object, so that no children in the
7377          * object are selected.
7378          */
7379         public void clearAccessibleSelection() {
7380             JTable.this.clearSelection();
7381         }
7382 
7383         /**
7384          * Causes every child of the object to be selected, but only
7385          * if the <code>JTable</code> supports multiple selections,
7386          * and if individual cell selection is enabled.
7387          */
7388         public void selectAllAccessibleSelection() {
7389             if (JTable.this.cellSelectionEnabled) {
7390                 JTable.this.selectAll();
7391             }
7392         }
7393 
7394         // begin AccessibleExtendedTable implementation -------------
7395 
7396         /**
7397          * Returns the row number of an index in the table.
7398          *
7399          * @param index the zero-based index in the table
7400          * @return the zero-based row of the table if one exists;
7401          * otherwise -1.
7402          * @since 1.4
7403          */
7404         public int getAccessibleRow(int index) {
7405             return getAccessibleRowAtIndex(index);
7406         }
7407 
7408         /**
7409          * Returns the column number of an index in the table.
7410          *
7411          * @param index the zero-based index in the table
7412          * @return the zero-based column of the table if one exists;
7413          * otherwise -1.
7414          * @since 1.4
7415          */
7416         public int getAccessibleColumn(int index) {
7417             return getAccessibleColumnAtIndex(index);
7418         }
7419 
7420         /**
7421          * Returns the index at a row and column in the table.
7422          *
7423          * @param r zero-based row of the table
7424          * @param c zero-based column of the table
7425          * @return the zero-based index in the table if one exists;
7426          * otherwise -1.
7427          * @since 1.4
7428          */
7429         public int getAccessibleIndex(int r, int c) {
7430             return getAccessibleIndexAt(r, c);
7431         }
7432 
7433         // end of AccessibleExtendedTable implementation ------------
7434 
7435         // start of AccessibleTable implementation ------------------
7436 
7437         private Accessible caption;
7438         private Accessible summary;
7439         private Accessible [] rowDescription;
7440         private Accessible [] columnDescription;
7441 
7442         /**
7443          * Gets the <code>AccessibleTable</code> associated with this
7444          * object.  In the implementation of the Java Accessibility
7445          * API for this class, return this object, which is responsible
7446          * for implementing the <code>AccessibleTables</code> interface
7447          * on behalf of itself.
7448          *
7449          * @return this object
7450          * @since 1.3
7451          */
7452         public AccessibleTable getAccessibleTable() {
7453             return this;
7454         }
7455 
7456         /**
7457          * Returns the caption for the table.
7458          *
7459          * @return the caption for the table
7460          * @since 1.3
7461          */
7462         public Accessible getAccessibleCaption() {
7463             return this.caption;
7464         }
7465 
7466         /**
7467          * Sets the caption for the table.
7468          *
7469          * @param a the caption for the table
7470          * @since 1.3
7471          */
7472         public void setAccessibleCaption(Accessible a) {
7473             Accessible oldCaption = caption;
7474             this.caption = a;
7475             firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_CAPTION_CHANGED,
7476                                oldCaption, this.caption);
7477         }
7478 
7479         /**
7480          * Returns the summary description of the table.
7481          *
7482          * @return the summary description of the table
7483          * @since 1.3
7484          */
7485         public Accessible getAccessibleSummary() {
7486             return this.summary;
7487         }
7488 
7489         /**
7490          * Sets the summary description of the table.
7491          *
7492          * @param a the summary description of the table
7493          * @since 1.3
7494          */
7495         public void setAccessibleSummary(Accessible a) {
7496             Accessible oldSummary = summary;
7497             this.summary = a;
7498             firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_SUMMARY_CHANGED,
7499                                oldSummary, this.summary);
7500         }
7501 
7502         /*
7503          * Returns the total number of rows in this table.
7504          *
7505          * @return the total number of rows in this table
7506          */
7507         public int getAccessibleRowCount() {
7508             return JTable.this.getRowCount();
7509         }
7510 
7511         /*
7512          * Returns the total number of columns in the table.
7513          *
7514          * @return the total number of columns in the table
7515          */
7516         public int getAccessibleColumnCount() {
7517             return JTable.this.getColumnCount();
7518         }
7519 
7520         /*
7521          * Returns the <code>Accessible</code> at a specified row
7522          * and column in the table.
7523          *
7524          * @param r zero-based row of the table
7525          * @param c zero-based column of the table
7526          * @return the <code>Accessible</code> at the specified row and column
7527          * in the table
7528          */
7529         public Accessible getAccessibleAt(int r, int c) {
7530             return getAccessibleChild((r * getAccessibleColumnCount()) + c);
7531         }
7532 
7533         /**
7534          * Returns the number of rows occupied by the <code>Accessible</code>
7535          * at a specified row and column in the table.
7536          *
7537          * @return the number of rows occupied by the <code>Accessible</code>
7538          *     at a specified row and column in the table
7539          * @since 1.3
7540          */
7541         public int getAccessibleRowExtentAt(int r, int c) {
7542             return 1;
7543         }
7544 
7545         /**
7546          * Returns the number of columns occupied by the
7547          * <code>Accessible</code> at a given (row, column).
7548          *
7549          * @return the number of columns occupied by the <code>Accessible</code>
7550          *     at a specified row and column in the table
7551          * @since 1.3
7552          */
7553         public int getAccessibleColumnExtentAt(int r, int c) {
7554             return 1;
7555         }
7556 
7557         /**
7558          * Returns the row headers as an <code>AccessibleTable</code>.
7559          *
7560          * @return an <code>AccessibleTable</code> representing the row
7561          * headers
7562          * @since 1.3
7563          */
7564         public AccessibleTable getAccessibleRowHeader() {
7565             // row headers are not supported
7566             return null;
7567         }
7568 
7569         /**
7570          * Sets the row headers as an <code>AccessibleTable</code>.
7571          *
7572          * @param a an <code>AccessibleTable</code> representing the row
7573          *  headers
7574          * @since 1.3
7575          */
7576         public void setAccessibleRowHeader(AccessibleTable a) {
7577             // row headers are not supported
7578         }
7579 
7580         /**
7581          * Returns the column headers as an <code>AccessibleTable</code>.
7582          *
7583          *  @return an <code>AccessibleTable</code> representing the column
7584          *          headers, or <code>null</code> if the table header is
7585          *          <code>null</code>
7586          * @since 1.3
7587          */
7588         public AccessibleTable getAccessibleColumnHeader() {
7589             JTableHeader header = JTable.this.getTableHeader();
7590             return header == null ? null : new AccessibleTableHeader(header);
7591         }
7592 
7593         /*
7594          * Private class representing a table column header
7595          */
7596         private class AccessibleTableHeader implements AccessibleTable {
7597             private JTableHeader header;
7598             private TableColumnModel headerModel;
7599 
7600             AccessibleTableHeader(JTableHeader header) {
7601                 this.header = header;
7602                 this.headerModel = header.getColumnModel();
7603             }
7604 
7605             /**
7606              * Returns the caption for the table.
7607              *
7608              * @return the caption for the table
7609              */
7610             public Accessible getAccessibleCaption() { return null; }
7611 
7612 
7613             /**
7614              * Sets the caption for the table.
7615              *
7616              * @param a the caption for the table
7617              */
7618             public void setAccessibleCaption(Accessible a) {}
7619 
7620             /**
7621              * Returns the summary description of the table.
7622              *
7623              * @return the summary description of the table
7624              */
7625             public Accessible getAccessibleSummary() { return null; }
7626 
7627             /**
7628              * Sets the summary description of the table
7629              *
7630              * @param a the summary description of the table
7631              */
7632             public void setAccessibleSummary(Accessible a) {}
7633 
7634             /**
7635              * Returns the number of rows in the table.
7636              *
7637              * @return the number of rows in the table
7638              */
7639             public int getAccessibleRowCount() { return 1; }
7640 
7641             /**
7642              * Returns the number of columns in the table.
7643              *
7644              * @return the number of columns in the table
7645              */
7646             public int getAccessibleColumnCount() {
7647                 return headerModel.getColumnCount();
7648             }
7649 
7650             /**
7651              * Returns the Accessible at a specified row and column
7652              * in the table.
7653              *
7654              * @param row zero-based row of the table
7655              * @param column zero-based column of the table
7656              * @return the Accessible at the specified row and column
7657              */
7658             public Accessible getAccessibleAt(int row, int column) {
7659 
7660 
7661                 // TIGER - 4715503
7662                 TableColumn aColumn = headerModel.getColumn(column);
7663                 TableCellRenderer renderer = aColumn.getHeaderRenderer();
7664                 if (renderer == null) {
7665                     renderer = header.getDefaultRenderer();
7666                 }
7667                 Component component = renderer.getTableCellRendererComponent(
7668                                   header.getTable(),
7669                                   aColumn.getHeaderValue(), false, false,
7670                                   -1, column);
7671 
7672                 return new AccessibleJTableHeaderCell(row, column,
7673                                                       JTable.this.getTableHeader(),
7674                                                       component);
7675             }
7676 
7677             /**
7678              * Returns the number of rows occupied by the Accessible at
7679              * a specified row and column in the table.
7680              *
7681              * @return the number of rows occupied by the Accessible at a
7682              * given specified (row, column)
7683              */
7684             public int getAccessibleRowExtentAt(int r, int c) { return 1; }
7685 
7686             /**
7687              * Returns the number of columns occupied by the Accessible at
7688              * a specified row and column in the table.
7689              *
7690              * @return the number of columns occupied by the Accessible at a
7691              * given specified row and column
7692              */
7693             public int getAccessibleColumnExtentAt(int r, int c) { return 1; }
7694 
7695             /**
7696              * Returns the row headers as an AccessibleTable.
7697              *
7698              * @return an AccessibleTable representing the row
7699              * headers
7700              */
7701             public AccessibleTable getAccessibleRowHeader() { return null; }
7702 
7703             /**
7704              * Sets the row headers.
7705              *
7706              * @param table an AccessibleTable representing the
7707              * row headers
7708              */
7709             public void setAccessibleRowHeader(AccessibleTable table) {}
7710 
7711             /**
7712              * Returns the column headers as an AccessibleTable.
7713              *
7714              * @return an AccessibleTable representing the column
7715              * headers
7716              */
7717             public AccessibleTable getAccessibleColumnHeader() { return null; }
7718 
7719             /**
7720              * Sets the column headers.
7721              *
7722              * @param table an AccessibleTable representing the
7723              * column headers
7724              * @since 1.3
7725              */
7726             public void setAccessibleColumnHeader(AccessibleTable table) {}
7727 
7728             /**
7729              * Returns the description of the specified row in the table.
7730              *
7731              * @param r zero-based row of the table
7732              * @return the description of the row
7733              * @since 1.3
7734              */
7735             public Accessible getAccessibleRowDescription(int r) { return null; }
7736 
7737             /**
7738              * Sets the description text of the specified row of the table.
7739              *
7740              * @param r zero-based row of the table
7741              * @param a the description of the row
7742              * @since 1.3
7743              */
7744             public void setAccessibleRowDescription(int r, Accessible a) {}
7745 
7746             /**
7747              * Returns the description text of the specified column in the table.
7748              *
7749              * @param c zero-based column of the table
7750              * @return the text description of the column
7751              * @since 1.3
7752              */
7753             public Accessible getAccessibleColumnDescription(int c) { return null; }
7754 
7755             /**
7756              * Sets the description text of the specified column in the table.
7757              *
7758              * @param c zero-based column of the table
7759              * @param a the text description of the column
7760              * @since 1.3
7761              */
7762             public void setAccessibleColumnDescription(int c, Accessible a) {}
7763 
7764             /**
7765              * Returns a boolean value indicating whether the accessible at
7766              * a specified row and column is selected.
7767              *
7768              * @param r zero-based row of the table
7769              * @param c zero-based column of the table
7770              * @return the boolean value true if the accessible at the
7771              * row and column is selected. Otherwise, the boolean value
7772              * false
7773              * @since 1.3
7774              */
7775             public boolean isAccessibleSelected(int r, int c) { return false; }
7776 
7777             /**
7778              * Returns a boolean value indicating whether the specified row
7779              * is selected.
7780              *
7781              * @param r zero-based row of the table
7782              * @return the boolean value true if the specified row is selected.
7783              * Otherwise, false.
7784              * @since 1.3
7785              */
7786             public boolean isAccessibleRowSelected(int r) { return false; }
7787 
7788             /**
7789              * Returns a boolean value indicating whether the specified column
7790              * is selected.
7791              *
7792              * @param c zero-based column of the table
7793              * @return the boolean value true if the specified column is selected.
7794              * Otherwise, false.
7795              * @since 1.3
7796              */
7797             public boolean isAccessibleColumnSelected(int c) { return false; }
7798 
7799             /**
7800              * Returns the selected rows in a table.
7801              *
7802              * @return an array of selected rows where each element is a
7803              * zero-based row of the table
7804              * @since 1.3
7805              */
7806             public int [] getSelectedAccessibleRows() { return new int[0]; }
7807 
7808             /**
7809              * Returns the selected columns in a table.
7810              *
7811              * @return an array of selected columns where each element is a
7812              * zero-based column of the table
7813              * @since 1.3
7814              */
7815             public int [] getSelectedAccessibleColumns() { return new int[0]; }
7816         }
7817 
7818 
7819         /**
7820          * Sets the column headers as an <code>AccessibleTable</code>.
7821          *
7822          * @param a an <code>AccessibleTable</code> representing the
7823          * column headers
7824          * @since 1.3
7825          */
7826         public void setAccessibleColumnHeader(AccessibleTable a) {
7827             // XXX not implemented
7828         }
7829 
7830         /**
7831          * Returns the description of the specified row in the table.
7832          *
7833          * @param r zero-based row of the table
7834          * @return the description of the row
7835          * @since 1.3
7836          */
7837         public Accessible getAccessibleRowDescription(int r) {
7838             if (r < 0 || r >= getAccessibleRowCount()) {
7839                 throw new IllegalArgumentException(Integer.toString(r));
7840             }
7841             if (rowDescription == null) {
7842                 return null;
7843             } else {
7844                 return rowDescription[r];
7845             }
7846         }
7847 
7848         /**
7849          * Sets the description text of the specified row of the table.
7850          *
7851          * @param r zero-based row of the table
7852          * @param a the description of the row
7853          * @since 1.3
7854          */
7855         public void setAccessibleRowDescription(int r, Accessible a) {
7856             if (r < 0 || r >= getAccessibleRowCount()) {
7857                 throw new IllegalArgumentException(Integer.toString(r));
7858             }
7859             if (rowDescription == null) {
7860                 int numRows = getAccessibleRowCount();
7861                 rowDescription = new Accessible[numRows];
7862             }
7863             rowDescription[r] = a;
7864         }
7865 
7866         /**
7867          * Returns the description of the specified column in the table.
7868          *
7869          * @param c zero-based column of the table
7870          * @return the description of the column
7871          * @since 1.3
7872          */
7873         public Accessible getAccessibleColumnDescription(int c) {
7874             if (c < 0 || c >= getAccessibleColumnCount()) {
7875                 throw new IllegalArgumentException(Integer.toString(c));
7876             }
7877             if (columnDescription == null) {
7878                 return null;
7879             } else {
7880                 return columnDescription[c];
7881             }
7882         }
7883 
7884         /**
7885          * Sets the description text of the specified column of the table.
7886          *
7887          * @param c zero-based column of the table
7888          * @param a the description of the column
7889          * @since 1.3
7890          */
7891         public void setAccessibleColumnDescription(int c, Accessible a) {
7892             if (c < 0 || c >= getAccessibleColumnCount()) {
7893                 throw new IllegalArgumentException(Integer.toString(c));
7894             }
7895             if (columnDescription == null) {
7896                 int numColumns = getAccessibleColumnCount();
7897                 columnDescription = new Accessible[numColumns];
7898             }
7899             columnDescription[c] = a;
7900         }
7901 
7902         /**
7903          * Returns a boolean value indicating whether the accessible at a
7904          * given (row, column) is selected.
7905          *
7906          * @param r zero-based row of the table
7907          * @param c zero-based column of the table
7908          * @return the boolean value true if the accessible at (row, column)
7909          *     is selected; otherwise, the boolean value false
7910          * @since 1.3
7911          */
7912         public boolean isAccessibleSelected(int r, int c) {
7913             return JTable.this.isCellSelected(r, c);
7914         }
7915 
7916         /**
7917          * Returns a boolean value indicating whether the specified row
7918          * is selected.
7919          *
7920          * @param r zero-based row of the table
7921          * @return the boolean value true if the specified row is selected;
7922          *     otherwise, false
7923          * @since 1.3
7924          */
7925         public boolean isAccessibleRowSelected(int r) {
7926             return JTable.this.isRowSelected(r);
7927         }
7928 
7929         /**
7930          * Returns a boolean value indicating whether the specified column
7931          * is selected.
7932          *
7933          * @param c zero-based column of the table
7934          * @return the boolean value true if the specified column is selected;
7935          *     otherwise, false
7936          * @since 1.3
7937          */
7938         public boolean isAccessibleColumnSelected(int c) {
7939             return JTable.this.isColumnSelected(c);
7940         }
7941 
7942         /**
7943          * Returns the selected rows in a table.
7944          *
7945          * @return an array of selected rows where each element is a
7946          *     zero-based row of the table
7947          * @since 1.3
7948          */
7949         public int [] getSelectedAccessibleRows() {
7950             return JTable.this.getSelectedRows();
7951         }
7952 
7953         /**
7954          * Returns the selected columns in a table.
7955          *
7956          * @return an array of selected columns where each element is a
7957          *     zero-based column of the table
7958          * @since 1.3
7959          */
7960         public int [] getSelectedAccessibleColumns() {
7961             return JTable.this.getSelectedColumns();
7962         }
7963 
7964         /**
7965          * Returns the row at a given index into the table.
7966          *
7967          * @param i zero-based index into the table
7968          * @return the row at a given index
7969          * @since 1.3
7970          */
7971         public int getAccessibleRowAtIndex(int i) {
7972             int columnCount = getAccessibleColumnCount();
7973             if (columnCount == 0) {
7974                 return -1;
7975             } else {
7976                 return (i / columnCount);
7977             }
7978         }
7979 
7980         /**
7981          * Returns the column at a given index into the table.
7982          *
7983          * @param i zero-based index into the table
7984          * @return the column at a given index
7985          * @since 1.3
7986          */
7987         public int getAccessibleColumnAtIndex(int i) {
7988             int columnCount = getAccessibleColumnCount();
7989             if (columnCount == 0) {
7990                 return -1;
7991             } else {
7992                 return (i % columnCount);
7993             }
7994         }
7995 
7996         /**
7997          * Returns the index at a given (row, column) in the table.
7998          *
7999          * @param r zero-based row of the table
8000          * @param c zero-based column of the table
8001          * @return the index into the table
8002          * @since 1.3
8003          */
8004         public int getAccessibleIndexAt(int r, int c) {
8005             return ((r * getAccessibleColumnCount()) + c);
8006         }
8007 
8008         // end of AccessibleTable implementation --------------------
8009 
8010         /**
8011          * The class provides an implementation of the Java Accessibility
8012          * API appropriate to table cells.
8013          */
8014         protected class AccessibleJTableCell extends AccessibleContext
8015             implements Accessible, AccessibleComponent {
8016 
8017             private JTable parent;
8018             private int row;
8019             private int column;
8020             private int index;
8021 
8022             /**
8023              *  Constructs an <code>AccessibleJTableHeaderEntry</code>.
8024              *
8025              * @param t a {@code JTable}
8026              * @param r an {@code int} specifying a row
8027              * @param c an {@code int} specifying a column
8028              * @param i an {@code int} specifying the index to this cell
8029              * @since 1.4
8030              */
8031             public AccessibleJTableCell(JTable t, int r, int c, int i) {
8032                 parent = t;
8033                 row = r;
8034                 column = c;
8035                 index = i;
8036                 this.setAccessibleParent(parent);
8037             }
8038 
8039             /**
8040              * Gets the <code>AccessibleContext</code> associated with this
8041              * component. In the implementation of the Java Accessibility
8042              * API for this class, return this object, which is its own
8043              * <code>AccessibleContext</code>.
8044              *
8045              * @return this object
8046              */
8047             public AccessibleContext getAccessibleContext() {
8048                 return this;
8049             }
8050 
8051             /**
8052              * Gets the AccessibleContext for the table cell renderer.
8053              *
8054              * @return the <code>AccessibleContext</code> for the table
8055              * cell renderer if one exists;
8056              * otherwise, returns <code>null</code>.
8057              * @since 1.6
8058              */
8059             protected AccessibleContext getCurrentAccessibleContext() {
8060                 TableColumn aColumn = getColumnModel().getColumn(column);
8061                 TableCellRenderer renderer = aColumn.getCellRenderer();
8062                 if (renderer == null) {
8063                     Class<?> columnClass = getColumnClass(column);
8064                     renderer = getDefaultRenderer(columnClass);
8065                 }
8066                 Component component = renderer.getTableCellRendererComponent(
8067                                   JTable.this, getValueAt(row, column),
8068                                   false, false, row, column);
8069                 if (component instanceof Accessible) {
8070                     return component.getAccessibleContext();
8071                 } else {
8072                     return null;
8073                 }
8074             }
8075 
8076             /**
8077              * Gets the table cell renderer component.
8078              *
8079              * @return the table cell renderer component if one exists;
8080              * otherwise, returns <code>null</code>.
8081              * @since 1.6
8082              */
8083             protected Component getCurrentComponent() {
8084                 TableColumn aColumn = getColumnModel().getColumn(column);
8085                 TableCellRenderer renderer = aColumn.getCellRenderer();
8086                 if (renderer == null) {
8087                     Class<?> columnClass = getColumnClass(column);
8088                     renderer = getDefaultRenderer(columnClass);
8089                 }
8090                 return renderer.getTableCellRendererComponent(
8091                                   JTable.this, null, false, false,
8092                                   row, column);
8093             }
8094 
8095         // AccessibleContext methods
8096 
8097             /**
8098              * Gets the accessible name of this object.
8099              *
8100              * @return the localized name of the object; <code>null</code>
8101              *     if this object does not have a name
8102              */
8103             public String getAccessibleName() {
8104                 AccessibleContext ac = getCurrentAccessibleContext();
8105                 if (ac != null) {
8106                     String name = ac.getAccessibleName();
8107                     if ((name != null) && (name != "")) {
8108                         // return the cell renderer's AccessibleName
8109                         return name;
8110                     }
8111                 }
8112                 if ((accessibleName != null) && (accessibleName != "")) {
8113                     return accessibleName;
8114                 } else {
8115                     // fall back to the client property
8116                     return (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
8117                 }
8118             }
8119 
8120             /**
8121              * Sets the localized accessible name of this object.
8122              *
8123              * @param s the new localized name of the object
8124              */
8125             public void setAccessibleName(String s) {
8126                 AccessibleContext ac = getCurrentAccessibleContext();
8127                 if (ac != null) {
8128                     ac.setAccessibleName(s);
8129                 } else {
8130                     super.setAccessibleName(s);
8131                 }
8132             }
8133 
8134             //
8135             // *** should check toolTip text for desc. (needs MouseEvent)
8136             //
8137             /**
8138              * Gets the accessible description of this object.
8139              *
8140              * @return the localized description of the object;
8141              *     <code>null</code> if this object does not have
8142              *     a description
8143              */
8144             public String getAccessibleDescription() {
8145                 AccessibleContext ac = getCurrentAccessibleContext();
8146                 if (ac != null) {
8147                     return ac.getAccessibleDescription();
8148                 } else {
8149                     return super.getAccessibleDescription();
8150                 }
8151             }
8152 
8153             /**
8154              * Sets the accessible description of this object.
8155              *
8156              * @param s the new localized description of the object
8157              */
8158             public void setAccessibleDescription(String s) {
8159                 AccessibleContext ac = getCurrentAccessibleContext();
8160                 if (ac != null) {
8161                     ac.setAccessibleDescription(s);
8162                 } else {
8163                     super.setAccessibleDescription(s);
8164                 }
8165             }
8166 
8167             /**
8168              * Gets the role of this object.
8169              *
8170              * @return an instance of <code>AccessibleRole</code>
8171              *      describing the role of the object
8172              * @see AccessibleRole
8173              */
8174             public AccessibleRole getAccessibleRole() {
8175                 AccessibleContext ac = getCurrentAccessibleContext();
8176                 if (ac != null) {
8177                     return ac.getAccessibleRole();
8178                 } else {
8179                     return AccessibleRole.UNKNOWN;
8180                 }
8181             }
8182 
8183             /**
8184              * Gets the state set of this object.
8185              *
8186              * @return an instance of <code>AccessibleStateSet</code>
8187              *     containing the current state set of the object
8188              * @see AccessibleState
8189              */
8190             public AccessibleStateSet getAccessibleStateSet() {
8191                 AccessibleContext ac = getCurrentAccessibleContext();
8192                 AccessibleStateSet as = null;
8193 
8194                 if (ac != null) {
8195                     as = ac.getAccessibleStateSet();
8196                 }
8197                 if (as == null) {
8198                     as = new AccessibleStateSet();
8199                 }
8200                 Rectangle rjt = JTable.this.getVisibleRect();
8201                 Rectangle rcell = JTable.this.getCellRect(row, column, false);
8202                 if (rjt.intersects(rcell)) {
8203                     as.add(AccessibleState.SHOWING);
8204                 } else {
8205                     if (as.contains(AccessibleState.SHOWING)) {
8206                          as.remove(AccessibleState.SHOWING);
8207                     }
8208                 }
8209                 if (parent.isCellSelected(row, column)) {
8210                     as.add(AccessibleState.SELECTED);
8211                 } else if (as.contains(AccessibleState.SELECTED)) {
8212                     as.remove(AccessibleState.SELECTED);
8213                 }
8214                 if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
8215                     as.add(AccessibleState.ACTIVE);
8216                 }
8217                 as.add(AccessibleState.TRANSIENT);
8218                 return as;
8219             }
8220 
8221             /**
8222              * Gets the <code>Accessible</code> parent of this object.
8223              *
8224              * @return the Accessible parent of this object;
8225              *     <code>null</code> if this object does not
8226              *     have an <code>Accessible</code> parent
8227              */
8228             public Accessible getAccessibleParent() {
8229                 return parent;
8230             }
8231 
8232             /**
8233              * Gets the index of this object in its accessible parent.
8234              *
8235              * @return the index of this object in its parent; -1 if this
8236              *     object does not have an accessible parent
8237              * @see #getAccessibleParent
8238              */
8239             public int getAccessibleIndexInParent() {
8240                 return index;
8241             }
8242 
8243             /**
8244              * Returns the number of accessible children in the object.
8245              *
8246              * @return the number of accessible children in the object
8247              */
8248             public int getAccessibleChildrenCount() {
8249                 AccessibleContext ac = getCurrentAccessibleContext();
8250                 if (ac != null) {
8251                     return ac.getAccessibleChildrenCount();
8252                 } else {
8253                     return 0;
8254                 }
8255             }
8256 
8257             /**
8258              * Returns the specified <code>Accessible</code> child of the
8259              * object.
8260              *
8261              * @param i zero-based index of child
8262              * @return the <code>Accessible</code> child of the object
8263              */
8264             public Accessible getAccessibleChild(int i) {
8265                 AccessibleContext ac = getCurrentAccessibleContext();
8266                 if (ac != null) {
8267                     Accessible accessibleChild = ac.getAccessibleChild(i);
8268                     ac.setAccessibleParent(this);
8269                     return accessibleChild;
8270                 } else {
8271                     return null;
8272                 }
8273             }
8274 
8275             /**
8276              * Gets the locale of the component. If the component
8277              * does not have a locale, then the locale of its parent
8278              * is returned.
8279              *
8280              * @return this component's locale; if this component does
8281              *    not have a locale, the locale of its parent is returned
8282              * @exception IllegalComponentStateException if the
8283              *    <code>Component</code> does not have its own locale
8284              *    and has not yet been added to a containment hierarchy
8285              *    such that the locale can be determined from the
8286              *    containing parent
8287              * @see #setLocale
8288              */
8289             public Locale getLocale() {
8290                 AccessibleContext ac = getCurrentAccessibleContext();
8291                 if (ac != null) {
8292                     return ac.getLocale();
8293                 } else {
8294                     return null;
8295                 }
8296             }
8297 
8298             /**
8299              * Adds a <code>PropertyChangeListener</code> to the listener list.
8300              * The listener is registered for all properties.
8301              *
8302              * @param l  the <code>PropertyChangeListener</code>
8303              *     to be added
8304              */
8305             public void addPropertyChangeListener(PropertyChangeListener l) {
8306                 AccessibleContext ac = getCurrentAccessibleContext();
8307                 if (ac != null) {
8308                     ac.addPropertyChangeListener(l);
8309                 } else {
8310                     super.addPropertyChangeListener(l);
8311                 }
8312             }
8313 
8314             /**
8315              * Removes a <code>PropertyChangeListener</code> from the
8316              * listener list. This removes a <code>PropertyChangeListener</code>
8317              * that was registered for all properties.
8318              *
8319              * @param l  the <code>PropertyChangeListener</code>
8320              *    to be removed
8321              */
8322             public void removePropertyChangeListener(PropertyChangeListener l) {
8323                 AccessibleContext ac = getCurrentAccessibleContext();
8324                 if (ac != null) {
8325                     ac.removePropertyChangeListener(l);
8326                 } else {
8327                     super.removePropertyChangeListener(l);
8328                 }
8329             }
8330 
8331             /**
8332              * Gets the <code>AccessibleAction</code> associated with this
8333              * object if one exists.  Otherwise returns <code>null</code>.
8334              *
8335              * @return the <code>AccessibleAction</code>, or <code>null</code>
8336              */
8337             public AccessibleAction getAccessibleAction() {
8338                 return getCurrentAccessibleContext().getAccessibleAction();
8339             }
8340 
8341             /**
8342              * Gets the <code>AccessibleComponent</code> associated with
8343              * this object if one exists.  Otherwise returns <code>null</code>.
8344              *
8345              * @return the <code>AccessibleComponent</code>, or
8346              *    <code>null</code>
8347              */
8348             public AccessibleComponent getAccessibleComponent() {
8349                 return this; // to override getBounds()
8350             }
8351 
8352             /**
8353              * Gets the <code>AccessibleSelection</code> associated with
8354              * this object if one exists.  Otherwise returns <code>null</code>.
8355              *
8356              * @return the <code>AccessibleSelection</code>, or
8357              *    <code>null</code>
8358              */
8359             public AccessibleSelection getAccessibleSelection() {
8360                 return getCurrentAccessibleContext().getAccessibleSelection();
8361             }
8362 
8363             /**
8364              * Gets the <code>AccessibleText</code> associated with this
8365              * object if one exists.  Otherwise returns <code>null</code>.
8366              *
8367              * @return the <code>AccessibleText</code>, or <code>null</code>
8368              */
8369             public AccessibleText getAccessibleText() {
8370                 return getCurrentAccessibleContext().getAccessibleText();
8371             }
8372 
8373             /**
8374              * Gets the <code>AccessibleValue</code> associated with
8375              * this object if one exists.  Otherwise returns <code>null</code>.
8376              *
8377              * @return the <code>AccessibleValue</code>, or <code>null</code>
8378              */
8379             public AccessibleValue getAccessibleValue() {
8380                 return getCurrentAccessibleContext().getAccessibleValue();
8381             }
8382 
8383 
8384         // AccessibleComponent methods
8385 
8386             /**
8387              * Gets the background color of this object.
8388              *
8389              * @return the background color, if supported, of the object;
8390              *     otherwise, <code>null</code>
8391              */
8392             public Color getBackground() {
8393                 AccessibleContext ac = getCurrentAccessibleContext();
8394                 if (ac instanceof AccessibleComponent) {
8395                     return ((AccessibleComponent) ac).getBackground();
8396                 } else {
8397                     Component c = getCurrentComponent();
8398                     if (c != null) {
8399                         return c.getBackground();
8400                     } else {
8401                         return null;
8402                     }
8403                 }
8404             }
8405 
8406             /**
8407              * Sets the background color of this object.
8408              *
8409              * @param c the new <code>Color</code> for the background
8410              */
8411             public void setBackground(Color c) {
8412                 AccessibleContext ac = getCurrentAccessibleContext();
8413                 if (ac instanceof AccessibleComponent) {
8414                     ((AccessibleComponent) ac).setBackground(c);
8415                 } else {
8416                     Component cp = getCurrentComponent();
8417                     if (cp != null) {
8418                         cp.setBackground(c);
8419                     }
8420                 }
8421             }
8422 
8423             /**
8424              * Gets the foreground color of this object.
8425              *
8426              * @return the foreground color, if supported, of the object;
8427              *     otherwise, <code>null</code>
8428              */
8429             public Color getForeground() {
8430                 AccessibleContext ac = getCurrentAccessibleContext();
8431                 if (ac instanceof AccessibleComponent) {
8432                     return ((AccessibleComponent) ac).getForeground();
8433                 } else {
8434                     Component c = getCurrentComponent();
8435                     if (c != null) {
8436                         return c.getForeground();
8437                     } else {
8438                         return null;
8439                     }
8440                 }
8441             }
8442 
8443             /**
8444              * Sets the foreground color of this object.
8445              *
8446              * @param c the new <code>Color</code> for the foreground
8447              */
8448             public void setForeground(Color c) {
8449                 AccessibleContext ac = getCurrentAccessibleContext();
8450                 if (ac instanceof AccessibleComponent) {
8451                     ((AccessibleComponent) ac).setForeground(c);
8452                 } else {
8453                     Component cp = getCurrentComponent();
8454                     if (cp != null) {
8455                         cp.setForeground(c);
8456                     }
8457                 }
8458             }
8459 
8460             /**
8461              * Gets the <code>Cursor</code> of this object.
8462              *
8463              * @return the <code>Cursor</code>, if supported,
8464              *    of the object; otherwise, <code>null</code>
8465              */
8466             public Cursor getCursor() {
8467                 AccessibleContext ac = getCurrentAccessibleContext();
8468                 if (ac instanceof AccessibleComponent) {
8469                     return ((AccessibleComponent) ac).getCursor();
8470                 } else {
8471                     Component c = getCurrentComponent();
8472                     if (c != null) {
8473                         return c.getCursor();
8474                     } else {
8475                         Accessible ap = getAccessibleParent();
8476                         if (ap instanceof AccessibleComponent) {
8477                             return ((AccessibleComponent) ap).getCursor();
8478                         } else {
8479                             return null;
8480                         }
8481                     }
8482                 }
8483             }
8484 
8485             /**
8486              * Sets the <code>Cursor</code> of this object.
8487              *
8488              * @param c the new <code>Cursor</code> for the object
8489              */
8490             public void setCursor(Cursor c) {
8491                 AccessibleContext ac = getCurrentAccessibleContext();
8492                 if (ac instanceof AccessibleComponent) {
8493                     ((AccessibleComponent) ac).setCursor(c);
8494                 } else {
8495                     Component cp = getCurrentComponent();
8496                     if (cp != null) {
8497                         cp.setCursor(c);
8498                     }
8499                 }
8500             }
8501 
8502             /**
8503              * Gets the <code>Font</code> of this object.
8504              *
8505              * @return the <code>Font</code>,if supported,
8506              *   for the object; otherwise, <code>null</code>
8507              */
8508             public Font getFont() {
8509                 AccessibleContext ac = getCurrentAccessibleContext();
8510                 if (ac instanceof AccessibleComponent) {
8511                     return ((AccessibleComponent) ac).getFont();
8512                 } else {
8513                     Component c = getCurrentComponent();
8514                     if (c != null) {
8515                         return c.getFont();
8516                     } else {
8517                         return null;
8518                     }
8519                 }
8520             }
8521 
8522             /**
8523              * Sets the <code>Font</code> of this object.
8524              *
8525              * @param f the new <code>Font</code> for the object
8526              */
8527             public void setFont(Font f) {
8528                 AccessibleContext ac = getCurrentAccessibleContext();
8529                 if (ac instanceof AccessibleComponent) {
8530                     ((AccessibleComponent) ac).setFont(f);
8531                 } else {
8532                     Component c = getCurrentComponent();
8533                     if (c != null) {
8534                         c.setFont(f);
8535                     }
8536                 }
8537             }
8538 
8539             /**
8540              * Gets the <code>FontMetrics</code> of this object.
8541              *
8542              * @param f the <code>Font</code>
8543              * @return the <code>FontMetrics</code> object, if supported;
8544              *    otherwise <code>null</code>
8545              * @see #getFont
8546              */
8547             public FontMetrics getFontMetrics(Font f) {
8548                 AccessibleContext ac = getCurrentAccessibleContext();
8549                 if (ac instanceof AccessibleComponent) {
8550                     return ((AccessibleComponent) ac).getFontMetrics(f);
8551                 } else {
8552                     Component c = getCurrentComponent();
8553                     if (c != null) {
8554                         return c.getFontMetrics(f);
8555                     } else {
8556                         return null;
8557                     }
8558                 }
8559             }
8560 
8561             /**
8562              * Determines if the object is enabled.
8563              *
8564              * @return true if object is enabled; otherwise, false
8565              */
8566             public boolean isEnabled() {
8567                 AccessibleContext ac = getCurrentAccessibleContext();
8568                 if (ac instanceof AccessibleComponent) {
8569                     return ((AccessibleComponent) ac).isEnabled();
8570                 } else {
8571                     Component c = getCurrentComponent();
8572                     if (c != null) {
8573                         return c.isEnabled();
8574                     } else {
8575                         return false;
8576                     }
8577                 }
8578             }
8579 
8580             /**
8581              * Sets the enabled state of the object.
8582              *
8583              * @param b if true, enables this object; otherwise, disables it
8584              */
8585             public void setEnabled(boolean b) {
8586                 AccessibleContext ac = getCurrentAccessibleContext();
8587                 if (ac instanceof AccessibleComponent) {
8588                     ((AccessibleComponent) ac).setEnabled(b);
8589                 } else {
8590                     Component c = getCurrentComponent();
8591                     if (c != null) {
8592                         c.setEnabled(b);
8593                     }
8594                 }
8595             }
8596 
8597             /**
8598              * Determines if this object is visible.  Note: this means that the
8599              * object intends to be visible; however, it may not in fact be
8600              * showing on the screen because one of the objects that this object
8601              * is contained by is not visible.  To determine if an object is
8602              * showing on the screen, use <code>isShowing</code>.
8603              *
8604              * @return true if object is visible; otherwise, false
8605              */
8606             public boolean isVisible() {
8607                 AccessibleContext ac = getCurrentAccessibleContext();
8608                 if (ac instanceof AccessibleComponent) {
8609                     return ((AccessibleComponent) ac).isVisible();
8610                 } else {
8611                     Component c = getCurrentComponent();
8612                     if (c != null) {
8613                         return c.isVisible();
8614                     } else {
8615                         return false;
8616                     }
8617                 }
8618             }
8619 
8620             /**
8621              * Sets the visible state of the object.
8622              *
8623              * @param b if true, shows this object; otherwise, hides it
8624              */
8625             public void setVisible(boolean b) {
8626                 AccessibleContext ac = getCurrentAccessibleContext();
8627                 if (ac instanceof AccessibleComponent) {
8628                     ((AccessibleComponent) ac).setVisible(b);
8629                 } else {
8630                     Component c = getCurrentComponent();
8631                     if (c != null) {
8632                         c.setVisible(b);
8633                     }
8634                 }
8635             }
8636 
8637             /**
8638              * Determines if the object is showing.  This is determined
8639              * by checking the visibility of the object and ancestors
8640              * of the object.  Note: this will return true even if the
8641              * object is obscured by another (for example,
8642              * it happens to be underneath a menu that was pulled down).
8643              *
8644              * @return true if the object is showing; otherwise, false
8645              */
8646             public boolean isShowing() {
8647                 AccessibleContext ac = getCurrentAccessibleContext();
8648                 if (ac instanceof AccessibleComponent) {
8649                     if (ac.getAccessibleParent() != null) {
8650                         return ((AccessibleComponent) ac).isShowing();
8651                     } else {
8652                         // Fixes 4529616 - AccessibleJTableCell.isShowing()
8653                         // returns false when the cell on the screen
8654                         // if no parent
8655                         return isVisible();
8656                     }
8657                 } else {
8658                     Component c = getCurrentComponent();
8659                     if (c != null) {
8660                         return c.isShowing();
8661                     } else {
8662                         return false;
8663                     }
8664                 }
8665             }
8666 
8667             /**
8668              * Checks whether the specified point is within this
8669              * object's bounds, where the point's x and y coordinates
8670              * are defined to be relative to the coordinate system of
8671              * the object.
8672              *
8673              * @param p the <code>Point</code> relative to the
8674              *    coordinate system of the object
8675              * @return true if object contains <code>Point</code>;
8676              *    otherwise false
8677              */
8678             public boolean contains(Point p) {
8679                 AccessibleContext ac = getCurrentAccessibleContext();
8680                 if (ac instanceof AccessibleComponent) {
8681                     Rectangle r = ((AccessibleComponent) ac).getBounds();
8682                     return r.contains(p);
8683                 } else {
8684                     Component c = getCurrentComponent();
8685                     if (c != null) {
8686                         Rectangle r = c.getBounds();
8687                         return r.contains(p);
8688                     } else {
8689                         return getBounds().contains(p);
8690                     }
8691                 }
8692             }
8693 
8694             /**
8695              * Returns the location of the object on the screen.
8696              *
8697              * @return location of object on screen -- can be
8698              *    <code>null</code> if this object is not on the screen
8699              */
8700             public Point getLocationOnScreen() {
8701                 if (parent != null && parent.isShowing()) {
8702                     Point parentLocation = parent.getLocationOnScreen();
8703                     Point componentLocation = getLocation();
8704                     componentLocation.translate(parentLocation.x, parentLocation.y);
8705                     return componentLocation;
8706                 } else {
8707                     return null;
8708                 }
8709             }
8710 
8711             /**
8712              * Gets the location of the object relative to the parent
8713              * in the form of a point specifying the object's
8714              * top-left corner in the screen's coordinate space.
8715              *
8716              * @return an instance of <code>Point</code> representing
8717              *    the top-left corner of the object's bounds in the
8718              *    coordinate space of the screen; <code>null</code> if
8719              *    this object or its parent are not on the screen
8720              */
8721             public Point getLocation() {
8722                 if (parent != null) {
8723                     Rectangle r = parent.getCellRect(row, column, false);
8724                     if (r != null) {
8725                         return r.getLocation();
8726                     }
8727                 }
8728                 return null;
8729             }
8730 
8731             /**
8732              * Sets the location of the object relative to the parent.
8733              */
8734             public void setLocation(Point p) {
8735 //              if ((parent != null)  && (parent.contains(p))) {
8736 //                  ensureIndexIsVisible(indexInParent);
8737 //              }
8738             }
8739 
8740             public Rectangle getBounds() {
8741                 if (parent != null) {
8742                     return parent.getCellRect(row, column, false);
8743                 } else {
8744                     return null;
8745                 }
8746             }
8747 
8748             public void setBounds(Rectangle r) {
8749                 AccessibleContext ac = getCurrentAccessibleContext();
8750                 if (ac instanceof AccessibleComponent) {
8751                     ((AccessibleComponent) ac).setBounds(r);
8752                 } else {
8753                     Component c = getCurrentComponent();
8754                     if (c != null) {
8755                         c.setBounds(r);
8756                     }
8757                 }
8758             }
8759 
8760             public Dimension getSize() {
8761                 if (parent != null) {
8762                     Rectangle r = parent.getCellRect(row, column, false);
8763                     if (r != null) {
8764                         return r.getSize();
8765                     }
8766                 }
8767                 return null;
8768             }
8769 
8770             public void setSize (Dimension d) {
8771                 AccessibleContext ac = getCurrentAccessibleContext();
8772                 if (ac instanceof AccessibleComponent) {
8773                     ((AccessibleComponent) ac).setSize(d);
8774                 } else {
8775                     Component c = getCurrentComponent();
8776                     if (c != null) {
8777                         c.setSize(d);
8778                     }
8779                 }
8780             }
8781 
8782             public Accessible getAccessibleAt(Point p) {
8783                 AccessibleContext ac = getCurrentAccessibleContext();
8784                 if (ac instanceof AccessibleComponent) {
8785                     return ((AccessibleComponent) ac).getAccessibleAt(p);
8786                 } else {
8787                     return null;
8788                 }
8789             }
8790 
8791             public boolean isFocusTraversable() {
8792                 AccessibleContext ac = getCurrentAccessibleContext();
8793                 if (ac instanceof AccessibleComponent) {
8794                     return ((AccessibleComponent) ac).isFocusTraversable();
8795                 } else {
8796                     Component c = getCurrentComponent();
8797                     if (c != null) {
8798                         return c.isFocusTraversable();
8799                     } else {
8800                         return false;
8801                     }
8802                 }
8803             }
8804 
8805             public void requestFocus() {
8806                 AccessibleContext ac = getCurrentAccessibleContext();
8807                 if (ac instanceof AccessibleComponent) {
8808                     ((AccessibleComponent) ac).requestFocus();
8809                 } else {
8810                     Component c = getCurrentComponent();
8811                     if (c != null) {
8812                         c.requestFocus();
8813                     }
8814                 }
8815             }
8816 
8817             public void addFocusListener(FocusListener l) {
8818                 AccessibleContext ac = getCurrentAccessibleContext();
8819                 if (ac instanceof AccessibleComponent) {
8820                     ((AccessibleComponent) ac).addFocusListener(l);
8821                 } else {
8822                     Component c = getCurrentComponent();
8823                     if (c != null) {
8824                         c.addFocusListener(l);
8825                     }
8826                 }
8827             }
8828 
8829             public void removeFocusListener(FocusListener l) {
8830                 AccessibleContext ac = getCurrentAccessibleContext();
8831                 if (ac instanceof AccessibleComponent) {
8832                     ((AccessibleComponent) ac).removeFocusListener(l);
8833                 } else {
8834                     Component c = getCurrentComponent();
8835                     if (c != null) {
8836                         c.removeFocusListener(l);
8837                     }
8838                 }
8839             }
8840 
8841         } // inner class AccessibleJTableCell
8842 
8843         // Begin AccessibleJTableHeader ========== // TIGER - 4715503
8844 
8845         /**
8846          * This class implements accessibility for JTable header cells.
8847          */
8848         private class AccessibleJTableHeaderCell extends AccessibleContext
8849             implements Accessible, AccessibleComponent {
8850 
8851             private int row;
8852             private int column;
8853             private JTableHeader parent;
8854             private Component rendererComponent;
8855 
8856             /**
8857              * Constructs an <code>AccessibleJTableHeaderEntry</code> instance.
8858              *
8859              * @param row header cell row index
8860              * @param column header cell column index
8861              * @param parent header cell parent
8862              * @param rendererComponent component that renders the header cell
8863              */
8864             public AccessibleJTableHeaderCell(int row, int column,
8865                                               JTableHeader parent,
8866                                               Component rendererComponent) {
8867                 this.row = row;
8868                 this.column = column;
8869                 this.parent = parent;
8870                 this.rendererComponent = rendererComponent;
8871                 this.setAccessibleParent(parent);
8872             }
8873 
8874             /**
8875              * Gets the <code>AccessibleContext</code> associated with this
8876              * component. In the implementation of the Java Accessibility
8877              * API for this class, return this object, which is its own
8878              * <code>AccessibleContext</code>.
8879              *
8880              * @return this object
8881              */
8882             public AccessibleContext getAccessibleContext() {
8883                 return this;
8884             }
8885 
8886             /*
8887              * Returns the AccessibleContext for the header cell
8888              * renderer.
8889              */
8890             private AccessibleContext getCurrentAccessibleContext() {
8891                 return rendererComponent.getAccessibleContext();
8892             }
8893 
8894             /*
8895              * Returns the component that renders the header cell.
8896              */
8897             private Component getCurrentComponent() {
8898                 return rendererComponent;
8899             }
8900 
8901             // AccessibleContext methods ==========
8902 
8903             /**
8904              * Gets the accessible name of this object.
8905              *
8906              * @return the localized name of the object; <code>null</code>
8907              *     if this object does not have a name
8908              */
8909             public String getAccessibleName() {
8910                 AccessibleContext ac = getCurrentAccessibleContext();
8911                 if (ac != null) {
8912                     String name = ac.getAccessibleName();
8913                     if ((name != null) && (name != "")) {
8914                         return ac.getAccessibleName();
8915                     }
8916                 }
8917                 if ((accessibleName != null) && (accessibleName != "")) {
8918                     return accessibleName;
8919                 } else {
8920                     return null;
8921                 }
8922             }
8923 
8924             /**
8925              * Sets the localized accessible name of this object.
8926              *
8927              * @param s the new localized name of the object
8928              */
8929             public void setAccessibleName(String s) {
8930                 AccessibleContext ac = getCurrentAccessibleContext();
8931                 if (ac != null) {
8932                     ac.setAccessibleName(s);
8933                 } else {
8934                     super.setAccessibleName(s);
8935                 }
8936             }
8937 
8938             /**
8939              * Gets the accessible description of this object.
8940              *
8941              * @return the localized description of the object;
8942              *     <code>null</code> if this object does not have
8943              *     a description
8944              */
8945             public String getAccessibleDescription() {
8946                 AccessibleContext ac = getCurrentAccessibleContext();
8947                 if (ac != null) {
8948                     return ac.getAccessibleDescription();
8949                 } else {
8950                     return super.getAccessibleDescription();
8951                 }
8952             }
8953 
8954             /**
8955              * Sets the accessible description of this object.
8956              *
8957              * @param s the new localized description of the object
8958              */
8959             public void setAccessibleDescription(String s) {
8960                 AccessibleContext ac = getCurrentAccessibleContext();
8961                 if (ac != null) {
8962                     ac.setAccessibleDescription(s);
8963                 } else {
8964                     super.setAccessibleDescription(s);
8965                 }
8966             }
8967 
8968             /**
8969              * Gets the role of this object.
8970              *
8971              * @return an instance of <code>AccessibleRole</code>
8972              *      describing the role of the object
8973              * @see AccessibleRole
8974              */
8975             public AccessibleRole getAccessibleRole() {
8976                 AccessibleContext ac = getCurrentAccessibleContext();
8977                 if (ac != null) {
8978                     return ac.getAccessibleRole();
8979                 } else {
8980                     return AccessibleRole.UNKNOWN;
8981                 }
8982             }
8983 
8984             /**
8985              * Gets the state set of this object.
8986              *
8987              * @return an instance of <code>AccessibleStateSet</code>
8988              *     containing the current state set of the object
8989              * @see AccessibleState
8990              */
8991             public AccessibleStateSet getAccessibleStateSet() {
8992                 AccessibleContext ac = getCurrentAccessibleContext();
8993                 AccessibleStateSet as = null;
8994 
8995                 if (ac != null) {
8996                     as = ac.getAccessibleStateSet();
8997                 }
8998                 if (as == null) {
8999                     as = new AccessibleStateSet();
9000                 }
9001                 Rectangle rjt = JTable.this.getVisibleRect();
9002                 Rectangle rcell = JTable.this.getCellRect(row, column, false);
9003                 if (rjt.intersects(rcell)) {
9004                     as.add(AccessibleState.SHOWING);
9005                 } else {
9006                     if (as.contains(AccessibleState.SHOWING)) {
9007                          as.remove(AccessibleState.SHOWING);
9008                     }
9009                 }
9010                 if (JTable.this.isCellSelected(row, column)) {
9011                     as.add(AccessibleState.SELECTED);
9012                 } else if (as.contains(AccessibleState.SELECTED)) {
9013                     as.remove(AccessibleState.SELECTED);
9014                 }
9015                 if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
9016                     as.add(AccessibleState.ACTIVE);
9017                 }
9018                 as.add(AccessibleState.TRANSIENT);
9019                 return as;
9020             }
9021 
9022             /**
9023              * Gets the <code>Accessible</code> parent of this object.
9024              *
9025              * @return the Accessible parent of this object;
9026              *     <code>null</code> if this object does not
9027              *     have an <code>Accessible</code> parent
9028              */
9029             public Accessible getAccessibleParent() {
9030                 return parent;
9031             }
9032 
9033             /**
9034              * Gets the index of this object in its accessible parent.
9035              *
9036              * @return the index of this object in its parent; -1 if this
9037              *     object does not have an accessible parent
9038              * @see #getAccessibleParent
9039              */
9040             public int getAccessibleIndexInParent() {
9041                 return column;
9042             }
9043 
9044             /**
9045              * Returns the number of accessible children in the object.
9046              *
9047              * @return the number of accessible children in the object
9048              */
9049             public int getAccessibleChildrenCount() {
9050                 AccessibleContext ac = getCurrentAccessibleContext();
9051                 if (ac != null) {
9052                     return ac.getAccessibleChildrenCount();
9053                 } else {
9054                     return 0;
9055                 }
9056             }
9057 
9058             /**
9059              * Returns the specified <code>Accessible</code> child of the
9060              * object.
9061              *
9062              * @param i zero-based index of child
9063              * @return the <code>Accessible</code> child of the object
9064              */
9065             public Accessible getAccessibleChild(int i) {
9066                 AccessibleContext ac = getCurrentAccessibleContext();
9067                 if (ac != null) {
9068                     Accessible accessibleChild = ac.getAccessibleChild(i);
9069                     ac.setAccessibleParent(this);
9070                     return accessibleChild;
9071                 } else {
9072                     return null;
9073                 }
9074             }
9075 
9076             /**
9077              * Gets the locale of the component. If the component
9078              * does not have a locale, then the locale of its parent
9079              * is returned.
9080              *
9081              * @return this component's locale; if this component does
9082              *    not have a locale, the locale of its parent is returned
9083              * @exception IllegalComponentStateException if the
9084              *    <code>Component</code> does not have its own locale
9085              *    and has not yet been added to a containment hierarchy
9086              *    such that the locale can be determined from the
9087              *    containing parent
9088              * @see #setLocale
9089              */
9090             public Locale getLocale() {
9091                 AccessibleContext ac = getCurrentAccessibleContext();
9092                 if (ac != null) {
9093                     return ac.getLocale();
9094                 } else {
9095                     return null;
9096                 }
9097             }
9098 
9099             /**
9100              * Adds a <code>PropertyChangeListener</code> to the listener list.
9101              * The listener is registered for all properties.
9102              *
9103              * @param l  the <code>PropertyChangeListener</code>
9104              *     to be added
9105              */
9106             public void addPropertyChangeListener(PropertyChangeListener l) {
9107                 AccessibleContext ac = getCurrentAccessibleContext();
9108                 if (ac != null) {
9109                     ac.addPropertyChangeListener(l);
9110                 } else {
9111                     super.addPropertyChangeListener(l);
9112                 }
9113             }
9114 
9115             /**
9116              * Removes a <code>PropertyChangeListener</code> from the
9117              * listener list. This removes a <code>PropertyChangeListener</code>
9118              * that was registered for all properties.
9119              *
9120              * @param l  the <code>PropertyChangeListener</code>
9121              *    to be removed
9122              */
9123             public void removePropertyChangeListener(PropertyChangeListener l) {
9124                 AccessibleContext ac = getCurrentAccessibleContext();
9125                 if (ac != null) {
9126                     ac.removePropertyChangeListener(l);
9127                 } else {
9128                     super.removePropertyChangeListener(l);
9129                 }
9130             }
9131 
9132             /**
9133              * Gets the <code>AccessibleAction</code> associated with this
9134              * object if one exists.  Otherwise returns <code>null</code>.
9135              *
9136              * @return the <code>AccessibleAction</code>, or <code>null</code>
9137              */
9138             public AccessibleAction getAccessibleAction() {
9139                 return getCurrentAccessibleContext().getAccessibleAction();
9140             }
9141 
9142             /**
9143              * Gets the <code>AccessibleComponent</code> associated with
9144              * this object if one exists.  Otherwise returns <code>null</code>.
9145              *
9146              * @return the <code>AccessibleComponent</code>, or
9147              *    <code>null</code>
9148              */
9149             public AccessibleComponent getAccessibleComponent() {
9150                 return this; // to override getBounds()
9151             }
9152 
9153             /**
9154              * Gets the <code>AccessibleSelection</code> associated with
9155              * this object if one exists.  Otherwise returns <code>null</code>.
9156              *
9157              * @return the <code>AccessibleSelection</code>, or
9158              *    <code>null</code>
9159              */
9160             public AccessibleSelection getAccessibleSelection() {
9161                 return getCurrentAccessibleContext().getAccessibleSelection();
9162             }
9163 
9164             /**
9165              * Gets the <code>AccessibleText</code> associated with this
9166              * object if one exists.  Otherwise returns <code>null</code>.
9167              *
9168              * @return the <code>AccessibleText</code>, or <code>null</code>
9169              */
9170             public AccessibleText getAccessibleText() {
9171                 return getCurrentAccessibleContext().getAccessibleText();
9172             }
9173 
9174             /**
9175              * Gets the <code>AccessibleValue</code> associated with
9176              * this object if one exists.  Otherwise returns <code>null</code>.
9177              *
9178              * @return the <code>AccessibleValue</code>, or <code>null</code>
9179              */
9180             public AccessibleValue getAccessibleValue() {
9181                 return getCurrentAccessibleContext().getAccessibleValue();
9182             }
9183 
9184 
9185             // AccessibleComponent methods ==========
9186 
9187             /**
9188              * Gets the background color of this object.
9189              *
9190              * @return the background color, if supported, of the object;
9191              *     otherwise, <code>null</code>
9192              */
9193             public Color getBackground() {
9194                 AccessibleContext ac = getCurrentAccessibleContext();
9195                 if (ac instanceof AccessibleComponent) {
9196                     return ((AccessibleComponent) ac).getBackground();
9197                 } else {
9198                     Component c = getCurrentComponent();
9199                     if (c != null) {
9200                         return c.getBackground();
9201                     } else {
9202                         return null;
9203                     }
9204                 }
9205             }
9206 
9207             /**
9208              * Sets the background color of this object.
9209              *
9210              * @param c the new <code>Color</code> for the background
9211              */
9212             public void setBackground(Color c) {
9213                 AccessibleContext ac = getCurrentAccessibleContext();
9214                 if (ac instanceof AccessibleComponent) {
9215                     ((AccessibleComponent) ac).setBackground(c);
9216                 } else {
9217                     Component cp = getCurrentComponent();
9218                     if (cp != null) {
9219                         cp.setBackground(c);
9220                     }
9221                 }
9222             }
9223 
9224             /**
9225              * Gets the foreground color of this object.
9226              *
9227              * @return the foreground color, if supported, of the object;
9228              *     otherwise, <code>null</code>
9229              */
9230             public Color getForeground() {
9231                 AccessibleContext ac = getCurrentAccessibleContext();
9232                 if (ac instanceof AccessibleComponent) {
9233                     return ((AccessibleComponent) ac).getForeground();
9234                 } else {
9235                     Component c = getCurrentComponent();
9236                     if (c != null) {
9237                         return c.getForeground();
9238                     } else {
9239                         return null;
9240                     }
9241                 }
9242             }
9243 
9244             /**
9245              * Sets the foreground color of this object.
9246              *
9247              * @param c the new <code>Color</code> for the foreground
9248              */
9249             public void setForeground(Color c) {
9250                 AccessibleContext ac = getCurrentAccessibleContext();
9251                 if (ac instanceof AccessibleComponent) {
9252                     ((AccessibleComponent) ac).setForeground(c);
9253                 } else {
9254                     Component cp = getCurrentComponent();
9255                     if (cp != null) {
9256                         cp.setForeground(c);
9257                     }
9258                 }
9259             }
9260 
9261             /**
9262              * Gets the <code>Cursor</code> of this object.
9263              *
9264              * @return the <code>Cursor</code>, if supported,
9265              *    of the object; otherwise, <code>null</code>
9266              */
9267             public Cursor getCursor() {
9268                 AccessibleContext ac = getCurrentAccessibleContext();
9269                 if (ac instanceof AccessibleComponent) {
9270                     return ((AccessibleComponent) ac).getCursor();
9271                 } else {
9272                     Component c = getCurrentComponent();
9273                     if (c != null) {
9274                         return c.getCursor();
9275                     } else {
9276                         Accessible ap = getAccessibleParent();
9277                         if (ap instanceof AccessibleComponent) {
9278                             return ((AccessibleComponent) ap).getCursor();
9279                         } else {
9280                             return null;
9281                         }
9282                     }
9283                 }
9284             }
9285 
9286             /**
9287              * Sets the <code>Cursor</code> of this object.
9288              *
9289              * @param c the new <code>Cursor</code> for the object
9290              */
9291             public void setCursor(Cursor c) {
9292                 AccessibleContext ac = getCurrentAccessibleContext();
9293                 if (ac instanceof AccessibleComponent) {
9294                     ((AccessibleComponent) ac).setCursor(c);
9295                 } else {
9296                     Component cp = getCurrentComponent();
9297                     if (cp != null) {
9298                         cp.setCursor(c);
9299                     }
9300                 }
9301             }
9302 
9303             /**
9304              * Gets the <code>Font</code> of this object.
9305              *
9306              * @return the <code>Font</code>,if supported,
9307              *   for the object; otherwise, <code>null</code>
9308              */
9309             public Font getFont() {
9310                 AccessibleContext ac = getCurrentAccessibleContext();
9311                 if (ac instanceof AccessibleComponent) {
9312                     return ((AccessibleComponent) ac).getFont();
9313                 } else {
9314                     Component c = getCurrentComponent();
9315                     if (c != null) {
9316                         return c.getFont();
9317                     } else {
9318                         return null;
9319                     }
9320                 }
9321             }
9322 
9323             /**
9324              * Sets the <code>Font</code> of this object.
9325              *
9326              * @param f the new <code>Font</code> for the object
9327              */
9328             public void setFont(Font f) {
9329                 AccessibleContext ac = getCurrentAccessibleContext();
9330                 if (ac instanceof AccessibleComponent) {
9331                     ((AccessibleComponent) ac).setFont(f);
9332                 } else {
9333                     Component c = getCurrentComponent();
9334                     if (c != null) {
9335                         c.setFont(f);
9336                     }
9337                 }
9338             }
9339 
9340             /**
9341              * Gets the <code>FontMetrics</code> of this object.
9342              *
9343              * @param f the <code>Font</code>
9344              * @return the <code>FontMetrics</code> object, if supported;
9345              *    otherwise <code>null</code>
9346              * @see #getFont
9347              */
9348             public FontMetrics getFontMetrics(Font f) {
9349                 AccessibleContext ac = getCurrentAccessibleContext();
9350                 if (ac instanceof AccessibleComponent) {
9351                     return ((AccessibleComponent) ac).getFontMetrics(f);
9352                 } else {
9353                     Component c = getCurrentComponent();
9354                     if (c != null) {
9355                         return c.getFontMetrics(f);
9356                     } else {
9357                         return null;
9358                     }
9359                 }
9360             }
9361 
9362             /**
9363              * Determines if the object is enabled.
9364              *
9365              * @return true if object is enabled; otherwise, false
9366              */
9367             public boolean isEnabled() {
9368                 AccessibleContext ac = getCurrentAccessibleContext();
9369                 if (ac instanceof AccessibleComponent) {
9370                     return ((AccessibleComponent) ac).isEnabled();
9371                 } else {
9372                     Component c = getCurrentComponent();
9373                     if (c != null) {
9374                         return c.isEnabled();
9375                     } else {
9376                         return false;
9377                     }
9378                 }
9379             }
9380 
9381             /**
9382              * Sets the enabled state of the object.
9383              *
9384              * @param b if true, enables this object; otherwise, disables it
9385              */
9386             public void setEnabled(boolean b) {
9387                 AccessibleContext ac = getCurrentAccessibleContext();
9388                 if (ac instanceof AccessibleComponent) {
9389                     ((AccessibleComponent) ac).setEnabled(b);
9390                 } else {
9391                     Component c = getCurrentComponent();
9392                     if (c != null) {
9393                         c.setEnabled(b);
9394                     }
9395                 }
9396             }
9397 
9398             /**
9399              * Determines if this object is visible.  Note: this means that the
9400              * object intends to be visible; however, it may not in fact be
9401              * showing on the screen because one of the objects that this object
9402              * is contained by is not visible.  To determine if an object is
9403              * showing on the screen, use <code>isShowing</code>.
9404              *
9405              * @return true if object is visible; otherwise, false
9406              */
9407             public boolean isVisible() {
9408                 AccessibleContext ac = getCurrentAccessibleContext();
9409                 if (ac instanceof AccessibleComponent) {
9410                     return ((AccessibleComponent) ac).isVisible();
9411                 } else {
9412                     Component c = getCurrentComponent();
9413                     if (c != null) {
9414                         return c.isVisible();
9415                     } else {
9416                         return false;
9417                     }
9418                 }
9419             }
9420 
9421             /**
9422              * Sets the visible state of the object.
9423              *
9424              * @param b if true, shows this object; otherwise, hides it
9425              */
9426             public void setVisible(boolean b) {
9427                 AccessibleContext ac = getCurrentAccessibleContext();
9428                 if (ac instanceof AccessibleComponent) {
9429                     ((AccessibleComponent) ac).setVisible(b);
9430                 } else {
9431                     Component c = getCurrentComponent();
9432                     if (c != null) {
9433                         c.setVisible(b);
9434                     }
9435                 }
9436             }
9437 
9438             /**
9439              * Determines if the object is showing.  This is determined
9440              * by checking the visibility of the object and ancestors
9441              * of the object.  Note: this will return true even if the
9442              * object is obscured by another (for example,
9443              * it happens to be underneath a menu that was pulled down).
9444              *
9445              * @return true if the object is showing; otherwise, false
9446              */
9447             public boolean isShowing() {
9448                 AccessibleContext ac = getCurrentAccessibleContext();
9449                 if (ac instanceof AccessibleComponent) {
9450                     if (ac.getAccessibleParent() != null) {
9451                         return ((AccessibleComponent) ac).isShowing();
9452                     } else {
9453                         // Fixes 4529616 - AccessibleJTableCell.isShowing()
9454                         // returns false when the cell on the screen
9455                         // if no parent
9456                         return isVisible();
9457                     }
9458                 } else {
9459                     Component c = getCurrentComponent();
9460                     if (c != null) {
9461                         return c.isShowing();
9462                     } else {
9463                         return false;
9464                     }
9465                 }
9466             }
9467 
9468             /**
9469              * Checks whether the specified point is within this
9470              * object's bounds, where the point's x and y coordinates
9471              * are defined to be relative to the coordinate system of
9472              * the object.
9473              *
9474              * @param p the <code>Point</code> relative to the
9475              *    coordinate system of the object
9476              * @return true if object contains <code>Point</code>;
9477              *    otherwise false
9478              */
9479             public boolean contains(Point p) {
9480                 AccessibleContext ac = getCurrentAccessibleContext();
9481                 if (ac instanceof AccessibleComponent) {
9482                     Rectangle r = ((AccessibleComponent) ac).getBounds();
9483                     return r.contains(p);
9484                 } else {
9485                     Component c = getCurrentComponent();
9486                     if (c != null) {
9487                         Rectangle r = c.getBounds();
9488                         return r.contains(p);
9489                     } else {
9490                         return getBounds().contains(p);
9491                     }
9492                 }
9493             }
9494 
9495             /**
9496              * Returns the location of the object on the screen.
9497              *
9498              * @return location of object on screen -- can be
9499              *    <code>null</code> if this object is not on the screen
9500              */
9501             public Point getLocationOnScreen() {
9502                 if (parent != null && parent.isShowing()) {
9503                     Point parentLocation = parent.getLocationOnScreen();
9504                     Point componentLocation = getLocation();
9505                     componentLocation.translate(parentLocation.x, parentLocation.y);
9506                     return componentLocation;
9507                 } else {
9508                     return null;
9509                 }
9510             }
9511 
9512             /**
9513              * Gets the location of the object relative to the parent
9514              * in the form of a point specifying the object's
9515              * top-left corner in the screen's coordinate space.
9516              *
9517              * @return an instance of <code>Point</code> representing
9518              *    the top-left corner of the object's bounds in the
9519              *    coordinate space of the screen; <code>null</code> if
9520              *    this object or its parent are not on the screen
9521              */
9522             public Point getLocation() {
9523                 if (parent != null) {
9524                     Rectangle r = parent.getHeaderRect(column);
9525                     if (r != null) {
9526                         return r.getLocation();
9527                     }
9528                 }
9529                 return null;
9530             }
9531 
9532             /**
9533              * Sets the location of the object relative to the parent.
9534              * @param p the new position for the top-left corner
9535              * @see #getLocation
9536              */
9537             public void setLocation(Point p) {
9538             }
9539 
9540             /**
9541              * Gets the bounds of this object in the form of a Rectangle object.
9542              * The bounds specify this object's width, height, and location
9543              * relative to its parent.
9544              *
9545              * @return A rectangle indicating this component's bounds; null if
9546              * this object is not on the screen.
9547              * @see #contains
9548              */
9549             public Rectangle getBounds() {
9550                 if (parent != null) {
9551                     return parent.getHeaderRect(column);
9552                 } else {
9553                     return null;
9554                 }
9555             }
9556 
9557             /**
9558              * Sets the bounds of this object in the form of a Rectangle object.
9559              * The bounds specify this object's width, height, and location
9560              * relative to its parent.
9561              *
9562              * @param r rectangle indicating this component's bounds
9563              * @see #getBounds
9564              */
9565             public void setBounds(Rectangle r) {
9566                 AccessibleContext ac = getCurrentAccessibleContext();
9567                 if (ac instanceof AccessibleComponent) {
9568                     ((AccessibleComponent) ac).setBounds(r);
9569                 } else {
9570                     Component c = getCurrentComponent();
9571                     if (c != null) {
9572                         c.setBounds(r);
9573                     }
9574                 }
9575             }
9576 
9577             /**
9578              * Returns the size of this object in the form of a Dimension object.
9579              * The height field of the Dimension object contains this object's
9580              * height, and the width field of the Dimension object contains this
9581              * object's width.
9582              *
9583              * @return A Dimension object that indicates the size of this component;
9584              * null if this object is not on the screen
9585              * @see #setSize
9586              */
9587             public Dimension getSize() {
9588                 if (parent != null) {
9589                     Rectangle r = parent.getHeaderRect(column);
9590                     if (r != null) {
9591                         return r.getSize();
9592                     }
9593                 }
9594                 return null;
9595             }
9596 
9597             /**
9598              * Resizes this object so that it has width and height.
9599              *
9600              * @param d The dimension specifying the new size of the object.
9601              * @see #getSize
9602              */
9603             public void setSize (Dimension d) {
9604                 AccessibleContext ac = getCurrentAccessibleContext();
9605                 if (ac instanceof AccessibleComponent) {
9606                     ((AccessibleComponent) ac).setSize(d);
9607                 } else {
9608                     Component c = getCurrentComponent();
9609                     if (c != null) {
9610                         c.setSize(d);
9611                     }
9612                 }
9613             }
9614 
9615             /**
9616              * Returns the Accessible child, if one exists, contained at the local
9617              * coordinate Point.
9618              *
9619              * @param p The point relative to the coordinate system of this object.
9620              * @return the Accessible, if it exists, at the specified location;
9621              * otherwise null
9622              */
9623             public Accessible getAccessibleAt(Point p) {
9624                 AccessibleContext ac = getCurrentAccessibleContext();
9625                 if (ac instanceof AccessibleComponent) {
9626                     return ((AccessibleComponent) ac).getAccessibleAt(p);
9627                 } else {
9628                     return null;
9629                 }
9630             }
9631 
9632             /**
9633              * Returns whether this object can accept focus or not.   Objects that
9634              * can accept focus will also have the AccessibleState.FOCUSABLE state
9635              * set in their AccessibleStateSets.
9636              *
9637              * @return true if object can accept focus; otherwise false
9638              * @see AccessibleContext#getAccessibleStateSet
9639              * @see AccessibleState#FOCUSABLE
9640              * @see AccessibleState#FOCUSED
9641              * @see AccessibleStateSet
9642              */
9643             public boolean isFocusTraversable() {
9644                 AccessibleContext ac = getCurrentAccessibleContext();
9645                 if (ac instanceof AccessibleComponent) {
9646                     return ((AccessibleComponent) ac).isFocusTraversable();
9647                 } else {
9648                     Component c = getCurrentComponent();
9649                     if (c != null) {
9650                         return c.isFocusTraversable();
9651                     } else {
9652                         return false;
9653                     }
9654                 }
9655             }
9656 
9657             /**
9658              * Requests focus for this object.  If this object cannot accept focus,
9659              * nothing will happen.  Otherwise, the object will attempt to take
9660              * focus.
9661              * @see #isFocusTraversable
9662              */
9663             public void requestFocus() {
9664                 AccessibleContext ac = getCurrentAccessibleContext();
9665                 if (ac instanceof AccessibleComponent) {
9666                     ((AccessibleComponent) ac).requestFocus();
9667                 } else {
9668                     Component c = getCurrentComponent();
9669                     if (c != null) {
9670                         c.requestFocus();
9671                     }
9672                 }
9673             }
9674 
9675             /**
9676              * Adds the specified focus listener to receive focus events from this
9677              * component.
9678              *
9679              * @param l the focus listener
9680              * @see #removeFocusListener
9681              */
9682             public void addFocusListener(FocusListener l) {
9683                 AccessibleContext ac = getCurrentAccessibleContext();
9684                 if (ac instanceof AccessibleComponent) {
9685                     ((AccessibleComponent) ac).addFocusListener(l);
9686                 } else {
9687                     Component c = getCurrentComponent();
9688                     if (c != null) {
9689                         c.addFocusListener(l);
9690                     }
9691                 }
9692             }
9693 
9694             /**
9695              * Removes the specified focus listener so it no longer receives focus
9696              * events from this component.
9697              *
9698              * @param l the focus listener
9699              * @see #addFocusListener
9700              */
9701             public void removeFocusListener(FocusListener l) {
9702                 AccessibleContext ac = getCurrentAccessibleContext();
9703                 if (ac instanceof AccessibleComponent) {
9704                     ((AccessibleComponent) ac).removeFocusListener(l);
9705                 } else {
9706                     Component c = getCurrentComponent();
9707                     if (c != null) {
9708                         c.removeFocusListener(l);
9709                     }
9710                 }
9711             }
9712 
9713         } // inner class AccessibleJTableHeaderCell
9714 
9715     }  // inner class AccessibleJTable
9716 
9717 }  // End of Class JTable