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