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