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