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