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