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