Save This Page
Home » openjdk-7 » javax » swing » [javadoc | source]
    1   /*
    2    * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package javax.swing;
   27   
   28   import java.util;
   29   
   30   import java.applet.Applet;
   31   import java.awt;
   32   import java.awt.event;
   33   import java.awt.print;
   34   
   35   import java.beans;
   36   
   37   import java.io.Serializable;
   38   import java.io.ObjectOutputStream;
   39   import java.io.ObjectInputStream;
   40   import java.io.IOException;
   41   
   42   import javax.accessibility;
   43   
   44   import javax.swing.event;
   45   import javax.swing.plaf;
   46   import javax.swing.table;
   47   import javax.swing.border;
   48   
   49   import java.text.NumberFormat;
   50   import java.text.DateFormat;
   51   import java.text.MessageFormat;
   52   
   53   import javax.print.attribute;
   54   import javax.print.PrintService;
   55   
   56   import sun.swing.SwingUtilities2;
   57   import sun.swing.SwingUtilities2.Section;
   58   import static sun.swing.SwingUtilities2.Section.*;
   59   import sun.swing.PrintingStatus;
   60   
   61   /**
   62    * The <code>JTable</code> is used to display and edit regular two-dimensional tables
   63    * of cells.
   64    * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/table.html">How to Use Tables</a>
   65    * in <em>The Java Tutorial</em>
   66    * for task-oriented documentation and examples of using <code>JTable</code>.
   67    *
   68    * <p>
   69    * The <code>JTable</code> has many
   70    * facilities that make it possible to customize its rendering and editing
   71    * but provides defaults for these features so that simple tables can be
   72    * set up easily.  For example, to set up a table with 10 rows and 10
   73    * columns of numbers:
   74    * <p>
   75    * <pre>
   76    *      TableModel dataModel = new AbstractTableModel() {
   77    *          public int getColumnCount() { return 10; }
   78    *          public int getRowCount() { return 10;}
   79    *          public Object getValueAt(int row, int col) { return new Integer(row*col); }
   80    *      };
   81    *      JTable table = new JTable(dataModel);
   82    *      JScrollPane scrollpane = new JScrollPane(table);
   83    * </pre>
   84    * <p>
   85    * {@code JTable}s are typically placed inside of a {@code JScrollPane}.  By
   86    * default, a {@code JTable} will adjust its width such that
   87    * a horizontal scrollbar is unnecessary.  To allow for a horizontal scrollbar,
   88    * invoke {@link #setAutoResizeMode} with {@code AUTO_RESIZE_OFF}.
   89    * Note that if you wish to use a <code>JTable</code> in a standalone
   90    * view (outside of a <code>JScrollPane</code>) and want the header
   91    * displayed, you can get it using {@link #getTableHeader} and
   92    * display it separately.
   93    * <p>
   94    * To enable sorting and filtering of rows, use a
   95    * {@code RowSorter}.
   96    * You can set up a row sorter in either of two ways:
   97    * <ul>
   98    *   <li>Directly set the {@code RowSorter}. For example:
   99    *        {@code table.setRowSorter(new TableRowSorter(model))}.
  100    *   <li>Set the {@code autoCreateRowSorter}
  101    *       property to {@code true}, so that the {@code JTable}
  102    *       creates a {@code RowSorter} for
  103    *       you. For example: {@code setAutoCreateRowSorter(true)}.
  104    * </ul>
  105    * <p>
  106    * When designing applications that use the <code>JTable</code> it is worth paying
  107    * close attention to the data structures that will represent the table's data.
  108    * The <code>DefaultTableModel</code> is a model implementation that
  109    * uses a <code>Vector</code> of <code>Vector</code>s of <code>Object</code>s to
  110    * store the cell values. As well as copying the data from an
  111    * application into the <code>DefaultTableModel</code>,
  112    * it is also possible to wrap the data in the methods of the
  113    * <code>TableModel</code> interface so that the data can be passed to the
  114    * <code>JTable</code> directly, as in the example above. This often results
  115    * in more efficient applications because the model is free to choose the
  116    * internal representation that best suits the data.
  117    * A good rule of thumb for deciding whether to use the <code>AbstractTableModel</code>
  118    * or the <code>DefaultTableModel</code> is to use the <code>AbstractTableModel</code>
  119    * as the base class for creating subclasses and the <code>DefaultTableModel</code>
  120    * when subclassing is not required.
  121    * <p>
  122    * The "TableExample" directory in the demo area of the source distribution
  123    * gives a number of complete examples of <code>JTable</code> usage,
  124    * covering how the <code>JTable</code> can be used to provide an
  125    * editable view of data taken from a database and how to modify
  126    * the columns in the display to use specialized renderers and editors.
  127    * <p>
  128    * The <code>JTable</code> uses integers exclusively to refer to both the rows and the columns
  129    * of the model that it displays. The <code>JTable</code> simply takes a tabular range of cells
  130    * and uses <code>getValueAt(int, int)</code> to retrieve the
  131    * values from the model during painting.  It is important to remember that
  132    * the column and row indexes returned by various <code>JTable</code> methods
  133    * are in terms of the <code>JTable</code> (the view) and are not
  134    * necessarily the same indexes used by the model.
  135    * <p>
  136    * By default, columns may be rearranged in the <code>JTable</code> so that the
  137    * view's columns appear in a different order to the columns in the model.
  138    * This does not affect the implementation of the model at all: when the
  139    * columns are reordered, the <code>JTable</code> maintains the new order of the columns
  140    * internally and converts its column indices before querying the model.
  141    * <p>
  142    * So, when writing a <code>TableModel</code>, it is not necessary to listen for column
  143    * reordering events as the model will be queried in its own coordinate
  144    * system regardless of what is happening in the view.
  145    * In the examples area there is a demonstration of a sorting algorithm making
  146    * use of exactly this technique to interpose yet another coordinate system
  147    * where the order of the rows is changed, rather than the order of the columns.
  148    * <p>
  149    * Similarly when using the sorting and filtering functionality
  150    * provided by <code>RowSorter</code> the underlying
  151    * <code>TableModel</code> does not need to know how to do sorting,
  152    * rather <code>RowSorter</code> will handle it.  Coordinate
  153    * conversions will be necessary when using the row based methods of
  154    * <code>JTable</code> with the underlying <code>TableModel</code>.
  155    * All of <code>JTable</code>s row based methods are in terms of the
  156    * <code>RowSorter</code>, which is not necessarily the same as that
  157    * of the underlying <code>TableModel</code>.  For example, the
  158    * selection is always in terms of <code>JTable</code> so that when
  159    * using <code>RowSorter</code> you will need to convert using
  160    * <code>convertRowIndexToView</code> or
  161    * <code>convertRowIndexToModel</code>.  The following shows how to
  162    * convert coordinates from <code>JTable</code> to that of the
  163    * underlying model:
  164    * <pre>
  165    *   int[] selection = table.getSelectedRows();
  166    *   for (int i = 0; i &lt; selection.length; i++) {
  167    *     selection[i] = table.convertRowIndexToModel(selection[i]);
  168    *   }
  169    *   // selection is now in terms of the underlying TableModel
  170    * </pre>
  171    * <p>
  172    * By default if sorting is enabled <code>JTable</code> will persist the
  173    * selection and variable row heights in terms of the model on
  174    * sorting.  For example if row 0, in terms of the underlying model,
  175    * is currently selected, after the sort row 0, in terms of the
  176    * underlying model will be selected.  Visually the selection may
  177    * change, but in terms of the underlying model it will remain the
  178    * same.  The one exception to that is if the model index is no longer
  179    * visible or was removed.  For example, if row 0 in terms of model
  180    * was filtered out the selection will be empty after the sort.
  181    * <p>
  182    * J2SE 5 adds methods to <code>JTable</code> to provide convenient access to some
  183    * common printing needs. Simple new {@link #print()} methods allow for quick
  184    * and easy addition of printing support to your application. In addition, a new
  185    * {@link #getPrintable} method is available for more advanced printing needs.
  186    * <p>
  187    * As for all <code>JComponent</code> classes, you can use
  188    * {@link InputMap} and {@link ActionMap} to associate an
  189    * {@link Action} object with a {@link KeyStroke} and execute the
  190    * action under specified conditions.
  191    * <p>
  192    * <strong>Warning:</strong> Swing is not thread safe. For more
  193    * information see <a
  194    * href="package-summary.html#threading">Swing's Threading
  195    * Policy</a>.
  196    * <p>
  197    * <strong>Warning:</strong>
  198    * Serialized objects of this class will not be compatible with
  199    * future Swing releases. The current serialization support is
  200    * appropriate for short term storage or RMI between applications running
  201    * the same version of Swing.  As of 1.4, support for long term storage
  202    * of all JavaBeans<sup><font size="-2">TM</font></sup>
  203    * has been added to the <code>java.beans</code> package.
  204    * Please see {@link java.beans.XMLEncoder}.
  205    *
  206    *
  207    * @beaninfo
  208    *   attribute: isContainer false
  209    * description: A component which displays data in a two dimensional grid.
  210    *
  211    * @author Philip Milne
  212    * @author Shannon Hickey (printing support)
  213    * @see javax.swing.table.DefaultTableModel
  214    * @see javax.swing.table.TableRowSorter
  215    */
  216   /* The first versions of the JTable, contained in Swing-0.1 through
  217    * Swing-0.4, were written by Alan Chung.
  218    */
  219   public class JTable extends JComponent implements TableModelListener, Scrollable,
  220       TableColumnModelListener, ListSelectionListener, CellEditorListener,
  221       Accessible, RowSorterListener
  222   {
  223   //
  224   // Static Constants
  225   //
  226   
  227       /**
  228        * @see #getUIClassID
  229        * @see #readObject
  230        */
  231       private static final String uiClassID = "TableUI";
  232   
  233       /** Do not adjust column widths automatically; use a horizontal scrollbar instead. */
  234       public static final int     AUTO_RESIZE_OFF = 0;
  235   
  236       /** When a column is adjusted in the UI, adjust the next column the opposite way. */
  237       public static final int     AUTO_RESIZE_NEXT_COLUMN = 1;
  238   
  239       /** During UI adjustment, change subsequent columns to preserve the total width;
  240         * this is the default behavior. */
  241       public static final int     AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
  242   
  243       /** During all resize operations, apply adjustments to the last column only. */
  244       public static final int     AUTO_RESIZE_LAST_COLUMN = 3;
  245   
  246       /** During all resize operations, proportionately resize all columns. */
  247       public static final int     AUTO_RESIZE_ALL_COLUMNS = 4;
  248   
  249   
  250       /**
  251        * Printing modes, used in printing <code>JTable</code>s.
  252        *
  253        * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
  254        *             boolean, PrintRequestAttributeSet, boolean)
  255        * @see #getPrintable
  256        * @since 1.5
  257        */
  258       public enum PrintMode {
  259   
  260           /**
  261            * Printing mode that prints the table at its current size,
  262            * spreading both columns and rows across multiple pages if necessary.
  263            */
  264           NORMAL,
  265   
  266           /**
  267            * Printing mode that scales the output smaller, if necessary,
  268            * to fit the table's entire width (and thereby all columns) on each page;
  269            * Rows are spread across multiple pages as necessary.
  270            */
  271           FIT_WIDTH
  272       }
  273   
  274   
  275   //
  276   // Instance Variables
  277   //
  278   
  279       /** The <code>TableModel</code> of the table. */
  280       protected TableModel        dataModel;
  281   
  282       /** The <code>TableColumnModel</code> of the table. */
  283       protected TableColumnModel  columnModel;
  284   
  285       /** The <code>ListSelectionModel</code> of the table, used to keep track of row selections. */
  286       protected ListSelectionModel selectionModel;
  287   
  288       /** The <code>TableHeader</code> working with the table. */
  289       protected JTableHeader      tableHeader;
  290   
  291       /** The height in pixels of each row in the table. */
  292       protected int               rowHeight;
  293   
  294       /** The height in pixels of the margin between the cells in each row. */
  295       protected int               rowMargin;
  296   
  297       /** The color of the grid. */
  298       protected Color             gridColor;
  299   
  300       /** The table draws horizontal lines between cells if <code>showHorizontalLines</code> is true. */
  301       protected boolean           showHorizontalLines;
  302   
  303       /** The table draws vertical lines between cells if <code>showVerticalLines</code> is true. */
  304       protected boolean           showVerticalLines;
  305   
  306       /**
  307        *  Determines if the table automatically resizes the
  308        *  width of the table's columns to take up the entire width of the
  309        *  table, and how it does the resizing.
  310        */
  311       protected int               autoResizeMode;
  312   
  313       /**
  314        *  The table will query the <code>TableModel</code> to build the default
  315        *  set of columns if this is true.
  316        */
  317       protected boolean           autoCreateColumnsFromModel;
  318   
  319       /** Used by the <code>Scrollable</code> interface to determine the initial visible area. */
  320       protected Dimension         preferredViewportSize;
  321   
  322       /** True if row selection is allowed in this table. */
  323       protected boolean           rowSelectionAllowed;
  324   
  325       /**
  326        * Obsolete as of Java 2 platform v1.3.  Please use the
  327        * <code>rowSelectionAllowed</code> property and the
  328        * <code>columnSelectionAllowed</code> property of the
  329        * <code>columnModel</code> instead. Or use the
  330        * method <code>getCellSelectionEnabled</code>.
  331        */
  332       /*
  333        * If true, both a row selection and a column selection
  334        * can be non-empty at the same time, the selected cells are the
  335        * the cells whose row and column are both selected.
  336        */
  337       protected boolean           cellSelectionEnabled;
  338   
  339       /** If editing, the <code>Component</code> that is handling the editing. */
  340       transient protected Component       editorComp;
  341   
  342       /**
  343        * The active cell editor object, that overwrites the screen real estate
  344        * occupied by the current cell and allows the user to change its contents.
  345        * {@code null} if the table isn't currently editing.
  346        */
  347       transient protected TableCellEditor cellEditor;
  348   
  349       /** Identifies the column of the cell being edited. */
  350       transient protected int             editingColumn;
  351   
  352       /** Identifies the row of the cell being edited. */
  353       transient protected int             editingRow;
  354   
  355       /**
  356        * A table of objects that display the contents of a cell,
  357        * indexed by class as declared in <code>getColumnClass</code>
  358        * in the <code>TableModel</code> interface.
  359        */
  360       transient protected Hashtable defaultRenderersByColumnClass;
  361   
  362       /**
  363        * A table of objects that display and edit the contents of a cell,
  364        * indexed by class as declared in <code>getColumnClass</code>
  365        * in the <code>TableModel</code> interface.
  366        */
  367       transient protected Hashtable defaultEditorsByColumnClass;
  368   
  369       /** The foreground color of selected cells. */
  370       protected Color selectionForeground;
  371   
  372       /** The background color of selected cells. */
  373       protected Color selectionBackground;
  374   
  375   //
  376   // Private state
  377   //
  378   
  379       // WARNING: If you directly access this field you should also change the
  380       // SortManager.modelRowSizes field as well.
  381       private SizeSequence rowModel;
  382       private boolean dragEnabled;
  383       private boolean surrendersFocusOnKeystroke;
  384       private PropertyChangeListener editorRemover = null;
  385       /**
  386        * The last value of getValueIsAdjusting from the column selection models
  387        * columnSelectionChanged notification. Used to test if a repaint is
  388        * needed.
  389        */
  390       private boolean columnSelectionAdjusting;
  391       /**
  392        * The last value of getValueIsAdjusting from the row selection models
  393        * valueChanged notification. Used to test if a repaint is needed.
  394        */
  395       private boolean rowSelectionAdjusting;
  396   
  397       /**
  398        * To communicate errors between threads during printing.
  399        */
  400       private Throwable printError;
  401   
  402       /**
  403        * True when setRowHeight(int) has been invoked.
  404        */
  405       private boolean isRowHeightSet;
  406   
  407       /**
  408        * If true, on a sort the selection is reset.
  409        */
  410       private boolean updateSelectionOnSort;
  411   
  412       /**
  413        * Information used in sorting.
  414        */
  415       private transient SortManager sortManager;
  416   
  417       /**
  418        * If true, when sorterChanged is invoked it's value is ignored.
  419        */
  420       private boolean ignoreSortChange;
  421   
  422       /**
  423        * Whether or not sorterChanged has been invoked.
  424        */
  425       private boolean sorterChanged;
  426   
  427       /**
  428        * If true, any time the model changes a new RowSorter is set.
  429        */
  430       private boolean autoCreateRowSorter;
  431   
  432       /**
  433        * Whether or not the table always fills the viewport height.
  434        * @see #setFillsViewportHeight
  435        * @see #getScrollableTracksViewportHeight
  436        */
  437       private boolean fillsViewportHeight;
  438   
  439       /**
  440        * The drop mode for this component.
  441        */
  442       private DropMode dropMode = DropMode.USE_SELECTION;
  443   
  444       /**
  445        * The drop location.
  446        */
  447       private transient DropLocation dropLocation;
  448   
  449       /**
  450        * A subclass of <code>TransferHandler.DropLocation</code> representing
  451        * a drop location for a <code>JTable</code>.
  452        *
  453        * @see #getDropLocation
  454        * @since 1.6
  455        */
  456       public static final class DropLocation extends TransferHandler.DropLocation {
  457           private final int row;
  458           private final int col;
  459           private final boolean isInsertRow;
  460           private final boolean isInsertCol;
  461   
  462           private DropLocation(Point p, int row, int col,
  463                                boolean isInsertRow, boolean isInsertCol) {
  464   
  465               super(p);
  466               this.row = row;
  467               this.col = col;
  468               this.isInsertRow = isInsertRow;
  469               this.isInsertCol = isInsertCol;
  470           }
  471   
  472           /**
  473            * Returns the row index where a dropped item should be placed in the
  474            * table. Interpretation of the value depends on the return of
  475            * <code>isInsertRow()</code>. If that method returns
  476            * <code>true</code> this value indicates the index where a new
  477            * row should be inserted. Otherwise, it represents the value
  478            * of an existing row on which the data was dropped. This index is
  479            * in terms of the view.
  480            * <p>
  481            * <code>-1</code> indicates that the drop occurred over empty space,
  482            * and no row could be calculated.
  483            *
  484            * @return the drop row
  485            */
  486           public int getRow() {
  487               return row;
  488           }
  489   
  490           /**
  491            * Returns the column index where a dropped item should be placed in the
  492            * table. Interpretation of the value depends on the return of
  493            * <code>isInsertColumn()</code>. If that method returns
  494            * <code>true</code> this value indicates the index where a new
  495            * column should be inserted. Otherwise, it represents the value
  496            * of an existing column on which the data was dropped. This index is
  497            * in terms of the view.
  498            * <p>
  499            * <code>-1</code> indicates that the drop occurred over empty space,
  500            * and no column could be calculated.
  501            *
  502            * @return the drop row
  503            */
  504           public int getColumn() {
  505               return col;
  506           }
  507   
  508           /**
  509            * Returns whether or not this location represents an insert
  510            * of a row.
  511            *
  512            * @return whether or not this is an insert row
  513            */
  514           public boolean isInsertRow() {
  515               return isInsertRow;
  516           }
  517   
  518           /**
  519            * Returns whether or not this location represents an insert
  520            * of a column.
  521            *
  522            * @return whether or not this is an insert column
  523            */
  524           public boolean isInsertColumn() {
  525               return isInsertCol;
  526           }
  527   
  528           /**
  529            * Returns a string representation of this drop location.
  530            * This method is intended to be used for debugging purposes,
  531            * and the content and format of the returned string may vary
  532            * between implementations.
  533            *
  534            * @return a string representation of this drop location
  535            */
  536           public String toString() {
  537               return getClass().getName()
  538                      + "[dropPoint=" + getDropPoint() + ","
  539                      + "row=" + row + ","
  540                      + "column=" + col + ","
  541                      + "insertRow=" + isInsertRow + ","
  542                      + "insertColumn=" + isInsertCol + "]";
  543           }
  544       }
  545   
  546   //
  547   // Constructors
  548   //
  549   
  550       /**
  551        * Constructs a default <code>JTable</code> that is initialized with a default
  552        * data model, a default column model, and a default selection
  553        * model.
  554        *
  555        * @see #createDefaultDataModel
  556        * @see #createDefaultColumnModel
  557        * @see #createDefaultSelectionModel
  558        */
  559       public JTable() {
  560           this(null, null, null);
  561       }
  562   
  563       /**
  564        * Constructs a <code>JTable</code> that is initialized with
  565        * <code>dm</code> as the data model, a default column model,
  566        * and a default selection model.
  567        *
  568        * @param dm        the data model for the table
  569        * @see #createDefaultColumnModel
  570        * @see #createDefaultSelectionModel
  571        */
  572       public JTable(TableModel dm) {
  573           this(dm, null, null);
  574       }
  575   
  576       /**
  577        * Constructs a <code>JTable</code> that is initialized with
  578        * <code>dm</code> as the data model, <code>cm</code>
  579        * as the column model, and a default selection model.
  580        *
  581        * @param dm        the data model for the table
  582        * @param cm        the column model for the table
  583        * @see #createDefaultSelectionModel
  584        */
  585       public JTable(TableModel dm, TableColumnModel cm) {
  586           this(dm, cm, null);
  587       }
  588   
  589       /**
  590        * Constructs a <code>JTable</code> that is initialized with
  591        * <code>dm</code> as the data model, <code>cm</code> as the
  592        * column model, and <code>sm</code> as the selection model.
  593        * If any of the parameters are <code>null</code> this method
  594        * will initialize the table with the corresponding default model.
  595        * The <code>autoCreateColumnsFromModel</code> flag is set to false
  596        * if <code>cm</code> is non-null, otherwise it is set to true
  597        * and the column model is populated with suitable
  598        * <code>TableColumns</code> for the columns in <code>dm</code>.
  599        *
  600        * @param dm        the data model for the table
  601        * @param cm        the column model for the table
  602        * @param sm        the row selection model for the table
  603        * @see #createDefaultDataModel
  604        * @see #createDefaultColumnModel
  605        * @see #createDefaultSelectionModel
  606        */
  607       public JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
  608           super();
  609           setLayout(null);
  610   
  611           setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
  612                              JComponent.getManagingFocusForwardTraversalKeys());
  613           setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
  614                              JComponent.getManagingFocusBackwardTraversalKeys());
  615           if (cm == null) {
  616               cm = createDefaultColumnModel();
  617               autoCreateColumnsFromModel = true;
  618           }
  619           setColumnModel(cm);
  620   
  621           if (sm == null) {
  622               sm = createDefaultSelectionModel();
  623           }
  624           setSelectionModel(sm);
  625   
  626       // Set the model last, that way if the autoCreatColumnsFromModel has
  627       // been set above, we will automatically populate an empty columnModel
  628       // with suitable columns for the new model.
  629           if (dm == null) {
  630               dm = createDefaultDataModel();
  631           }
  632           setModel(dm);
  633   
  634           initializeLocalVars();
  635           updateUI();
  636       }
  637   
  638       /**
  639        * Constructs a <code>JTable</code> with <code>numRows</code>
  640        * and <code>numColumns</code> of empty cells using
  641        * <code>DefaultTableModel</code>.  The columns will have
  642        * names of the form "A", "B", "C", etc.
  643        *
  644        * @param numRows           the number of rows the table holds
  645        * @param numColumns        the number of columns the table holds
  646        * @see javax.swing.table.DefaultTableModel
  647        */
  648       public JTable(int numRows, int numColumns) {
  649           this(new DefaultTableModel(numRows, numColumns));
  650       }
  651   
  652       /**
  653        * Constructs a <code>JTable</code> to display the values in the
  654        * <code>Vector</code> of <code>Vectors</code>, <code>rowData</code>,
  655        * with column names, <code>columnNames</code>.  The
  656        * <code>Vectors</code> contained in <code>rowData</code>
  657        * should contain the values for that row. In other words,
  658        * the value of the cell at row 1, column 5 can be obtained
  659        * with the following code:
  660        * <p>
  661        * <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
  662        * <p>
  663        * @param rowData           the data for the new table
  664        * @param columnNames       names of each column
  665        */
  666       public JTable(Vector rowData, Vector columnNames) {
  667           this(new DefaultTableModel(rowData, columnNames));
  668       }
  669   
  670       /**
  671        * Constructs a <code>JTable</code> to display the values in the two dimensional array,
  672        * <code>rowData</code>, with column names, <code>columnNames</code>.
  673        * <code>rowData</code> is an array of rows, so the value of the cell at row 1,
  674        * column 5 can be obtained with the following code:
  675        * <p>
  676        * <pre> rowData[1][5]; </pre>
  677        * <p>
  678        * All rows must be of the same length as <code>columnNames</code>.
  679        * <p>
  680        * @param rowData           the data for the new table
  681        * @param columnNames       names of each column
  682        */
  683       public JTable(final Object[][] rowData, final Object[] columnNames) {
  684           this(new AbstractTableModel() {
  685               public String getColumnName(int column) { return columnNames[column].toString(); }
  686               public int getRowCount() { return rowData.length; }
  687               public int getColumnCount() { return columnNames.length; }
  688               public Object getValueAt(int row, int col) { return rowData[row][col]; }
  689               public boolean isCellEditable(int row, int column) { return true; }
  690               public void setValueAt(Object value, int row, int col) {
  691                   rowData[row][col] = value;
  692                   fireTableCellUpdated(row, col);
  693               }
  694           });
  695       }
  696   
  697       /**
  698        * Calls the <code>configureEnclosingScrollPane</code> method.
  699        *
  700        * @see #configureEnclosingScrollPane
  701        */
  702       public void addNotify() {
  703           super.addNotify();
  704           configureEnclosingScrollPane();
  705       }
  706   
  707       /**
  708        * If this <code>JTable</code> is the <code>viewportView</code> of an enclosing <code>JScrollPane</code>
  709        * (the usual situation), configure this <code>ScrollPane</code> by, amongst other things,
  710        * installing the table's <code>tableHeader</code> as the <code>columnHeaderView</code> of the scroll pane.
  711        * When a <code>JTable</code> is added to a <code>JScrollPane</code> in the usual way,
  712        * using <code>new JScrollPane(myTable)</code>, <code>addNotify</code> is
  713        * called in the <code>JTable</code> (when the table is added to the viewport).
  714        * <code>JTable</code>'s <code>addNotify</code> method in turn calls this method,
  715        * which is protected so that this default installation procedure can
  716        * be overridden by a subclass.
  717        *
  718        * @see #addNotify
  719        */
  720       protected void configureEnclosingScrollPane() {
  721           Container p = getParent();
  722           if (p instanceof JViewport) {
  723               Container gp = p.getParent();
  724               if (gp instanceof JScrollPane) {
  725                   JScrollPane scrollPane = (JScrollPane)gp;
  726                   // Make certain we are the viewPort's view and not, for
  727                   // example, the rowHeaderView of the scrollPane -
  728                   // an implementor of fixed columns might do this.
  729                   JViewport viewport = scrollPane.getViewport();
  730                   if (viewport == null || viewport.getView() != this) {
  731                       return;
  732                   }
  733                   scrollPane.setColumnHeaderView(getTableHeader());
  734                   //  scrollPane.getViewport().setBackingStoreEnabled(true);
  735                   Border border = scrollPane.getBorder();
  736                   if (border == null || border instanceof UIResource) {
  737                       Border scrollPaneBorder =
  738                           UIManager.getBorder("Table.scrollPaneBorder");
  739                       if (scrollPaneBorder != null) {
  740                           scrollPane.setBorder(scrollPaneBorder);
  741                       }
  742                   }
  743               }
  744           }
  745       }
  746   
  747       /**
  748        * Calls the <code>unconfigureEnclosingScrollPane</code> method.
  749        *
  750        * @see #unconfigureEnclosingScrollPane
  751        */
  752       public void removeNotify() {
  753           KeyboardFocusManager.getCurrentKeyboardFocusManager().
  754               removePropertyChangeListener("permanentFocusOwner", editorRemover);
  755           editorRemover = null;
  756           unconfigureEnclosingScrollPane();
  757           super.removeNotify();
  758       }
  759   
  760       /**
  761        * Reverses the effect of <code>configureEnclosingScrollPane</code>
  762        * by replacing the <code>columnHeaderView</code> of the enclosing
  763        * scroll pane with <code>null</code>. <code>JTable</code>'s
  764        * <code>removeNotify</code> method calls
  765        * this method, which is protected so that this default uninstallation
  766        * procedure can be overridden by a subclass.
  767        *
  768        * @see #removeNotify
  769        * @see #configureEnclosingScrollPane
  770        * @since 1.3
  771        */
  772       protected void unconfigureEnclosingScrollPane() {
  773           Container p = getParent();
  774           if (p instanceof JViewport) {
  775               Container gp = p.getParent();
  776               if (gp instanceof JScrollPane) {
  777                   JScrollPane scrollPane = (JScrollPane)gp;
  778                   // Make certain we are the viewPort's view and not, for
  779                   // example, the rowHeaderView of the scrollPane -
  780                   // an implementor of fixed columns might do this.
  781                   JViewport viewport = scrollPane.getViewport();
  782                   if (viewport == null || viewport.getView() != this) {
  783                       return;
  784                   }
  785                   scrollPane.setColumnHeaderView(null);
  786               }
  787           }
  788       }
  789   
  790       void setUIProperty(String propertyName, Object value) {
  791           if (propertyName == "rowHeight") {
  792               if (!isRowHeightSet) {
  793                   setRowHeight(((Number)value).intValue());
  794                   isRowHeightSet = false;
  795               }
  796               return;
  797           }
  798           super.setUIProperty(propertyName, value);
  799       }
  800   
  801   //
  802   // Static Methods
  803   //
  804   
  805       /**
  806        * Equivalent to <code>new JScrollPane(aTable)</code>.
  807        *
  808        * @deprecated As of Swing version 1.0.2,
  809        * replaced by <code>new JScrollPane(aTable)</code>.
  810        */
  811       @Deprecated
  812       static public JScrollPane createScrollPaneForTable(JTable aTable) {
  813           return new JScrollPane(aTable);
  814       }
  815   
  816   //
  817   // Table Attributes
  818   //
  819   
  820       /**
  821        * Sets the <code>tableHeader</code> working with this <code>JTable</code> to <code>newHeader</code>.
  822        * It is legal to have a <code>null</code> <code>tableHeader</code>.
  823        *
  824        * @param   tableHeader                       new tableHeader
  825        * @see     #getTableHeader
  826        * @beaninfo
  827        *  bound: true
  828        *  description: The JTableHeader instance which renders the column headers.
  829        */
  830       public void setTableHeader(JTableHeader tableHeader) {
  831           if (this.tableHeader != tableHeader) {
  832               JTableHeader old = this.tableHeader;
  833               // Release the old header
  834               if (old != null) {
  835                   old.setTable(null);
  836               }
  837               this.tableHeader = tableHeader;
  838               if (tableHeader != null) {
  839                   tableHeader.setTable(this);
  840               }
  841               firePropertyChange("tableHeader", old, tableHeader);
  842           }
  843       }
  844   
  845       /**
  846        * Returns the <code>tableHeader</code> used by this <code>JTable</code>.
  847        *
  848        * @return  the <code>tableHeader</code> used by this table
  849        * @see     #setTableHeader
  850        */
  851       public JTableHeader getTableHeader() {
  852           return tableHeader;
  853       }
  854   
  855       /**
  856        * Sets the height, in pixels, of all cells to <code>rowHeight</code>,
  857        * revalidates, and repaints.
  858        * The height of the cells will be equal to the row height minus
  859        * the row margin.
  860        *
  861        * @param   rowHeight                       new row height
  862        * @exception IllegalArgumentException      if <code>rowHeight</code> is
  863        *                                          less than 1
  864        * @see     #getRowHeight
  865        * @beaninfo
  866        *  bound: true
  867        *  description: The height of the specified row.
  868        */
  869       public void setRowHeight(int rowHeight) {
  870           if (rowHeight <= 0) {
  871               throw new IllegalArgumentException("New row height less than 1");
  872           }
  873           int old = this.rowHeight;
  874           this.rowHeight = rowHeight;
  875           rowModel = null;
  876           if (sortManager != null) {
  877               sortManager.modelRowSizes = null;
  878           }
  879           isRowHeightSet = true;
  880           resizeAndRepaint();
  881           firePropertyChange("rowHeight", old, rowHeight);
  882       }
  883   
  884       /**
  885        * Returns the height of a table row, in pixels.
  886        * The default row height is 16.0.
  887        *
  888        * @return  the height in pixels of a table row
  889        * @see     #setRowHeight
  890        */
  891       public int getRowHeight() {
  892           return rowHeight;
  893       }
  894   
  895       private SizeSequence getRowModel() {
  896           if (rowModel == null) {
  897               rowModel = new SizeSequence(getRowCount(), getRowHeight());
  898           }
  899           return rowModel;
  900       }
  901   
  902       /**
  903        * Sets the height for <code>row</code> to <code>rowHeight</code>,
  904        * revalidates, and repaints. The height of the cells in this row
  905        * will be equal to the row height minus the row margin.
  906        *
  907        * @param   row                             the row whose height is being
  908                                                   changed
  909        * @param   rowHeight                       new row height, in pixels
  910        * @exception IllegalArgumentException      if <code>rowHeight</code> is
  911        *                                          less than 1
  912        * @beaninfo
  913        *  bound: true
  914        *  description: The height in pixels of the cells in <code>row</code>
  915        * @since 1.3
  916        */
  917       public void setRowHeight(int row, int rowHeight) {
  918           if (rowHeight <= 0) {
  919               throw new IllegalArgumentException("New row height less than 1");
  920           }
  921           getRowModel().setSize(row, rowHeight);
  922           if (sortManager != null) {
  923               sortManager.setViewRowHeight(row, rowHeight);
  924           }
  925           resizeAndRepaint();
  926       }
  927   
  928       /**
  929        * Returns the height, in pixels, of the cells in <code>row</code>.
  930        * @param   row              the row whose height is to be returned
  931        * @return the height, in pixels, of the cells in the row
  932        * @since 1.3
  933        */
  934       public int getRowHeight(int row) {
  935           return (rowModel == null) ? getRowHeight() : rowModel.getSize(row);
  936       }
  937   
  938       /**
  939        * Sets the amount of empty space between cells in adjacent rows.
  940        *
  941        * @param  rowMargin  the number of pixels between cells in a row
  942        * @see     #getRowMargin
  943        * @beaninfo
  944        *  bound: true
  945        *  description: The amount of space between cells.
  946        */
  947       public void setRowMargin(int rowMargin) {
  948           int old = this.rowMargin;
  949           this.rowMargin = rowMargin;
  950           resizeAndRepaint();
  951           firePropertyChange("rowMargin", old, rowMargin);
  952       }
  953   
  954       /**
  955        * Gets the amount of empty space, in pixels, between cells. Equivalent to:
  956        * <code>getIntercellSpacing().height</code>.
  957        * @return the number of pixels between cells in a row
  958        *
  959        * @see     #setRowMargin
  960        */
  961       public int getRowMargin() {
  962           return rowMargin;
  963       }
  964   
  965       /**
  966        * Sets the <code>rowMargin</code> and the <code>columnMargin</code> --
  967        * the height and width of the space between cells -- to
  968        * <code>intercellSpacing</code>.
  969        *
  970        * @param   intercellSpacing        a <code>Dimension</code>
  971        *                                  specifying the new width
  972        *                                  and height between cells
  973        * @see     #getIntercellSpacing
  974        * @beaninfo
  975        *  description: The spacing between the cells,
  976        *               drawn in the background color of the JTable.
  977        */
  978       public void setIntercellSpacing(Dimension intercellSpacing) {
  979           // Set the rowMargin here and columnMargin in the TableColumnModel
  980           setRowMargin(intercellSpacing.height);
  981           getColumnModel().setColumnMargin(intercellSpacing.width);
  982   
  983           resizeAndRepaint();
  984       }
  985   
  986       /**
  987        * Returns the horizontal and vertical space between cells.
  988        * The default spacing is (1, 1), which provides room to draw the grid.
  989        *
  990        * @return  the horizontal and vertical spacing between cells
  991        * @see     #setIntercellSpacing
  992        */
  993       public Dimension getIntercellSpacing() {
  994           return new Dimension(getColumnModel().getColumnMargin(), rowMargin);
  995       }
  996   
  997       /**
  998        * Sets the color used to draw grid lines to <code>gridColor</code> and redisplays.
  999        * The default color is look and feel dependent.
 1000        *
 1001        * @param   gridColor                       the new color of the grid lines
 1002        * @exception IllegalArgumentException      if <code>gridColor</code> is <code>null</code>
 1003        * @see     #getGridColor
 1004        * @beaninfo
 1005        *  bound: true
 1006        *  description: The grid color.
 1007        */
 1008       public void setGridColor(Color gridColor) {
 1009           if (gridColor == null) {
 1010               throw new IllegalArgumentException("New color is null");
 1011           }
 1012           Color old = this.gridColor;
 1013           this.gridColor = gridColor;
 1014           firePropertyChange("gridColor", old, gridColor);
 1015           // Redraw
 1016           repaint();
 1017       }
 1018   
 1019       /**
 1020        * Returns the color used to draw grid lines.
 1021        * The default color is look and feel dependent.
 1022        *
 1023        * @return  the color used to draw grid lines
 1024        * @see     #setGridColor
 1025        */
 1026       public Color getGridColor() {
 1027           return gridColor;
 1028       }
 1029   
 1030       /**
 1031        *  Sets whether the table draws grid lines around cells.
 1032        *  If <code>showGrid</code> is true it does; if it is false it doesn't.
 1033        *  There is no <code>getShowGrid</code> method as this state is held
 1034        *  in two variables -- <code>showHorizontalLines</code> and <code>showVerticalLines</code> --
 1035        *  each of which can be queried independently.
 1036        *
 1037        * @param   showGrid                 true if table view should draw grid lines
 1038        *
 1039        * @see     #setShowVerticalLines
 1040        * @see     #setShowHorizontalLines
 1041        * @beaninfo
 1042        *  description: The color used to draw the grid lines.
 1043        */
 1044       public void setShowGrid(boolean showGrid) {
 1045           setShowHorizontalLines(showGrid);
 1046           setShowVerticalLines(showGrid);
 1047   
 1048           // Redraw
 1049           repaint();
 1050       }
 1051   
 1052       /**
 1053        *  Sets whether the table draws horizontal lines between cells.
 1054        *  If <code>showHorizontalLines</code> is true it does; if it is false it doesn't.
 1055        *
 1056        * @param   showHorizontalLines      true if table view should draw horizontal lines
 1057        * @see     #getShowHorizontalLines
 1058        * @see     #setShowGrid
 1059        * @see     #setShowVerticalLines
 1060        * @beaninfo
 1061        *  bound: true
 1062        *  description: Whether horizontal lines should be drawn in between the cells.
 1063        */
 1064       public void setShowHorizontalLines(boolean showHorizontalLines) {
 1065           boolean old = this.showHorizontalLines;
 1066           this.showHorizontalLines = showHorizontalLines;
 1067           firePropertyChange("showHorizontalLines", old, showHorizontalLines);
 1068   
 1069           // Redraw
 1070           repaint();
 1071       }
 1072   
 1073       /**
 1074        *  Sets whether the table draws vertical lines between cells.
 1075        *  If <code>showVerticalLines</code> is true it does; if it is false it doesn't.
 1076        *
 1077        * @param   showVerticalLines              true if table view should draw vertical lines
 1078        * @see     #getShowVerticalLines
 1079        * @see     #setShowGrid
 1080        * @see     #setShowHorizontalLines
 1081        * @beaninfo
 1082        *  bound: true
 1083        *  description: Whether vertical lines should be drawn in between the cells.
 1084        */
 1085       public void setShowVerticalLines(boolean showVerticalLines) {
 1086           boolean old = this.showVerticalLines;
 1087           this.showVerticalLines = showVerticalLines;
 1088           firePropertyChange("showVerticalLines", old, showVerticalLines);
 1089           // Redraw
 1090           repaint();
 1091       }
 1092   
 1093       /**
 1094        * Returns true if the table draws horizontal lines between cells, false if it
 1095        * doesn't. The default is true.
 1096        *
 1097        * @return  true if the table draws horizontal lines between cells, false if it
 1098        *          doesn't
 1099        * @see     #setShowHorizontalLines
 1100        */
 1101       public boolean getShowHorizontalLines() {
 1102           return showHorizontalLines;
 1103       }
 1104   
 1105       /**
 1106        * Returns true if the table draws vertical lines between cells, false if it
 1107        * doesn't. The default is true.
 1108        *
 1109        * @return  true if the table draws vertical lines between cells, false if it
 1110        *          doesn't
 1111        * @see     #setShowVerticalLines
 1112        */
 1113       public boolean getShowVerticalLines() {
 1114           return showVerticalLines;
 1115       }
 1116   
 1117       /**
 1118        * Sets the table's auto resize mode when the table is resized.  For further
 1119        * information on how the different resize modes work, see
 1120        * {@link #doLayout}.
 1121        *
 1122        * @param   mode One of 5 legal values:
 1123        *                   AUTO_RESIZE_OFF,
 1124        *                   AUTO_RESIZE_NEXT_COLUMN,
 1125        *                   AUTO_RESIZE_SUBSEQUENT_COLUMNS,
 1126        *                   AUTO_RESIZE_LAST_COLUMN,
 1127        *                   AUTO_RESIZE_ALL_COLUMNS
 1128        *
 1129        * @see     #getAutoResizeMode
 1130        * @see     #doLayout
 1131        * @beaninfo
 1132        *  bound: true
 1133        *  description: Whether the columns should adjust themselves automatically.
 1134        *        enum: AUTO_RESIZE_OFF                JTable.AUTO_RESIZE_OFF
 1135        *              AUTO_RESIZE_NEXT_COLUMN        JTable.AUTO_RESIZE_NEXT_COLUMN
 1136        *              AUTO_RESIZE_SUBSEQUENT_COLUMNS JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS
 1137        *              AUTO_RESIZE_LAST_COLUMN        JTable.AUTO_RESIZE_LAST_COLUMN
 1138        *              AUTO_RESIZE_ALL_COLUMNS        JTable.AUTO_RESIZE_ALL_COLUMNS
 1139        */
 1140       public void setAutoResizeMode(int mode) {
 1141           if ((mode == AUTO_RESIZE_OFF) ||
 1142               (mode == AUTO_RESIZE_NEXT_COLUMN) ||
 1143               (mode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) ||
 1144               (mode == AUTO_RESIZE_LAST_COLUMN) ||
 1145               (mode == AUTO_RESIZE_ALL_COLUMNS)) {
 1146               int old = autoResizeMode;
 1147               autoResizeMode = mode;
 1148               resizeAndRepaint();
 1149               if (tableHeader != null) {
 1150                   tableHeader.resizeAndRepaint();
 1151               }
 1152               firePropertyChange("autoResizeMode", old, autoResizeMode);
 1153           }
 1154       }
 1155   
 1156       /**
 1157        * Returns the auto resize mode of the table.  The default mode
 1158        * is AUTO_RESIZE_SUBSEQUENT_COLUMNS.
 1159        *
 1160        * @return  the autoResizeMode of the table
 1161        *
 1162        * @see     #setAutoResizeMode
 1163        * @see     #doLayout
 1164        */
 1165       public int getAutoResizeMode() {
 1166           return autoResizeMode;
 1167       }
 1168   
 1169       /**
 1170        * Sets this table's <code>autoCreateColumnsFromModel</code> flag.
 1171        * This method calls <code>createDefaultColumnsFromModel</code> if
 1172        * <code>autoCreateColumnsFromModel</code> changes from false to true.
 1173        *
 1174        * @param   autoCreateColumnsFromModel   true if <code>JTable</code> should automatically create columns
 1175        * @see     #getAutoCreateColumnsFromModel
 1176        * @see     #createDefaultColumnsFromModel
 1177        * @beaninfo
 1178        *  bound: true
 1179        *  description: Automatically populates the columnModel when a new TableModel is submitted.
 1180        */
 1181       public void setAutoCreateColumnsFromModel(boolean autoCreateColumnsFromModel) {
 1182           if (this.autoCreateColumnsFromModel != autoCreateColumnsFromModel) {
 1183               boolean old = this.autoCreateColumnsFromModel;
 1184               this.autoCreateColumnsFromModel = autoCreateColumnsFromModel;
 1185               if (autoCreateColumnsFromModel) {
 1186                   createDefaultColumnsFromModel();
 1187               }
 1188               firePropertyChange("autoCreateColumnsFromModel", old, autoCreateColumnsFromModel);
 1189           }
 1190       }
 1191   
 1192       /**
 1193        * Determines whether the table will create default columns from the model.
 1194        * If true, <code>setModel</code> will clear any existing columns and
 1195        * create new columns from the new model.  Also, if the event in
 1196        * the <code>tableChanged</code> notification specifies that the
 1197        * entire table changed, then the columns will be rebuilt.
 1198        * The default is true.
 1199        *
 1200        * @return  the autoCreateColumnsFromModel of the table
 1201        * @see     #setAutoCreateColumnsFromModel
 1202        * @see     #createDefaultColumnsFromModel
 1203        */
 1204       public boolean getAutoCreateColumnsFromModel() {
 1205           return autoCreateColumnsFromModel;
 1206       }
 1207   
 1208       /**
 1209        * Creates default columns for the table from
 1210        * the data model using the <code>getColumnCount</code> method
 1211        * defined in the <code>TableModel</code> interface.
 1212        * <p>
 1213        * Clears any existing columns before creating the
 1214        * new columns based on information from the model.
 1215        *
 1216        * @see     #getAutoCreateColumnsFromModel
 1217        */
 1218       public void createDefaultColumnsFromModel() {
 1219           TableModel m = getModel();
 1220           if (m != null) {
 1221               // Remove any current columns
 1222               TableColumnModel cm = getColumnModel();
 1223               while (cm.getColumnCount() > 0) {
 1224                   cm.removeColumn(cm.getColumn(0));
 1225               }
 1226   
 1227               // Create new columns from the data model info
 1228               for (int i = 0; i < m.getColumnCount(); i++) {
 1229                   TableColumn newColumn = new TableColumn(i);
 1230                   addColumn(newColumn);
 1231               }
 1232           }
 1233       }
 1234   
 1235       /**
 1236        * Sets a default cell renderer to be used if no renderer has been set in
 1237        * a <code>TableColumn</code>. If renderer is <code>null</code>,
 1238        * removes the default renderer for this column class.
 1239        *
 1240        * @param  columnClass     set the default cell renderer for this columnClass
 1241        * @param  renderer        default cell renderer to be used for this
 1242        *                         columnClass
 1243        * @see     #getDefaultRenderer
 1244        * @see     #setDefaultEditor
 1245        */
 1246       public void setDefaultRenderer(Class<?> columnClass, TableCellRenderer renderer) {
 1247           if (renderer != null) {
 1248               defaultRenderersByColumnClass.put(columnClass, renderer);
 1249           }
 1250           else {
 1251               defaultRenderersByColumnClass.remove(columnClass);
 1252           }
 1253       }
 1254   
 1255       /**
 1256        * Returns the cell renderer to be used when no renderer has been set in
 1257        * a <code>TableColumn</code>. During the rendering of cells the renderer is fetched from
 1258        * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
 1259        * there is no entry for this <code>columnClass</code> the method returns
 1260        * the entry for the most specific superclass. The <code>JTable</code> installs entries
 1261        * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
 1262        * or replaced.
 1263        *
 1264        * @param   columnClass   return the default cell renderer
 1265        *                        for this columnClass
 1266        * @return  the renderer for this columnClass
 1267        * @see     #setDefaultRenderer
 1268        * @see     #getColumnClass
 1269        */
 1270       public TableCellRenderer getDefaultRenderer(Class<?> columnClass) {
 1271           if (columnClass == null) {
 1272               return null;
 1273           }
 1274           else {
 1275               Object renderer = defaultRenderersByColumnClass.get(columnClass);
 1276               if (renderer != null) {
 1277                   return (TableCellRenderer)renderer;
 1278               }
 1279               else {
 1280                   return getDefaultRenderer(columnClass.getSuperclass());
 1281               }
 1282           }
 1283       }
 1284   
 1285       /**
 1286        * Sets a default cell editor to be used if no editor has been set in
 1287        * a <code>TableColumn</code>. If no editing is required in a table, or a
 1288        * particular column in a table, uses the <code>isCellEditable</code>
 1289        * method in the <code>TableModel</code> interface to ensure that this
 1290        * <code>JTable</code> will not start an editor in these columns.
 1291        * If editor is <code>null</code>, removes the default editor for this
 1292        * column class.
 1293        *
 1294        * @param  columnClass  set the default cell editor for this columnClass
 1295        * @param  editor   default cell editor to be used for this columnClass
 1296        * @see     TableModel#isCellEditable
 1297        * @see     #getDefaultEditor
 1298        * @see     #setDefaultRenderer
 1299        */
 1300       public void setDefaultEditor(Class<?> columnClass, TableCellEditor editor) {
 1301           if (editor != null) {
 1302               defaultEditorsByColumnClass.put(columnClass, editor);
 1303           }
 1304           else {
 1305               defaultEditorsByColumnClass.remove(columnClass);
 1306           }
 1307       }
 1308   
 1309       /**
 1310        * Returns the editor to be used when no editor has been set in
 1311        * a <code>TableColumn</code>. During the editing of cells the editor is fetched from
 1312        * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
 1313        * there is no entry for this <code>columnClass</code> the method returns
 1314        * the entry for the most specific superclass. The <code>JTable</code> installs entries
 1315        * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
 1316        * or replaced.
 1317        *
 1318        * @param   columnClass  return the default cell editor for this columnClass
 1319        * @return the default cell editor to be used for this columnClass
 1320        * @see     #setDefaultEditor
 1321        * @see     #getColumnClass
 1322        */
 1323       public TableCellEditor getDefaultEditor(Class<?> columnClass) {
 1324           if (columnClass == null) {
 1325               return null;
 1326           }
 1327           else {
 1328               Object editor = defaultEditorsByColumnClass.get(columnClass);
 1329               if (editor != null) {
 1330                   return (TableCellEditor)editor;
 1331               }
 1332               else {
 1333                   return getDefaultEditor(columnClass.getSuperclass());
 1334               }
 1335           }
 1336       }
 1337   
 1338       /**
 1339        * Turns on or off automatic drag handling. In order to enable automatic
 1340        * drag handling, this property should be set to {@code true}, and the
 1341        * table's {@code TransferHandler} needs to be {@code non-null}.
 1342        * The default value of the {@code dragEnabled} property is {@code false}.
 1343        * <p>
 1344        * The job of honoring this property, and recognizing a user drag gesture,
 1345        * lies with the look and feel implementation, and in particular, the table's
 1346        * {@code TableUI}. When automatic drag handling is enabled, most look and
 1347        * feels (including those that subclass {@code BasicLookAndFeel}) begin a
 1348        * drag and drop operation whenever the user presses the mouse button over
 1349        * an item (in single selection mode) or a selection (in other selection
 1350        * modes) and then moves the mouse a few pixels. Setting this property to
 1351        * {@code true} can therefore have a subtle effect on how selections behave.
 1352        * <p>
 1353        * If a look and feel is used that ignores this property, you can still
 1354        * begin a drag and drop operation by calling {@code exportAsDrag} on the
 1355        * table's {@code TransferHandler}.
 1356        *
 1357        * @param b whether or not to enable automatic drag handling
 1358        * @exception HeadlessException if
 1359        *            <code>b</code> is <code>true</code> and
 1360        *            <code>GraphicsEnvironment.isHeadless()</code>
 1361        *            returns <code>true</code>
 1362        * @see java.awt.GraphicsEnvironment#isHeadless
 1363        * @see #getDragEnabled
 1364        * @see #setTransferHandler
 1365        * @see TransferHandler
 1366        * @since 1.4
 1367        *
 1368        * @beaninfo
 1369        *  description: determines whether automatic drag handling is enabled
 1370        *        bound: false
 1371        */
 1372       public void setDragEnabled(boolean b) {
 1373           if (b && GraphicsEnvironment.isHeadless()) {
 1374               throw new HeadlessException();
 1375           }
 1376           dragEnabled = b;
 1377       }
 1378   
 1379       /**
 1380        * Returns whether or not automatic drag handling is enabled.
 1381        *
 1382        * @return the value of the {@code dragEnabled} property
 1383        * @see #setDragEnabled
 1384        * @since 1.4
 1385        */
 1386       public boolean getDragEnabled() {
 1387           return dragEnabled;
 1388       }
 1389   
 1390       /**
 1391        * Sets the drop mode for this component. For backward compatibility,
 1392        * the default for this property is <code>DropMode.USE_SELECTION</code>.
 1393        * Usage of one of the other modes is recommended, however, for an
 1394        * improved user experience. <code>DropMode.ON</code>, for instance,
 1395        * offers similar behavior of showing items as selected, but does so without
 1396        * affecting the actual selection in the table.
 1397        * <p>
 1398        * <code>JTable</code> supports the following drop modes:
 1399        * <ul>
 1400        *    <li><code>DropMode.USE_SELECTION</code></li>
 1401        *    <li><code>DropMode.ON</code></li>
 1402        *    <li><code>DropMode.INSERT</code></li>
 1403        *    <li><code>DropMode.INSERT_ROWS</code></li>
 1404        *    <li><code>DropMode.INSERT_COLS</code></li>
 1405        *    <li><code>DropMode.ON_OR_INSERT</code></li>
 1406        *    <li><code>DropMode.ON_OR_INSERT_ROWS</code></li>
 1407        *    <li><code>DropMode.ON_OR_INSERT_COLS</code></li>
 1408        * </ul>
 1409        * <p>
 1410        * The drop mode is only meaningful if this component has a
 1411        * <code>TransferHandler</code> that accepts drops.
 1412        *
 1413        * @param dropMode the drop mode to use
 1414        * @throws IllegalArgumentException if the drop mode is unsupported
 1415        *         or <code>null</code>
 1416        * @see #getDropMode
 1417        * @see #getDropLocation
 1418        * @see #setTransferHandler
 1419        * @see TransferHandler
 1420        * @since 1.6
 1421        */
 1422       public final void setDropMode(DropMode dropMode) {
 1423           if (dropMode != null) {
 1424               switch (dropMode) {
 1425                   case USE_SELECTION:
 1426                   case ON:
 1427                   case INSERT:
 1428                   case INSERT_ROWS:
 1429                   case INSERT_COLS:
 1430                   case ON_OR_INSERT:
 1431                   case ON_OR_INSERT_ROWS:
 1432                   case ON_OR_INSERT_COLS:
 1433                       this.dropMode = dropMode;
 1434                       return;
 1435               }
 1436           }
 1437   
 1438           throw new IllegalArgumentException(dropMode + ": Unsupported drop mode for table");
 1439       }
 1440   
 1441       /**
 1442        * Returns the drop mode for this component.
 1443        *
 1444        * @return the drop mode for this component
 1445        * @see #setDropMode
 1446        * @since 1.6
 1447        */
 1448       public final DropMode getDropMode() {
 1449           return dropMode;
 1450       }
 1451   
 1452       /**
 1453        * Calculates a drop location in this component, representing where a
 1454        * drop at the given point should insert data.
 1455        *
 1456        * @param p the point to calculate a drop location for
 1457        * @return the drop location, or <code>null</code>
 1458        */
 1459       DropLocation dropLocationForPoint(Point p) {
 1460           DropLocation location = null;
 1461   
 1462           int row = rowAtPoint(p);
 1463           int col = columnAtPoint(p);
 1464           boolean outside = Boolean.TRUE == getClientProperty("Table.isFileList")
 1465                             && SwingUtilities2.pointOutsidePrefSize(this, row, col, p);
 1466   
 1467           Rectangle rect = getCellRect(row, col, true);
 1468           Section xSection, ySection;
 1469           boolean between = false;
 1470           boolean ltr = getComponentOrientation().isLeftToRight();
 1471   
 1472           switch(dropMode) {
 1473               case USE_SELECTION:
 1474               case ON:
 1475                   if (row == -1 || col == -1 || outside) {
 1476                       location = new DropLocation(p, -1, -1, false, false);
 1477                   } else {
 1478                       location = new DropLocation(p, row, col, false, false);
 1479                   }
 1480                   break;
 1481               case INSERT:
 1482                   if (row == -1 && col == -1) {
 1483                       location = new DropLocation(p, 0, 0, true, true);
 1484                       break;
 1485                   }
 1486   
 1487                   xSection = SwingUtilities2.liesInHorizontal(rect, p, ltr, true);
 1488   
 1489                   if (row == -1) {
 1490                       if (xSection == LEADING) {
 1491                           location = new DropLocation(p, getRowCount(), col, true, true);
 1492                       } else if (xSection == TRAILING) {
 1493                           location = new DropLocation(p, getRowCount(), col + 1, true, true);
 1494                       } else {
 1495                           location = new DropLocation(p, getRowCount(), col, true, false);
 1496                       }
 1497                   } else if (xSection == LEADING || xSection == TRAILING) {
 1498                       ySection = SwingUtilities2.liesInVertical(rect, p, true);
 1499                       if (ySection == LEADING) {
 1500                           between = true;
 1501                       } else if (ySection == TRAILING) {
 1502                           row++;
 1503                           between = true;
 1504                       }
 1505   
 1506                       location = new DropLocation(p, row,
 1507                                                   xSection == TRAILING ? col + 1 : col,
 1508                                                   between, true);
 1509                   } else {
 1510                       if (SwingUtilities2.liesInVertical(rect, p, false) == TRAILING) {
 1511                           row++;
 1512                       }
 1513   
 1514                       location = new DropLocation(p, row, col, true, false);
 1515                   }
 1516   
 1517                   break;
 1518               case INSERT_ROWS:
 1519                   if (row == -1 && col == -1) {
 1520                       location = new DropLocation(p, -1, -1, false, false);
 1521                       break;
 1522                   }
 1523   
 1524                   if (row == -1) {
 1525                       location = new DropLocation(p, getRowCount(), col, true, false);
 1526                       break;
 1527                   }
 1528   
 1529                   if (SwingUtilities2.liesInVertical(rect, p, false) == TRAILING) {
 1530                       row++;
 1531                   }
 1532   
 1533                   location = new DropLocation(p, row, col, true, false);
 1534                   break;
 1535               case ON_OR_INSERT_ROWS:
 1536                   if (row == -1 && col == -1) {
 1537                       location = new DropLocation(p, -1, -1, false, false);
 1538                       break;
 1539                   }
 1540   
 1541                   if (row == -1) {
 1542                       location = new DropLocation(p, getRowCount(), col, true, false);
 1543                       break;
 1544                   }
 1545   
 1546                   ySection = SwingUtilities2.liesInVertical(rect, p, true);
 1547                   if (ySection == LEADING) {
 1548                       between = true;
 1549                   } else if (ySection == TRAILING) {
 1550                       row++;
 1551                       between = true;
 1552                   }
 1553   
 1554                   location = new DropLocation(p, row, col, between, false);
 1555                   break;
 1556               case INSERT_COLS:
 1557                   if (row == -1) {
 1558                       location = new DropLocation(p, -1, -1, false, false);
 1559                       break;
 1560                   }
 1561   
 1562                   if (col == -1) {
 1563                       location = new DropLocation(p, getColumnCount(), col, false, true);
 1564                       break;
 1565                   }
 1566   
 1567                   if (SwingUtilities2.liesInHorizontal(rect, p, ltr, false) == TRAILING) {
 1568                       col++;
 1569                   }
 1570   
 1571                   location = new DropLocation(p, row, col, false, true);
 1572                   break;
 1573               case ON_OR_INSERT_COLS:
 1574                   if (row == -1) {
 1575                       location = new DropLocation(p, -1, -1, false, false);
 1576                       break;
 1577                   }
 1578   
 1579                   if (col == -1) {
 1580                       location = new DropLocation(p, row, getColumnCount(), false, true);
 1581                       break;
 1582                   }
 1583   
 1584                   xSection = SwingUtilities2.liesInHorizontal(rect, p, ltr, true);
 1585                   if (xSection == LEADING) {
 1586                       between = true;
 1587                   } else if (xSection == TRAILING) {
 1588                       col++;
 1589                       between = true;
 1590                   }
 1591   
 1592                   location = new DropLocation(p, row, col, false, between);
 1593                   break;
 1594               case ON_OR_INSERT:
 1595                   if (row == -1 && col == -1) {
 1596                       location = new DropLocation(p, 0, 0, true, true);
 1597                       break;
 1598                   }
 1599   
 1600                   xSection = SwingUtilities2.liesInHorizontal(rect, p, ltr, true);
 1601   
 1602                   if (row == -1) {
 1603                       if (xSection == LEADING) {
 1604                           location = new DropLocation(p, getRowCount(), col, true, true);
 1605                       } else if (xSection == TRAILING) {
 1606                           location = new DropLocation(p, getRowCount(), col + 1, true, true);
 1607                       } else {
 1608                           location = new DropLocation(p, getRowCount(), col, true, false);
 1609                       }
 1610   
 1611                       break;
 1612                   }
 1613   
 1614                   ySection = SwingUtilities2.liesInVertical(rect, p, true);
 1615                   if (ySection == LEADING) {
 1616                       between = true;
 1617                   } else if (ySection == TRAILING) {
 1618                       row++;
 1619                       between = true;
 1620                   }
 1621   
 1622                   location = new DropLocation(p, row,
 1623                                               xSection == TRAILING ? col + 1 : col,
 1624                                               between,
 1625                                               xSection != MIDDLE);
 1626   
 1627                   break;
 1628               default:
 1629                   assert false : "Unexpected drop mode";
 1630           }
 1631   
 1632           return location;
 1633       }
 1634   
 1635       /**
 1636        * Called to set or clear the drop location during a DnD operation.
 1637        * In some cases, the component may need to use it's internal selection
 1638        * temporarily to indicate the drop location. To help facilitate this,
 1639        * this method returns and accepts as a parameter a state object.
 1640        * This state object can be used to store, and later restore, the selection
 1641        * state. Whatever this method returns will be passed back to it in
 1642        * future calls, as the state parameter. If it wants the DnD system to
 1643        * continue storing the same state, it must pass it back every time.
 1644        * Here's how this is used:
 1645        * <p>
 1646        * Let's say that on the first call to this method the component decides
 1647        * to save some state (because it is about to use the selection to show
 1648        * a drop index). It can return a state object to the caller encapsulating
 1649        * any saved selection state. On a second call, let's say the drop location
 1650        * is being changed to something else. The component doesn't need to
 1651        * restore anything yet, so it simply passes back the same state object
 1652        * to have the DnD system continue storing it. Finally, let's say this
 1653        * method is messaged with <code>null</code>. This means DnD
 1654        * is finished with this component for now, meaning it should restore
 1655        * state. At this point, it can use the state parameter to restore
 1656        * said state, and of course return <code>null</code> since there's
 1657        * no longer anything to store.
 1658        *
 1659        * @param location the drop location (as calculated by
 1660        *        <code>dropLocationForPoint</code>) or <code>null</code>
 1661        *        if there's no longer a valid drop location
 1662        * @param state the state object saved earlier for this component,
 1663        *        or <code>null</code>
 1664        * @param forDrop whether or not the method is being called because an
 1665        *        actual drop occurred
 1666        * @return any saved state for this component, or <code>null</code> if none
 1667        */
 1668       Object setDropLocation(TransferHandler.DropLocation location,
 1669                              Object state,
 1670                              boolean forDrop) {
 1671   
 1672           Object retVal = null;
 1673           DropLocation tableLocation = (DropLocation)location;
 1674   
 1675           if (dropMode == DropMode.USE_SELECTION) {
 1676               if (tableLocation == null) {
 1677                   if (!forDrop && state != null) {
 1678                       clearSelection();
 1679   
 1680                       int[] rows = (int[])((int[][])state)[0];
 1681                       int[] cols = (int[])((int[][])state)[1];
 1682                       int[] anchleads = (int[])((int[][])state)[2];
 1683   
 1684                       for (int i = 0; i < rows.length; i++) {
 1685                           addRowSelectionInterval(rows[i], rows[i]);
 1686                       }
 1687   
 1688                       for (int i = 0; i < cols.length; i++) {
 1689                           addColumnSelectionInterval(cols[i], cols[i]);
 1690                       }
 1691   
 1692                       SwingUtilities2.setLeadAnchorWithoutSelection(
 1693                               getSelectionModel(), anchleads[1], anchleads[0]);
 1694   
 1695                       SwingUtilities2.setLeadAnchorWithoutSelection(
 1696                               getColumnModel().getSelectionModel(),
 1697                               anchleads[3], anchleads[2]);
 1698                   }
 1699               } else {
 1700                   if (dropLocation == null) {
 1701                       retVal = new int[][]{
 1702                           getSelectedRows(),
 1703                           getSelectedColumns(),
 1704                           {getAdjustedIndex(getSelectionModel()
 1705                                .getAnchorSelectionIndex(), true),
 1706                            getAdjustedIndex(getSelectionModel()
 1707                                .getLeadSelectionIndex(), true),
 1708                            getAdjustedIndex(getColumnModel().getSelectionModel()
 1709                                .getAnchorSelectionIndex(), false),
 1710                            getAdjustedIndex(getColumnModel().getSelectionModel()
 1711                                .getLeadSelectionIndex(), false)}};
 1712                   } else {
 1713                       retVal = state;
 1714                   }
 1715   
 1716                   if (tableLocation.getRow() == -1) {
 1717                       clearSelectionAndLeadAnchor();
 1718                   } else {
 1719                       setRowSelectionInterval(tableLocation.getRow(),
 1720                                               tableLocation.getRow());
 1721                       setColumnSelectionInterval(tableLocation.getColumn(),
 1722                                                  tableLocation.getColumn());
 1723                   }
 1724               }
 1725           }
 1726   
 1727           DropLocation old = dropLocation;
 1728           dropLocation = tableLocation;
 1729           firePropertyChange("dropLocation", old, dropLocation);
 1730   
 1731           return retVal;
 1732       }
 1733   
 1734       /**
 1735        * Returns the location that this component should visually indicate
 1736        * as the drop location during a DnD operation over the component,
 1737        * or {@code null} if no location is to currently be shown.
 1738        * <p>
 1739        * This method is not meant for querying the drop location
 1740        * from a {@code TransferHandler}, as the drop location is only
 1741        * set after the {@code TransferHandler}'s <code>canImport</code>
 1742        * has returned and has allowed for the location to be shown.
 1743        * <p>
 1744        * When this property changes, a property change event with
 1745        * name "dropLocation" is fired by the component.
 1746        *
 1747        * @return the drop location
 1748        * @see #setDropMode
 1749        * @see TransferHandler#canImport(TransferHandler.TransferSupport)
 1750        * @since 1.6
 1751        */
 1752       public final DropLocation getDropLocation() {
 1753           return dropLocation;
 1754       }
 1755   
 1756       /**
 1757        * Specifies whether a {@code RowSorter} should be created for the
 1758        * table whenever its model changes.
 1759        * <p>
 1760        * When {@code setAutoCreateRowSorter(true)} is invoked, a {@code
 1761        * TableRowSorter} is immediately created and installed on the
 1762        * table.  While the {@code autoCreateRowSorter} property remains
 1763        * {@code true}, every time the model is changed, a new {@code
 1764        * TableRowSorter} is created and set as the table's row sorter.
 1765        *
 1766        * @param autoCreateRowSorter whether or not a {@code RowSorter}
 1767        *        should be automatically created
 1768        * @see javax.swing.table.TableRowSorter
 1769        * @beaninfo
 1770        *        bound: true
 1771        *    preferred: true
 1772        *  description: Whether or not to turn on sorting by default.
 1773        * @since 1.6
 1774        */
 1775       public void setAutoCreateRowSorter(boolean autoCreateRowSorter) {
 1776           boolean oldValue = this.autoCreateRowSorter;
 1777           this.autoCreateRowSorter = autoCreateRowSorter;
 1778           if (autoCreateRowSorter) {
 1779               setRowSorter(new TableRowSorter(getModel()));
 1780           }
 1781           firePropertyChange("autoCreateRowSorter", oldValue,
 1782                              autoCreateRowSorter);
 1783       }
 1784   
 1785       /**
 1786        * Returns {@code true} if whenever the model changes, a new
 1787        * {@code RowSorter} should be created and installed
 1788        * as the table's sorter; otherwise, returns {@code false}.
 1789        *
 1790        * @return true if a {@code RowSorter} should be created when
 1791        *         the model changes
 1792        * @since 1.6
 1793        */
 1794       public boolean getAutoCreateRowSorter() {
 1795           return autoCreateRowSorter;
 1796       }
 1797   
 1798       /**
 1799        * Specifies whether the selection should be updated after sorting.
 1800        * If true, on sorting the selection is reset such that
 1801        * the same rows, in terms of the model, remain selected.  The default
 1802        * is true.
 1803        *
 1804        * @param update whether or not to update the selection on sorting
 1805        * @beaninfo
 1806        *        bound: true
 1807        *       expert: true
 1808        *  description: Whether or not to update the selection on sorting
 1809        * @since 1.6
 1810        */
 1811       public void setUpdateSelectionOnSort(boolean update) {
 1812           if (updateSelectionOnSort != update) {
 1813               updateSelectionOnSort = update;
 1814               firePropertyChange("updateSelectionOnSort", !update, update);
 1815           }
 1816       }
 1817   
 1818       /**
 1819        * Returns true if the selection should be updated after sorting.
 1820        *
 1821        * @return whether to update the selection on a sort
 1822        * @since 1.6
 1823        */
 1824       public boolean getUpdateSelectionOnSort() {
 1825           return updateSelectionOnSort;
 1826       }
 1827   
 1828       /**
 1829        * Sets the <code>RowSorter</code>.  <code>RowSorter</code> is used
 1830        * to provide sorting and filtering to a <code>JTable</code>.
 1831        * <p>
 1832        * This method clears the selection and resets any variable row heights.
 1833        * <p>
 1834        * This method fires a <code>PropertyChangeEvent</code> when appropriate,
 1835        * with the property name <code>"rowSorter"</code>.  For
 1836        * backward-compatibility, this method fires an additional event with the
 1837        * property name <code>"sorter"</code>.
 1838        * <p>
 1839        * If the underlying model of the <code>RowSorter</code> differs from
 1840        * that of this <code>JTable</code> undefined behavior will result.
 1841        *
 1842        * @param sorter the <code>RowSorter</code>; <code>null</code> turns
 1843        *        sorting off
 1844        * @see javax.swing.table.TableRowSorter
 1845        * @beaninfo
 1846        *        bound: true
 1847        *  description: The table's RowSorter
 1848        * @since 1.6
 1849        */
 1850       public void setRowSorter(RowSorter<? extends TableModel> sorter) {
 1851           RowSorter<? extends TableModel> oldRowSorter = null;
 1852           if (sortManager != null) {
 1853               oldRowSorter = sortManager.sorter;
 1854               sortManager.dispose();
 1855               sortManager = null;
 1856           }
 1857           rowModel = null;
 1858           clearSelectionAndLeadAnchor();
 1859           if (sorter != null) {
 1860               sortManager = new SortManager(sorter);
 1861           }
 1862           resizeAndRepaint();
 1863           firePropertyChange("rowSorter", oldRowSorter, sorter);
 1864           firePropertyChange("sorter", oldRowSorter, sorter);
 1865       }
 1866   
 1867       /**
 1868        * Returns the object responsible for sorting.
 1869        *
 1870        * @return the object responsible for sorting
 1871        * @since 1.6
 1872        */
 1873       public RowSorter<? extends TableModel> getRowSorter() {
 1874           return (sortManager != null) ? sortManager.sorter : null;
 1875       }
 1876   
 1877   //
 1878   // Selection methods
 1879   //
 1880       /**
 1881        * Sets the table's selection mode to allow only single selections, a single
 1882        * contiguous interval, or multiple intervals.
 1883        * <P>
 1884        * <bold>Note:</bold>
 1885        * <code>JTable</code> provides all the methods for handling
 1886        * column and row selection.  When setting states,
 1887        * such as <code>setSelectionMode</code>, it not only
 1888        * updates the mode for the row selection model but also sets similar
 1889        * values in the selection model of the <code>columnModel</code>.
 1890        * If you want to have the row and column selection models operating
 1891        * in different modes, set them both directly.
 1892        * <p>
 1893        * Both the row and column selection models for <code>JTable</code>
 1894        * default to using a <code>DefaultListSelectionModel</code>
 1895        * so that <code>JTable</code> works the same way as the
 1896        * <code>JList</code>. See the <code>setSelectionMode</code> method
 1897        * in <code>JList</code> for details about the modes.
 1898        *
 1899        * @see JList#setSelectionMode
 1900        * @beaninfo
 1901        * description: The selection mode used by the row and column selection models.
 1902        *        enum: SINGLE_SELECTION            ListSelectionModel.SINGLE_SELECTION
 1903        *              SINGLE_INTERVAL_SELECTION   ListSelectionModel.SINGLE_INTERVAL_SELECTION
 1904        *              MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
 1905        */
 1906       public void setSelectionMode(int selectionMode) {
 1907           clearSelection();
 1908           getSelectionModel().setSelectionMode(selectionMode);
 1909           getColumnModel().getSelectionModel().setSelectionMode(selectionMode);
 1910       }
 1911   
 1912       /**
 1913        * Sets whether the rows in this model can be selected.
 1914        *
 1915        * @param rowSelectionAllowed   true if this model will allow row selection
 1916        * @see #getRowSelectionAllowed
 1917        * @beaninfo
 1918        *  bound: true
 1919        *    attribute: visualUpdate true
 1920        *  description: If true, an entire row is selected for each selected cell.
 1921        */
 1922       public void setRowSelectionAllowed(boolean rowSelectionAllowed) {
 1923           boolean old = this.rowSelectionAllowed;
 1924           this.rowSelectionAllowed = rowSelectionAllowed;
 1925           if (old != rowSelectionAllowed) {
 1926               repaint();
 1927           }
 1928           firePropertyChange("rowSelectionAllowed", old, rowSelectionAllowed);
 1929       }
 1930   
 1931       /**
 1932        * Returns true if rows can be selected.
 1933        *
 1934        * @return true if rows can be selected, otherwise false
 1935        * @see #setRowSelectionAllowed
 1936        */
 1937       public boolean getRowSelectionAllowed() {
 1938           return rowSelectionAllowed;
 1939       }
 1940   
 1941       /**
 1942        * Sets whether the columns in this model can be selected.
 1943        *
 1944        * @param columnSelectionAllowed   true if this model will allow column selection
 1945        * @see #getColumnSelectionAllowed
 1946        * @beaninfo
 1947        *  bound: true
 1948        *    attribute: visualUpdate true
 1949        *  description: If true, an entire column is selected for each selected cell.
 1950        */
 1951       public void setColumnSelectionAllowed(boolean columnSelectionAllowed) {
 1952           boolean old = columnModel.getColumnSelectionAllowed();
 1953           columnModel.setColumnSelectionAllowed(columnSelectionAllowed);
 1954           if (old != columnSelectionAllowed) {
 1955               repaint();
 1956           }
 1957           firePropertyChange("columnSelectionAllowed", old, columnSelectionAllowed);
 1958       }
 1959   
 1960       /**
 1961        * Returns true if columns can be selected.
 1962        *
 1963        * @return true if columns can be selected, otherwise false
 1964        * @see #setColumnSelectionAllowed
 1965        */
 1966       public boolean getColumnSelectionAllowed() {
 1967           return columnModel.getColumnSelectionAllowed();
 1968       }
 1969   
 1970       /**
 1971        * Sets whether this table allows both a column selection and a
 1972        * row selection to exist simultaneously. When set,
 1973        * the table treats the intersection of the row and column selection
 1974        * models as the selected cells. Override <code>isCellSelected</code> to
 1975        * change this default behavior. This method is equivalent to setting
 1976        * both the <code>rowSelectionAllowed</code> property and
 1977        * <code>columnSelectionAllowed</code> property of the
 1978        * <code>columnModel</code> to the supplied value.
 1979        *
 1980        * @param  cellSelectionEnabled     true if simultaneous row and column
 1981        *                                  selection is allowed
 1982        * @see #getCellSelectionEnabled
 1983        * @see #isCellSelected
 1984        * @beaninfo
 1985        *  bound: true
 1986        *    attribute: visualUpdate true
 1987        *  description: Select a rectangular region of cells rather than
 1988        *               rows or columns.
 1989        */
 1990       public void setCellSelectionEnabled(boolean cellSelectionEnabled) {
 1991           setRowSelectionAllowed(cellSelectionEnabled);
 1992           setColumnSelectionAllowed(cellSelectionEnabled);
 1993           boolean old = this.cellSelectionEnabled;
 1994           this.cellSelectionEnabled = cellSelectionEnabled;
 1995           firePropertyChange("cellSelectionEnabled", old, cellSelectionEnabled);
 1996       }
 1997   
 1998       /**
 1999        * Returns true if both row and column selection models are enabled.
 2000        * Equivalent to <code>getRowSelectionAllowed() &&
 2001        * getColumnSelectionAllowed()</code>.
 2002        *
 2003        * @return true if both row and column selection models are enabled
 2004        *
 2005        * @see #setCellSelectionEnabled
 2006        */
 2007       public boolean getCellSelectionEnabled() {
 2008           return getRowSelectionAllowed() && getColumnSelectionAllowed();
 2009       }
 2010   
 2011       /**
 2012        *  Selects all rows, columns, and cells in the table.
 2013        */
 2014       public void selectAll() {
 2015           // If I'm currently editing, then I should stop editing
 2016           if (isEditing()) {
 2017               removeEditor();
 2018           }
 2019           if (getRowCount() > 0 && getColumnCount() > 0) {
 2020               int oldLead;
 2021               int oldAnchor;
 2022               ListSelectionModel selModel;
 2023   
 2024               selModel = selectionModel;
 2025               selModel.setValueIsAdjusting(true);
 2026               oldLead = getAdjustedIndex(selModel.getLeadSelectionIndex(), true);
 2027               oldAnchor = getAdjustedIndex(selModel.getAnchorSelectionIndex(), true);
 2028   
 2029               setRowSelectionInterval(0, getRowCount()-1);
 2030   
 2031               // this is done to restore the anchor and lead
 2032               SwingUtilities2.setLeadAnchorWithoutSelection(selModel, oldLead, oldAnchor);
 2033   
 2034               selModel.setValueIsAdjusting(false);
 2035   
 2036               selModel = columnModel.getSelectionModel();
 2037               selModel.setValueIsAdjusting(true);
 2038               oldLead = getAdjustedIndex(selModel.getLeadSelectionIndex(), false);
 2039               oldAnchor = getAdjustedIndex(selModel.getAnchorSelectionIndex(), false);
 2040   
 2041               setColumnSelectionInterval(0, getColumnCount()-1);
 2042   
 2043               // this is done to restore the anchor and lead
 2044               SwingUtilities2.setLeadAnchorWithoutSelection(selModel, oldLead, oldAnchor);
 2045   
 2046               selModel.setValueIsAdjusting(false);
 2047           }
 2048       }
 2049   
 2050       /**
 2051        * Deselects all selected columns and rows.
 2052        */
 2053       public void clearSelection() {
 2054           selectionModel.clearSelection();
 2055           columnModel.getSelectionModel().clearSelection();
 2056       }
 2057   
 2058       private void clearSelectionAndLeadAnchor() {
 2059           selectionModel.setValueIsAdjusting(true);
 2060           columnModel.getSelectionModel().setValueIsAdjusting(true);
 2061   
 2062           clearSelection();
 2063   
 2064           selectionModel.setAnchorSelectionIndex(-1);
 2065           selectionModel.setLeadSelectionIndex(-1);
 2066           columnModel.getSelectionModel().setAnchorSelectionIndex(-1);
 2067           columnModel.getSelectionModel().setLeadSelectionIndex(-1);
 2068   
 2069           selectionModel.setValueIsAdjusting(false);
 2070           columnModel.getSelectionModel().setValueIsAdjusting(false);
 2071       }
 2072   
 2073       private int getAdjustedIndex(int index, boolean row) {
 2074           int compare = row ? getRowCount() : getColumnCount();
 2075           return index < compare ? index : -1;
 2076       }
 2077   
 2078       private int boundRow(int row) throws IllegalArgumentException {
 2079           if (row < 0 || row >= getRowCount()) {
 2080               throw new IllegalArgumentException("Row index out of range");
 2081           }
 2082           return row;
 2083       }
 2084   
 2085       private int boundColumn(int col) {
 2086           if (col< 0 || col >= getColumnCount()) {
 2087               throw new IllegalArgumentException("Column index out of range");
 2088           }
 2089           return col;
 2090       }
 2091   
 2092       /**
 2093        * Selects the rows from <code>index0</code> to <code>index1</code>,
 2094        * inclusive.
 2095        *
 2096        * @exception IllegalArgumentException      if <code>index0</code> or
 2097        *                                          <code>index1</code> lie outside
 2098        *                                          [0, <code>getRowCount()</code>-1]
 2099        * @param   index0 one end of the interval
 2100        * @param   index1 the other end of the interval
 2101        */
 2102       public void setRowSelectionInterval(int index0, int index1) {
 2103           selectionModel.setSelectionInterval(boundRow(index0), boundRow(index1));
 2104       }
 2105   
 2106       /**
 2107        * Selects the columns from <code>index0</code> to <code>index1</code>,
 2108        * inclusive.
 2109        *
 2110        * @exception IllegalArgumentException      if <code>index0</code> or
 2111        *                                          <code>index1</code> lie outside
 2112        *                                          [0, <code>getColumnCount()</code>-1]
 2113        * @param   index0 one end of the interval
 2114        * @param   index1 the other end of the interval
 2115        */
 2116       public void setColumnSelectionInterval(int index0, int index1) {
 2117           columnModel.getSelectionModel().setSelectionInterval(boundColumn(index0), boundColumn(index1));
 2118       }
 2119   
 2120       /**
 2121        * Adds the rows from <code>index0</code> to <code>index1</code>, inclusive, to
 2122        * the current selection.
 2123        *
 2124        * @exception IllegalArgumentException      if <code>index0</code> or <code>index1</code>
 2125        *                                          lie outside [0, <code>getRowCount()</code>-1]
 2126        * @param   index0 one end of the interval
 2127        * @param   index1 the other end of the interval
 2128        */
 2129       public void addRowSelectionInterval(int index0, int index1) {
 2130           selectionModel.addSelectionInterval(boundRow(index0), boundRow(index1));
 2131       }
 2132   
 2133       /**
 2134        * Adds the columns from <code>index0</code> to <code>index1</code>,
 2135        * inclusive, to the current selection.
 2136        *
 2137        * @exception IllegalArgumentException      if <code>index0</code> or
 2138        *                                          <code>index1</code> lie outside
 2139        *                                          [0, <code>getColumnCount()</code>-1]
 2140        * @param   index0 one end of the interval
 2141        * @param   index1 the other end of the interval
 2142        */
 2143       public void addColumnSelectionInterval(int index0, int index1) {
 2144           columnModel.getSelectionModel().addSelectionInterval(boundColumn(index0), boundColumn(index1));
 2145       }
 2146   
 2147       /**
 2148        * Deselects the rows from <code>index0</code> to <code>index1</code>, inclusive.
 2149        *
 2150        * @exception IllegalArgumentException      if <code>index0</code> or
 2151        *                                          <code>index1</code> lie outside
 2152        *                                          [0, <code>getRowCount()</code>-1]
 2153        * @param   index0 one end of the interval
 2154        * @param   index1 the other end of the interval
 2155        */
 2156       public void removeRowSelectionInterval(int index0, int index1) {
 2157           selectionModel.removeSelectionInterval(boundRow(index0), boundRow(index1));
 2158       }
 2159   
 2160       /**
 2161        * Deselects the columns from <code>index0</code> to <code>index1</code>, inclusive.
 2162        *
 2163        * @exception IllegalArgumentException      if <code>index0</code> or
 2164        *                                          <code>index1</code> lie outside
 2165        *                                          [0, <code>getColumnCount()</code>-1]
 2166        * @param   index0 one end of the interval
 2167        * @param   index1 the other end of the interval
 2168        */
 2169       public void removeColumnSelectionInterval(int index0, int index1) {
 2170           columnModel.getSelectionModel().removeSelectionInterval(boundColumn(index0), boundColumn(index1));
 2171       }
 2172   
 2173       /**
 2174        * Returns the index of the first selected row, -1 if no row is selected.
 2175        * @return the index of the first selected row
 2176        */
 2177       public int getSelectedRow() {
 2178           return selectionModel.getMinSelectionIndex();
 2179       }
 2180   
 2181       /**
 2182        * Returns the index of the first selected column,
 2183        * -1 if no column is selected.
 2184        * @return the index of the first selected column
 2185        */
 2186       public int getSelectedColumn() {
 2187           return columnModel.getSelectionModel().getMinSelectionIndex();
 2188       }
 2189   
 2190       /**
 2191        * Returns the indices of all selected rows.
 2192        *
 2193        * @return an array of integers containing the indices of all selected rows,
 2194        *         or an empty array if no row is selected
 2195        * @see #getSelectedRow
 2196        */
 2197       public int[] getSelectedRows() {
 2198           int iMin = selectionModel.getMinSelectionIndex();
 2199           int iMax = selectionModel.getMaxSelectionIndex();
 2200   
 2201           if ((iMin == -1) || (iMax == -1)) {
 2202               return new int[0];
 2203           }
 2204   
 2205           int[] rvTmp = new int[1+ (iMax - iMin)];
 2206           int n = 0;
 2207           for(int i = iMin; i <= iMax; i++) {
 2208               if (selectionModel.isSelectedIndex(i)) {
 2209                   rvTmp[n++] = i;
 2210               }
 2211           }
 2212           int[] rv = new int[n];
 2213           System.arraycopy(rvTmp, 0, rv, 0, n);
 2214           return rv;
 2215       }
 2216   
 2217       /**
 2218        * Returns the indices of all selected columns.
 2219        *
 2220        * @return an array of integers containing the indices of all selected columns,
 2221        *         or an empty array if no column is selected
 2222        * @see #getSelectedColumn
 2223        */
 2224       public int[] getSelectedColumns() {
 2225           return columnModel.getSelectedColumns();
 2226       }
 2227   
 2228       /**
 2229        * Returns the number of selected rows.
 2230        *
 2231        * @return the number of selected rows, 0 if no rows are selected
 2232        */
 2233       public int getSelectedRowCount() {
 2234           int iMin = selectionModel.getMinSelectionIndex();
 2235           int iMax = selectionModel.getMaxSelectionIndex();
 2236           int count = 0;
 2237   
 2238           for(int i = iMin; i <= iMax; i++) {
 2239               if (selectionModel.isSelectedIndex(i)) {
 2240                   count++;
 2241               }
 2242           }
 2243           return count;
 2244       }
 2245   
 2246       /**
 2247        * Returns the number of selected columns.
 2248        *
 2249        * @return the number of selected columns, 0 if no columns are selected
 2250        */
 2251       public int getSelectedColumnCount() {
 2252           return columnModel.getSelectedColumnCount();
 2253       }
 2254   
 2255       /**
 2256        * Returns true if the specified index is in the valid range of rows,
 2257        * and the row at that index is selected.
 2258        *
 2259        * @return true if <code>row</code> is a valid index and the row at
 2260        *              that index is selected (where 0 is the first row)
 2261        */
 2262       public boolean isRowSelected(int row) {
 2263           return selectionModel.isSelectedIndex(row);
 2264       }
 2265   
 2266       /**
 2267        * Returns true if the specified index is in the valid range of columns,
 2268        * and the column at that index is selected.
 2269        *
 2270        * @param   column   the column in the column model
 2271        * @return true if <code>column</code> is a valid index and the column at
 2272        *              that index is selected (where 0 is the first column)
 2273        */
 2274       public boolean isColumnSelected(int column) {
 2275           return columnModel.getSelectionModel().isSelectedIndex(column);
 2276       }
 2277   
 2278       /**
 2279        * Returns true if the specified indices are in the valid range of rows
 2280        * and columns and the cell at the specified position is selected.
 2281        * @param row   the row being queried
 2282        * @param column  the column being queried
 2283        *
 2284        * @return true if <code>row</code> and <code>column</code> are valid indices
 2285        *              and the cell at index <code>(row, column)</code> is selected,
 2286        *              where the first row and first column are at index 0
 2287        */
 2288       public boolean isCellSelected(int row, int column) {
 2289           if (!getRowSelectionAllowed() && !getColumnSelectionAllowed()) {
 2290               return false;
 2291           }
 2292           return (!getRowSelectionAllowed() || isRowSelected(row)) &&
 2293                  (!getColumnSelectionAllowed() || isColumnSelected(column));
 2294       }
 2295   
 2296       private void changeSelectionModel(ListSelectionModel sm, int index,
 2297                                         boolean toggle, boolean extend, boolean selected,
 2298                                         int anchor, boolean anchorSelected) {
 2299           if (extend) {
 2300               if (toggle) {
 2301                   if (anchorSelected) {
 2302                       sm.addSelectionInterval(anchor, index);
 2303