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