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