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