Use Tree Navigation
protected class

JTable.AccessibleJTable.AccessibleJTableModelChange

extends Object
implements AccessibleTableModelChange
/*
 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */


package javax.swing;

import java.util.*;

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.awt.print.*;

import java.beans.*;

import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;

import javax.accessibility.*;

import javax.swing.event.*;
import javax.swing.plaf.*;
import javax.swing.table.*;
import javax.swing.border.*;

import java.text.NumberFormat;
import java.text.DateFormat;
import java.text.MessageFormat;

import javax.print.attribute.*;
import javax.print.PrintService;

import sun.swing.SwingUtilities2;
import sun.swing.SwingUtilities2.Section;
import static sun.swing.SwingUtilities2.Section.*;
import sun.swing.PrintingStatus;
import sun.swing.SwingLazyValue;

/**
 * The <code>JTable</code> is used to display and edit regular two-dimensional tables
 * of cells.
 * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/table.html">How to Use Tables</a>
 * in <em>The Java Tutorial</em>
 * for task-oriented documentation and examples of using <code>JTable</code>.
 *
 * <p>
 * The <code>JTable</code> has many
 * facilities that make it possible to customize its rendering and editing
 * but provides defaults for these features so that simple tables can be
 * set up easily.  For example, to set up a table with 10 rows and 10
 * columns of numbers:
 * <p>
 * <pre>
 *      TableModel dataModel = new AbstractTableModel() {
 *          public int getColumnCount() { return 10; }
 *          public int getRowCount() { return 10;}
 *          public Object getValueAt(int row, int col) { return new Integer(row*col); }
 *      };
 *      JTable table = new JTable(dataModel);
 *      JScrollPane scrollpane = new JScrollPane(table);
 * </pre>
 * <p>
 * {@code JTable}s are typically placed inside of a {@code JScrollPane}.  By
 * default, a {@code JTable} will adjust its width such that
 * a horizontal scrollbar is unnecessary.  To allow for a horizontal scrollbar,
 * invoke {@link #setAutoResizeMode} with {@code AUTO_RESIZE_OFF}.
 * Note that if you wish to use a <code>JTable</code> in a standalone
 * view (outside of a <code>JScrollPane</code>) and want the header
 * displayed, you can get it using {@link #getTableHeader} and
 * display it separately.
 * <p>
 * To enable sorting and filtering of rows, use a
 * {@code RowSorter}.
 * You can set up a row sorter in either of two ways:
 * <ul>
 *   <li>Directly set the {@code RowSorter}. For example:
 *        {@code table.setRowSorter(new TableRowSorter(model))}.
 *   <li>Set the {@code autoCreateRowSorter}
 *       property to {@code true}, so that the {@code JTable}
 *       creates a {@code RowSorter} for
 *       you. For example: {@code setAutoCreateRowSorter(true)}.
 * </ul>
 * <p>
 * When designing applications that use the <code>JTable</code> it is worth paying
 * close attention to the data structures that will represent the table's data.
 * The <code>DefaultTableModel</code> is a model implementation that
 * uses a <code>Vector</code> of <code>Vector</code>s of <code>Object</code>s to
 * store the cell values. As well as copying the data from an
 * application into the <code>DefaultTableModel</code>,
 * it is also possible to wrap the data in the methods of the
 * <code>TableModel</code> interface so that the data can be passed to the
 * <code>JTable</code> directly, as in the example above. This often results
 * in more efficient applications because the model is free to choose the
 * internal representation that best suits the data.
 * A good rule of thumb for deciding whether to use the <code>AbstractTableModel</code>
 * or the <code>DefaultTableModel</code> is to use the <code>AbstractTableModel</code>
 * as the base class for creating subclasses and the <code>DefaultTableModel</code>
 * when subclassing is not required.
 * <p>
 * The "TableExample" directory in the demo area of the source distribution
 * gives a number of complete examples of <code>JTable</code> usage,
 * covering how the <code>JTable</code> can be used to provide an
 * editable view of data taken from a database and how to modify
 * the columns in the display to use specialized renderers and editors.
 * <p>
 * The <code>JTable</code> uses integers exclusively to refer to both the rows and the columns
 * of the model that it displays. The <code>JTable</code> simply takes a tabular range of cells
 * and uses <code>getValueAt(int, int)</code> to retrieve the
 * values from the model during painting.  It is important to remember that
 * the column and row indexes returned by various <code>JTable</code> methods
 * are in terms of the <code>JTable</code> (the view) and are not
 * necessarily the same indexes used by the model.
 * <p>
 * By default, columns may be rearranged in the <code>JTable</code> so that the
 * view's columns appear in a different order to the columns in the model.
 * This does not affect the implementation of the model at all: when the
 * columns are reordered, the <code>JTable</code> maintains the new order of the columns
 * internally and converts its column indices before querying the model.
 * <p>
 * So, when writing a <code>TableModel</code>, it is not necessary to listen for column
 * reordering events as the model will be queried in its own coordinate
 * system regardless of what is happening in the view.
 * In the examples area there is a demonstration of a sorting algorithm making
 * use of exactly this technique to interpose yet another coordinate system
 * where the order of the rows is changed, rather than the order of the columns.
 * <p>
 * Similarly when using the sorting and filtering functionality
 * provided by <code>RowSorter</code> the underlying
 * <code>TableModel</code> does not need to know how to do sorting,
 * rather <code>RowSorter</code> will handle it.  Coordinate
 * conversions will be necessary when using the row based methods of
 * <code>JTable</code> with the underlying <code>TableModel</code>.
 * All of <code>JTable</code>s row based methods are in terms of the
 * <code>RowSorter</code>, which is not necessarily the same as that
 * of the underlying <code>TableModel</code>.  For example, the
 * selection is always in terms of <code>JTable</code> so that when
 * using <code>RowSorter</code> you will need to convert using
 * <code>convertRowIndexToView</code> or
 * <code>convertRowIndexToModel</code>.  The following shows how to
 * convert coordinates from <code>JTable</code> to that of the
 * underlying model:
 * <pre>
 *   int[] selection = table.getSelectedRows();
 *   for (int i = 0; i &lt; selection.length; i++) {
 *     selection[i] = table.convertRowIndexToModel(selection[i]);
 *   }
 *   // selection is now in terms of the underlying TableModel
 * </pre>
 * <p>
 * By default if sorting is enabled <code>JTable</code> will persist the
 * selection and variable row heights in terms of the model on
 * sorting.  For example if row 0, in terms of the underlying model,
 * is currently selected, after the sort row 0, in terms of the
 * underlying model will be selected.  Visually the selection may
 * change, but in terms of the underlying model it will remain the
 * same.  The one exception to that is if the model index is no longer
 * visible or was removed.  For example, if row 0 in terms of model
 * was filtered out the selection will be empty after the sort.
 * <p>
 * J2SE 5 adds methods to <code>JTable</code> to provide convenient access to some
 * common printing needs. Simple new {@link #print()} methods allow for quick
 * and easy addition of printing support to your application. In addition, a new
 * {@link #getPrintable} method is available for more advanced printing needs.
 * <p>
 * As for all <code>JComponent</code> classes, you can use
 * {@link InputMap} and {@link ActionMap} to associate an
 * {@link Action} object with a {@link KeyStroke} and execute the
 * action under specified conditions.
 * <p>
 * <strong>Warning:</strong> Swing is not thread safe. For more
 * information see <a
 * href="package-summary.html#threading">Swing's Threading
 * Policy</a>.
 * <p>
 * <strong>Warning:</strong>
 * Serialized objects of this class will not be compatible with
 * future Swing releases. The current serialization support is
 * appropriate for short term storage or RMI between applications running
 * the same version of Swing.  As of 1.4, support for long term storage
 * of all JavaBeans<sup><font size="-2">TM</font></sup>
 * has been added to the <code>java.beans</code> package.
 * Please see {@link java.beans.XMLEncoder}.
 *
 *
 * @beaninfo
 *   attribute: isContainer false
 * description: A component which displays data in a two dimensional grid.
 *
 * @author Philip Milne
 * @author Shannon Hickey (printing support)
 * @see javax.swing.table.DefaultTableModel
 * @see javax.swing.table.TableRowSorter
 */

/* The first versions of the JTable, contained in Swing-0.1 through
 * Swing-0.4, were written by Alan Chung.
 */

public class JTable extends JComponent implements TableModelListener, Scrollable,
   
TableColumnModelListener, ListSelectionListener, CellEditorListener,
   
Accessible, RowSorterListener
{
//
// Static Constants
//

   
/**
     * @see #getUIClassID
     * @see #readObject
     */

   
private static final String uiClassID = "TableUI";

   
/** Do not adjust column widths automatically; use a horizontal scrollbar instead. */
   
public static final int     AUTO_RESIZE_OFF = 0;

   
/** When a column is adjusted in the UI, adjust the next column the opposite way. */
   
public static final int     AUTO_RESIZE_NEXT_COLUMN = 1;

   
/** During UI adjustment, change subsequent columns to preserve the total width;
      * this is the default behavior. */

   
public static final int     AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;

   
/** During all resize operations, apply adjustments to the last column only. */
   
public static final int     AUTO_RESIZE_LAST_COLUMN = 3;

   
/** During all resize operations, proportionately resize all columns. */
   
public static final int     AUTO_RESIZE_ALL_COLUMNS = 4;


   
/**
     * Printing modes, used in printing <code>JTable</code>s.
     *
     * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
     *             boolean, PrintRequestAttributeSet, boolean)
     * @see #getPrintable
     * @since 1.5
     */

   
public enum PrintMode {

       
/**
         * Printing mode that prints the table at its current size,
         * spreading both columns and rows across multiple pages if necessary.
         */

        NORMAL
,

       
/**
         * Printing mode that scales the output smaller, if necessary,
         * to fit the table's entire width (and thereby all columns) on each page;
         * Rows are spread across multiple pages as necessary.
         */

        FIT_WIDTH
   
}


//
// Instance Variables
//

   
/** The <code>TableModel</code> of the table. */
   
protected TableModel        dataModel;

   
/** The <code>TableColumnModel</code> of the table. */
   
protected TableColumnModel  columnModel;

   
/** The <code>ListSelectionModel</code> of the table, used to keep track of row selections. */
   
protected ListSelectionModel selectionModel;

   
/** The <code>TableHeader</code> working with the table. */
   
protected JTableHeader      tableHeader;

   
/** The height in pixels of each row in the table. */
   
protected int               rowHeight;

   
/** The height in pixels of the margin between the cells in each row. */
   
protected int               rowMargin;

   
/** The color of the grid. */
   
protected Color             gridColor;

   
/** The table draws horizontal lines between cells if <code>showHorizontalLines</code> is true. */
   
protected boolean           showHorizontalLines;

   
/** The table draws vertical lines between cells if <code>showVerticalLines</code> is true. */
   
protected boolean           showVerticalLines;

   
/**
     *  Determines if the table automatically resizes the
     *  width of the table's columns to take up the entire width of the
     *  table, and how it does the resizing.
     */

   
protected int               autoResizeMode;

   
/**
     *  The table will query the <code>TableModel</code> to build the default
     *  set of columns if this is true.
     */

   
protected boolean           autoCreateColumnsFromModel;

   
/** Used by the <code>Scrollable</code> interface to determine the initial visible area. */
   
protected Dimension         preferredViewportSize;

   
/** True if row selection is allowed in this table. */
   
protected boolean           rowSelectionAllowed;

   
/**
     * Obsolete as of Java 2 platform v1.3.  Please use the
     * <code>rowSelectionAllowed</code> property and the
     * <code>columnSelectionAllowed</code> property of the
     * <code>columnModel</code> instead. Or use the
     * method <code>getCellSelectionEnabled</code>.
     */

   
/*
     * If true, both a row selection and a column selection
     * can be non-empty at the same time, the selected cells are the
     * the cells whose row and column are both selected.
     */

   
protected boolean           cellSelectionEnabled;

   
/** If editing, the <code>Component</code> that is handling the editing. */
   
transient protected Component       editorComp;

   
/**
     * The active cell editor object, that overwrites the screen real estate
     * occupied by the current cell and allows the user to change its contents.
     * {@code null} if the table isn't currently editing.
     */

   
transient protected TableCellEditor cellEditor;

   
/** Identifies the column of the cell being edited. */
   
transient protected int             editingColumn;

   
/** Identifies the row of the cell being edited. */
   
transient protected int             editingRow;

   
/**
     * A table of objects that display the contents of a cell,
     * indexed by class as declared in <code>getColumnClass</code>
     * in the <code>TableModel</code> interface.
     */

   
transient protected Hashtable defaultRenderersByColumnClass;

   
/**
     * A table of objects that display and edit the contents of a cell,
     * indexed by class as declared in <code>getColumnClass</code>
     * in the <code>TableModel</code> interface.
     */

   
transient protected Hashtable defaultEditorsByColumnClass;

   
/** The foreground color of selected cells. */
   
protected Color selectionForeground;

   
/** The background color of selected cells. */
   
protected Color selectionBackground;

//
// Private state
//

   
// WARNING: If you directly access this field you should also change the
   
// SortManager.modelRowSizes field as well.
   
private SizeSequence rowModel;
   
private boolean dragEnabled;
   
private boolean surrendersFocusOnKeystroke;
   
private PropertyChangeListener editorRemover = null;
   
/**
     * The last value of getValueIsAdjusting from the column selection models
     * columnSelectionChanged notification. Used to test if a repaint is
     * needed.
     */

   
private boolean columnSelectionAdjusting;
   
/**
     * The last value of getValueIsAdjusting from the row selection models
     * valueChanged notification. Used to test if a repaint is needed.
     */

   
private boolean rowSelectionAdjusting;

   
/**
     * To communicate errors between threads during printing.
     */

   
private Throwable printError;

   
/**
     * True when setRowHeight(int) has been invoked.
     */

   
private boolean isRowHeightSet;

   
/**
     * If true, on a sort the selection is reset.
     */

   
private boolean updateSelectionOnSort;

   
/**
     * Information used in sorting.
     */

   
private transient SortManager sortManager;

   
/**
     * If true, when sorterChanged is invoked it's value is ignored.
     */

   
private boolean ignoreSortChange;

   
/**
     * Whether or not sorterChanged has been invoked.
     */

   
private boolean sorterChanged;

   
/**
     * If true, any time the model changes a new RowSorter is set.
     */

   
private boolean autoCreateRowSorter;

   
/**
     * Whether or not the table always fills the viewport height.
     * @see #setFillsViewportHeight
     * @see #getScrollableTracksViewportHeight
     */

   
private boolean fillsViewportHeight;

   
/**
     * The drop mode for this component.
     */

   
private DropMode dropMode = DropMode.USE_SELECTION;

   
/**
     * The drop location.
     */

   
private transient DropLocation dropLocation;

   
/**
     * A subclass of <code>TransferHandler.DropLocation</code> representing
     * a drop location for a <code>JTable</code>.
     *
     * @see #getDropLocation
     * @since 1.6
     */

   
public static final class DropLocation extends TransferHandler.DropLocation {
       
private final int row;
       
private final int col;
       
private final boolean isInsertRow;
       
private final boolean isInsertCol;

       
private DropLocation(Point p, int row, int col,
                             
boolean isInsertRow, boolean isInsertCol) {

           
super(p);
           
this.row = row;
           
this.col = col;
           
this.isInsertRow = isInsertRow;
           
this.isInsertCol = isInsertCol;
       
}

       
/**
         * Returns the row index where a dropped item should be placed in the
         * table. Interpretation of the value depends on the return of
         * <code>isInsertRow()</code>. If that method returns
         * <code>true</code> this value indicates the index where a new
         * row should be inserted. Otherwise, it represents the value
         * of an existing row on which the data was dropped. This index is
         * in terms of the view.
         * <p>
         * <code>-1</code> indicates that the drop occurred over empty space,
         * and no row could be calculated.
         *
         * @return the drop row
         */

       
public int getRow() {
           
return row;
       
}

       
/**
         * Returns the column index where a dropped item should be placed in the
         * table. Interpretation of the value depends on the return of
         * <code>isInsertColumn()</code>. If that method returns
         * <code>true</code> this value indicates the index where a new
         * column should be inserted. Otherwise, it represents the value
         * of an existing column on which the data was dropped. This index is
         * in terms of the view.
         * <p>
         * <code>-1</code> indicates that the drop occurred over empty space,
         * and no column could be calculated.
         *
         * @return the drop row
         */

       
public int getColumn() {
           
return col;
       
}

       
/**
         * Returns whether or not this location represents an insert
         * of a row.
         *
         * @return whether or not this is an insert row
         */

       
public boolean isInsertRow() {
           
return isInsertRow;
       
}

       
/**
         * Returns whether or not this location represents an insert
         * of a column.
         *
         * @return whether or not this is an insert column
         */

       
public boolean isInsertColumn() {
           
return isInsertCol;
       
}

       
/**
         * Returns a string representation of this drop location.
         * This method is intended to be used for debugging purposes,
         * and the content and format of the returned string may vary
         * between implementations.
         *
         * @return a string representation of this drop location
         */

       
public String toString() {
           
return getClass().getName()
                   
+ "[dropPoint=" + getDropPoint() + ","
                   
+ "row=" + row + ","
                   
+ "column=" + col + ","
                   
+ "insertRow=" + isInsertRow + ","
                   
+ "insertColumn=" + isInsertCol + "]";
       
}
   
}

//
// Constructors
//

   
/**
     * Constructs a default <code>JTable</code> that is initialized with a default
     * data model, a default column model, and a default selection
     * model.
     *
     * @see #createDefaultDataModel
     * @see #createDefaultColumnModel
     * @see #createDefaultSelectionModel
     */

   
public JTable() {
       
this(null, null, null);
   
}

   
/**
     * Constructs a <code>JTable</code> that is initialized with
     * <code>dm</code> as the data model, a default column model,
     * and a default selection model.
     *
     * @param dm        the data model for the table
     * @see #createDefaultColumnModel
     * @see #createDefaultSelectionModel
     */

   
public JTable(TableModel dm) {
       
this(dm, null, null);
   
}

   
/**
     * Constructs a <code>JTable</code> that is initialized with
     * <code>dm</code> as the data model, <code>cm</code>
     * as the column model, and a default selection model.
     *
     * @param dm        the data model for the table
     * @param cm        the column model for the table
     * @see #createDefaultSelectionModel
     */

   
public JTable(TableModel dm, TableColumnModel cm) {
       
this(dm, cm, null);
   
}

   
/**
     * Constructs a <code>JTable</code> that is initialized with
     * <code>dm</code> as the data model, <code>cm</code> as the
     * column model, and <code>sm</code> as the selection model.
     * If any of the parameters are <code>null</code> this method
     * will initialize the table with the corresponding default model.
     * The <code>autoCreateColumnsFromModel</code> flag is set to false
     * if <code>cm</code> is non-null, otherwise it is set to true
     * and the column model is populated with suitable
     * <code>TableColumns</code> for the columns in <code>dm</code>.
     *
     * @param dm        the data model for the table
     * @param cm        the column model for the table
     * @param sm        the row selection model for the table
     * @see #createDefaultDataModel
     * @see #createDefaultColumnModel
     * @see #createDefaultSelectionModel
     */

   
public JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
       
super();
        setLayout
(null);

        setFocusTraversalKeys
(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
                           
JComponent.getManagingFocusForwardTraversalKeys());
        setFocusTraversalKeys
(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
                           
JComponent.getManagingFocusBackwardTraversalKeys());
       
if (cm == null) {
            cm
= createDefaultColumnModel();
            autoCreateColumnsFromModel
= true;
       
}
        setColumnModel
(cm);

       
if (sm == null) {
            sm
= createDefaultSelectionModel();
       
}
        setSelectionModel
(sm);

   
// Set the model last, that way if the autoCreatColumnsFromModel has
   
// been set above, we will automatically populate an empty columnModel
   
// with suitable columns for the new model.
       
if (dm == null) {
            dm
= createDefaultDataModel();
       
}
        setModel
(dm);

        initializeLocalVars
();
        updateUI
();
   
}

   
/**
     * Constructs a <code>JTable</code> with <code>numRows</code>
     * and <code>numColumns</code> of empty cells using
     * <code>DefaultTableModel</code>.  The columns will have
     * names of the form "A", "B", "C", etc.
     *
     * @param numRows           the number of rows the table holds
     * @param numColumns        the number of columns the table holds
     * @see javax.swing.table.DefaultTableModel
     */

   
public JTable(int numRows, int numColumns) {
       
this(new DefaultTableModel(numRows, numColumns));
   
}

   
/**
     * Constructs a <code>JTable</code> to display the values in the
     * <code>Vector</code> of <code>Vectors</code>, <code>rowData</code>,
     * with column names, <code>columnNames</code>.  The
     * <code>Vectors</code> contained in <code>rowData</code>
     * should contain the values for that row. In other words,
     * the value of the cell at row 1, column 5 can be obtained
     * with the following code:
     * <p>
     * <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
     * <p>
     * @param rowData           the data for the new table
     * @param columnNames       names of each column
     */

   
public JTable(Vector rowData, Vector columnNames) {
       
this(new DefaultTableModel(rowData, columnNames));
   
}

   
/**
     * Constructs a <code>JTable</code> to display the values in the two dimensional array,
     * <code>rowData</code>, with column names, <code>columnNames</code>.
     * <code>rowData</code> is an array of rows, so the value of the cell at row 1,
     * column 5 can be obtained with the following code:
     * <p>
     * <pre> rowData[1][5]; </pre>
     * <p>
     * All rows must be of the same length as <code>columnNames</code>.
     * <p>
     * @param rowData           the data for the new table
     * @param columnNames       names of each column
     */

   
public JTable(final Object[][] rowData, final Object[] columnNames) {
       
this(new AbstractTableModel() {
           
public String getColumnName(int column) { return columnNames[column].toString(); }
           
public int getRowCount() { return rowData.length; }
           
public int getColumnCount() { return columnNames.length; }
           
public Object getValueAt(int row, int col) { return rowData[row][col]; }
           
public boolean isCellEditable(int row, int column) { return true; }
           
public void setValueAt(Object value, int row, int col) {
                rowData
[row][col] = value;
                fireTableCellUpdated
(row, col);
           
}
       
});
   
}

   
/**
     * Calls the <code>configureEnclosingScrollPane</code> method.
     *
     * @see #configureEnclosingScrollPane
     */

   
public void addNotify() {
       
super.addNotify();
        configureEnclosingScrollPane
();
   
}

   
/**
     * If this <code>JTable</code> is the <code>viewportView</code> of an enclosing <code>JScrollPane</code>
     * (the usual situation), configure this <code>ScrollPane</code> by, amongst other things,
     * installing the table's <code>tableHeader</code> as the <code>columnHeaderView</code> of the scroll pane.
     * When a <code>JTable</code> is added to a <code>JScrollPane</code> in the usual way,
     * using <code>new JScrollPane(myTable)</code>, <code>addNotify</code> is
     * called in the <code>JTable</code> (when the table is added to the viewport).
     * <code>JTable</code>'s <code>addNotify</code> method in turn calls this method,
     * which is protected so that this default installation procedure can
     * be overridden by a subclass.
     *
     * @see #addNotify
     */

   
protected void configureEnclosingScrollPane() {
       
Container p = getParent();
       
if (p instanceof JViewport) {
           
Container gp = p.getParent();
           
if (gp instanceof JScrollPane) {
               
JScrollPane scrollPane = (JScrollPane)gp;
               
// Make certain we are the viewPort's view and not, for
               
// example, the rowHeaderView of the scrollPane -
               
// an implementor of fixed columns might do this.
               
JViewport viewport = scrollPane.getViewport();
               
if (viewport == null || viewport.getView() != this) {
                   
return;
               
}
                scrollPane
.setColumnHeaderView(getTableHeader());
               
// configure the scrollpane for any LAF dependent settings
                configureEnclosingScrollPaneUI
();
           
}
       
}
   
}

   
/**
     * This is a sub-part of configureEnclosingScrollPane() that configures
     * anything on the scrollpane that may change when the look and feel
     * changes. It needed to be split out from configureEnclosingScrollPane() so
     * that it can be called from updateUI() when the LAF changes without
     * causing the regression found in bug 6687962. This was because updateUI()
     * is called from the constructor which then caused
     * configureEnclosingScrollPane() to be called by the constructor which
     * changes its contract for any subclass that overrides it. So by splitting
     * it out in this way configureEnclosingScrollPaneUI() can be called both
     * from configureEnclosingScrollPane() and updateUI() in a safe manor.
     */

   
private void configureEnclosingScrollPaneUI() {
       
Container p = getParent();
       
if (p instanceof JViewport) {
           
Container gp = p.getParent();
           
if (gp instanceof JScrollPane) {
               
JScrollPane scrollPane = (JScrollPane)gp;
               
// Make certain we are the viewPort's view and not, for
               
// example, the rowHeaderView of the scrollPane -
               
// an implementor of fixed columns might do this.
               
JViewport viewport = scrollPane.getViewport();
               
if (viewport == null || viewport.getView() != this) {
                   
return;
               
}
               
//  scrollPane.getViewport().setBackingStoreEnabled(true);
               
Border border = scrollPane.getBorder();
               
if (border == null || border instanceof UIResource) {
                   
Border scrollPaneBorder =
                       
UIManager.getBorder("Table.scrollPaneBorder");
                   
if (scrollPaneBorder != null) {
                        scrollPane
.setBorder(scrollPaneBorder);
                   
}
               
}
               
// add JScrollBar corner component if available from LAF and not already set by the user
               
Component corner =
                        scrollPane
.getCorner(JScrollPane.UPPER_TRAILING_CORNER);
               
if (corner == null || corner instanceof UIResource){
                    corner
= null;
                   
Object componentClass = UIManager.get(
                           
"Table.scrollPaneCornerComponent");
                   
if (componentClass instanceof Class){
                       
try {
                            corner
= (Component)
                                   
((Class)componentClass).newInstance();
                       
} catch (Exception e) {
                           
// just ignore and don't set corner
                       
}
                   
}
                    scrollPane
.setCorner(JScrollPane.UPPER_TRAILING_CORNER,
                            corner
);
               
}
           
}
       
}
   
}

   
/**
     * Calls the <code>unconfigureEnclosingScrollPane</code> method.
     *
     * @see #unconfigureEnclosingScrollPane
     */

   
public void removeNotify() {
       
KeyboardFocusManager.getCurrentKeyboardFocusManager().
            removePropertyChangeListener
("permanentFocusOwner", editorRemover);
        editorRemover
= null;
        unconfigureEnclosingScrollPane
();
       
super.removeNotify();
   
}

   
/**
     * Reverses the effect of <code>configureEnclosingScrollPane</code>
     * by replacing the <code>columnHeaderView</code> of the enclosing
     * scroll pane with <code>null</code>. <code>JTable</code>'s
     * <code>removeNotify</code> method calls
     * this method, which is protected so that this default uninstallation
     * procedure can be overridden by a subclass.
     *
     * @see #removeNotify
     * @see #configureEnclosingScrollPane
     * @since 1.3
     */

   
protected void unconfigureEnclosingScrollPane() {
       
Container p = getParent();
       
if (p instanceof JViewport) {
           
Container gp = p.getParent();
           
if (gp instanceof JScrollPane) {
               
JScrollPane scrollPane = (JScrollPane)gp;
               
// Make certain we are the viewPort's view and not, for
               
// example, the rowHeaderView of the scrollPane -
               
// an implementor of fixed columns might do this.
               
JViewport viewport = scrollPane.getViewport();
               
if (viewport == null || viewport.getView() != this) {
                   
return;
               
}
                scrollPane
.setColumnHeaderView(null);
               
// remove ScrollPane corner if one was added by the LAF
               
Component corner =
                        scrollPane
.getCorner(JScrollPane.UPPER_TRAILING_CORNER);
               
if (corner instanceof UIResource){
                    scrollPane
.setCorner(JScrollPane.UPPER_TRAILING_CORNER,
                           
null);
               
}
           
}
       
}
   
}

   
void setUIProperty(String propertyName, Object value) {
       
if (propertyName == "rowHeight") {
           
if (!isRowHeightSet) {
                setRowHeight
(((Number)value).intValue());
                isRowHeightSet
= false;
           
}
           
return;
       
}
       
super.setUIProperty(propertyName, value);
   
}

//
// Static Methods
//

   
/**
     * Equivalent to <code>new JScrollPane(aTable)</code>.
     *
     * @deprecated As of Swing version 1.0.2,
     * replaced by <code>new JScrollPane(aTable)</code>.
     */

   
@Deprecated
   
static public JScrollPane createScrollPaneForTable(JTable aTable) {
       
return new JScrollPane(aTable);
   
}

//
// Table Attributes
//

   
/**
     * Sets the <code>tableHeader</code> working with this <code>JTable</code> to <code>newHeader</code>.
     * It is legal to have a <code>null</code> <code>tableHeader</code>.
     *
     * @param   tableHeader                       new tableHeader
     * @see     #getTableHeader
     * @beaninfo
     *  bound: true
     *  description: The JTableHeader instance which renders the column headers.
     */

   
public void setTableHeader(JTableHeader tableHeader) {
       
if (this.tableHeader != tableHeader) {
           
JTableHeader old = this.tableHeader;
           
// Release the old header
           
if (old != null) {
                old
.setTable(null);
           
}
           
this.tableHeader = tableHeader;
           
if (tableHeader != null) {
                tableHeader
.setTable(this);
           
}
            firePropertyChange
("tableHeader", old, tableHeader);
       
}
   
}

   
/**
     * Returns the <code>tableHeader</code> used by this <code>JTable</code>.
     *
     * @return  the <code>tableHeader</code> used by this table
     * @see     #setTableHeader
     */

   
public JTableHeader getTableHeader() {
       
return tableHeader;
   
}

   
/**
     * Sets the height, in pixels, of all cells to <code>rowHeight</code>,
     * revalidates, and repaints.
     * The height of the cells will be equal to the row height minus
     * the row margin.
     *
     * @param   rowHeight                       new row height
     * @exception IllegalArgumentException      if <code>rowHeight</code> is
     *                                          less than 1
     * @see     #getRowHeight
     * @beaninfo
     *  bound: true
     *  description: The height of the specified row.
     */

   
public void setRowHeight(int rowHeight) {
       
if (rowHeight <= 0) {
           
throw new IllegalArgumentException("New row height less than 1");
       
}
       
int old = this.rowHeight;
       
this.rowHeight = rowHeight;
        rowModel
= null;
       
if (sortManager != null) {
            sortManager
.modelRowSizes = null;
       
}
        isRowHeightSet
= true;
        resizeAndRepaint
();
        firePropertyChange
("rowHeight", old, rowHeight);
   
}

   
/**
     * Returns the height of a table row, in pixels.
     * The default row height is 16.0.
     *
     * @return  the height in pixels of a table row
     * @see     #setRowHeight
     */

   
public int getRowHeight() {
       
return rowHeight;
   
}

   
private SizeSequence getRowModel() {
       
if (rowModel == null) {
            rowModel
= new SizeSequence(getRowCount(), getRowHeight());
       
}
       
return rowModel;
   
}

   
/**
     * Sets the height for <code>row</code> to <code>rowHeight</code>,
     * revalidates, and repaints. The height of the cells in this row
     * will be equal to the row height minus the row margin.
     *
     * @param   row                             the row whose height is being
                                                changed
     * @param   rowHeight                       new row height, in pixels
     * @exception IllegalArgumentException      if <code>rowHeight</code> is
     *                                          less than 1
     * @beaninfo
     *  bound: true
     *  description: The height in pixels of the cells in <code>row</code>
     * @since 1.3
     */

   
public void setRowHeight(int row, int rowHeight) {
       
if (rowHeight <= 0) {
           
throw new IllegalArgumentException("New row height less than 1");
       
}
        getRowModel
().setSize(row, rowHeight);
       
if (sortManager != null) {
            sortManager
.setViewRowHeight(row, rowHeight);
       
}
        resizeAndRepaint
();
   
}

   
/**
     * Returns the height, in pixels, of the cells in <code>row</code>.
     * @param   row              the row whose height is to be returned
     * @return the height, in pixels, of the cells in the row
     * @since 1.3
     */

   
public int getRowHeight(int row) {
       
return (rowModel == null) ? getRowHeight() : rowModel.getSize(row);
   
}

   
/**
     * Sets the amount of empty space between cells in adjacent rows.
     *
     * @param  rowMargin  the number of pixels between cells in a row
     * @see     #getRowMargin
     * @beaninfo
     *  bound: true
     *  description: The amount of space between cells.
     */

   
public void setRowMargin(int rowMargin) {
       
int old = this.rowMargin;
       
this.rowMargin = rowMargin;
        resizeAndRepaint
();
        firePropertyChange
("rowMargin", old, rowMargin);
   
}

   
/**
     * Gets the amount of empty space, in pixels, between cells. Equivalent to:
     * <code>getIntercellSpacing().height</code>.
     * @return the number of pixels between cells in a row
     *
     * @see     #setRowMargin
     */

   
public int getRowMargin() {
       
return rowMargin;
   
}

   
/**
     * Sets the <code>rowMargin</code> and the <code>columnMargin</code> --
     * the height and width of the space between cells -- to
     * <code>intercellSpacing</code>.
     *
     * @param   intercellSpacing        a <code>Dimension</code>
     *                                  specifying the new width
     *                                  and height between cells
     * @see     #getIntercellSpacing
     * @beaninfo
     *  description: The spacing between the cells,
     *               drawn in the background color of the JTable.
     */

   
public void setIntercellSpacing(Dimension intercellSpacing) {
       
// Set the rowMargin here and columnMargin in the TableColumnModel
        setRowMargin
(intercellSpacing.height);
        getColumnModel
().setColumnMargin(intercellSpacing.width);

        resizeAndRepaint
();
   
}

   
/**
     * Returns the horizontal and vertical space between cells.
     * The default spacing is (1, 1), which provides room to draw the grid.
     *
     * @return  the horizontal and vertical spacing between cells
     * @see     #setIntercellSpacing
     */

   
public Dimension getIntercellSpacing() {
       
return new Dimension(getColumnModel().getColumnMargin(), rowMargin);
   
}

   
/**
     * Sets the color used to draw grid lines to <code>gridColor</code> and redisplays.
     * The default color is look and feel dependent.
     *
     * @param   gridColor                       the new color of the grid lines
     * @exception IllegalArgumentException      if <code>gridColor</code> is <code>null</code>
     * @see     #getGridColor
     * @beaninfo
     *  bound: true
     *  description: The grid color.
     */

   
public void setGridColor(Color gridColor) {
       
if (gridColor == null) {
           
throw new IllegalArgumentException("New color is null");
       
}
       
Color old = this.gridColor;
       
this.gridColor = gridColor;
        firePropertyChange
("gridColor", old, gridColor);
       
// Redraw
        repaint
();
   
}

   
/**
     * Returns the color used to draw grid lines.
     * The default color is look and feel dependent.
     *
     * @return  the color used to draw grid lines
     * @see     #setGridColor
     */

   
public Color getGridColor() {
       
return gridColor;
   
}

   
/**
     *  Sets whether the table draws grid lines around cells.
     *  If <code>showGrid</code> is true it does; if it is false it doesn't.
     *  There is no <code>getShowGrid</code> method as this state is held
     *  in two variables -- <code>showHorizontalLines</code> and <code>showVerticalLines</code> --
     *  each of which can be queried independently.
     *
     * @param   showGrid                 true if table view should draw grid lines
     *
     * @see     #setShowVerticalLines
     * @see     #setShowHorizontalLines
     * @beaninfo
     *  description: The color used to draw the grid lines.
     */

   
public void setShowGrid(boolean showGrid) {
        setShowHorizontalLines
(showGrid);
        setShowVerticalLines
(showGrid);

       
// Redraw
        repaint
();
   
}

   
/**
     *  Sets whether the table draws horizontal lines between cells.
     *  If <code>showHorizontalLines</code> is true it does; if it is false it doesn't.
     *
     * @param   showHorizontalLines      true if table view should draw horizontal lines
     * @see     #getShowHorizontalLines
     * @see     #setShowGrid
     * @see     #setShowVerticalLines
     * @beaninfo
     *  bound: true
     *  description: Whether horizontal lines should be drawn in between the cells.
     */

   
public void setShowHorizontalLines(boolean showHorizontalLines) {
       
boolean old = this.showHorizontalLines;
       
this.showHorizontalLines = showHorizontalLines;
        firePropertyChange
("showHorizontalLines", old, showHorizontalLines);

       
// Redraw
        repaint
();
   
}

   
/**
     *  Sets whether the table draws vertical lines between cells.
     *  If <code>showVerticalLines</code> is true it does; if it is false it doesn't.
     *
     * @param   showVerticalLines              true if table view should draw vertical lines
     * @see     #getShowVerticalLines
     * @see     #setShowGrid
     * @see     #setShowHorizontalLines
     * @beaninfo
     *  bound: true
     *  description: Whether vertical lines should be drawn in between the cells.
     */

   
public void setShowVerticalLines(boolean showVerticalLines) {
       
boolean old = this.showVerticalLines;
       
this.showVerticalLines = showVerticalLines;
        firePropertyChange
("showVerticalLines", old, showVerticalLines);
       
// Redraw
        repaint
();
   
}

   
/**
     * Returns true if the table draws horizontal lines between cells, false if it
     * doesn't. The default is true.
     *
     * @return  true if the table draws horizontal lines between cells, false if it
     *          doesn't
     * @see     #setShowHorizontalLines
     */

   
public boolean getShowHorizontalLines() {
       
return showHorizontalLines;
   
}

   
/**
     * Returns true if the table draws vertical lines between cells, false if it
     * doesn't. The default is true.
     *
     * @return  true if the table draws vertical lines between cells, false if it
     *          doesn't
     * @see     #setShowVerticalLines
     */

   
public boolean getShowVerticalLines() {
       
return showVerticalLines;
   
}

   
/**
     * Sets the table's auto resize mode when the table is resized.  For further
     * information on how the different resize modes work, see
     * {@link #doLayout}.
     *
     * @param   mode One of 5 legal values:
     *                   AUTO_RESIZE_OFF,
     *                   AUTO_RESIZE_NEXT_COLUMN,
     *                   AUTO_RESIZE_SUBSEQUENT_COLUMNS,
     *                   AUTO_RESIZE_LAST_COLUMN,
     *                   AUTO_RESIZE_ALL_COLUMNS
     *
     * @see     #getAutoResizeMode
     * @see     #doLayout
     * @beaninfo
     *  bound: true
     *  description: Whether the columns should adjust themselves automatically.
     *        enum: AUTO_RESIZE_OFF                JTable.AUTO_RESIZE_OFF
     *              AUTO_RESIZE_NEXT_COLUMN        JTable.AUTO_RESIZE_NEXT_COLUMN
     *              AUTO_RESIZE_SUBSEQUENT_COLUMNS JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS
     *              AUTO_RESIZE_LAST_COLUMN        JTable.AUTO_RESIZE_LAST_COLUMN
     *              AUTO_RESIZE_ALL_COLUMNS        JTable.AUTO_RESIZE_ALL_COLUMNS
     */

   
public void setAutoResizeMode(int mode) {
       
if ((mode == AUTO_RESIZE_OFF) ||
           
(mode == AUTO_RESIZE_NEXT_COLUMN) ||
           
(mode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) ||
           
(mode == AUTO_RESIZE_LAST_COLUMN) ||
           
(mode == AUTO_RESIZE_ALL_COLUMNS)) {
           
int old = autoResizeMode;
            autoResizeMode
= mode;
            resizeAndRepaint
();
           
if (tableHeader != null) {
                tableHeader
.resizeAndRepaint();
           
}
            firePropertyChange
("autoResizeMode", old, autoResizeMode);
       
}
   
}

   
/**
     * Returns the auto resize mode of the table.  The default mode
     * is AUTO_RESIZE_SUBSEQUENT_COLUMNS.
     *
     * @return  the autoResizeMode of the table
     *
     * @see     #setAutoResizeMode
     * @see     #doLayout
     */

   
public int getAutoResizeMode() {
       
return autoResizeMode;
   
}

   
/**
     * Sets this table's <code>autoCreateColumnsFromModel</code> flag.
     * This method calls <code>createDefaultColumnsFromModel</code> if
     * <code>autoCreateColumnsFromModel</code> changes from false to true.
     *
     * @param   autoCreateColumnsFromModel   true if <code>JTable</code> should automatically create columns
     * @see     #getAutoCreateColumnsFromModel
     * @see     #createDefaultColumnsFromModel
     * @beaninfo
     *  bound: true
     *  description: Automatically populates the columnModel when a new TableModel is submitted.
     */

   
public void setAutoCreateColumnsFromModel(boolean autoCreateColumnsFromModel) {
       
if (this.autoCreateColumnsFromModel != autoCreateColumnsFromModel) {
           
boolean old = this.autoCreateColumnsFromModel;
           
this.autoCreateColumnsFromModel = autoCreateColumnsFromModel;
           
if (autoCreateColumnsFromModel) {
                createDefaultColumnsFromModel
();
           
}
            firePropertyChange
("autoCreateColumnsFromModel", old, autoCreateColumnsFromModel);
       
}
   
}

   
/**
     * Determines whether the table will create default columns from the model.
     * If true, <code>setModel</code> will clear any existing columns and
     * create new columns from the new model.  Also, if the event in
     * the <code>tableChanged</code> notification specifies that the
     * entire table changed, then the columns will be rebuilt.
     * The default is true.
     *
     * @return  the autoCreateColumnsFromModel of the table
     * @see     #setAutoCreateColumnsFromModel
     * @see     #createDefaultColumnsFromModel
     */

   
public boolean getAutoCreateColumnsFromModel() {
       
return autoCreateColumnsFromModel;
   
}

   
/**
     * Creates default columns for the table from
     * the data model using the <code>getColumnCount</code> method
     * defined in the <code>TableModel</code> interface.
     * <p>
     * Clears any existing columns before creating the
     * new columns based on information from the model.
     *
     * @see     #getAutoCreateColumnsFromModel
     */

   
public void createDefaultColumnsFromModel() {
       
TableModel m = getModel();
       
if (m != null) {
           
// Remove any current columns
           
TableColumnModel cm = getColumnModel();
           
while (cm.getColumnCount() > 0) {
                cm
.removeColumn(cm.getColumn(0));
           
}

           
// Create new columns from the data model info
           
for (int i = 0; i < m.getColumnCount(); i++) {
               
TableColumn newColumn = new TableColumn(i);
                addColumn
(newColumn);
           
}
       
}
   
}

   
/**
     * Sets a default cell renderer to be used if no renderer has been set in
     * a <code>TableColumn</code>. If renderer is <code>null</code>,
     * removes the default renderer for this column class.
     *
     * @param  columnClass     set the default cell renderer for this columnClass
     * @param  renderer        default cell renderer to be used for this
     *                         columnClass
     * @see     #getDefaultRenderer
     * @see     #setDefaultEditor
     */

   
public void setDefaultRenderer(Class<?> columnClass, TableCellRenderer renderer) {
       
if (renderer != null) {
            defaultRenderersByColumnClass
.put(columnClass, renderer);
       
}
       
else {
            defaultRenderersByColumnClass
.remove(columnClass);
       
}
   
}

   
/**
     * Returns the cell renderer to be used when no renderer has been set in
     * a <code>TableColumn</code>. During the rendering of cells the renderer is fetched from
     * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
     * there is no entry for this <code>columnClass</code> the method returns
     * the entry for the most specific superclass. The <code>JTable</code> installs entries
     * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
     * or replaced.
     *
     * @param   columnClass   return the default cell renderer
     *                        for this columnClass
     * @return  the renderer for this columnClass
     * @see     #setDefaultRenderer
     * @see     #getColumnClass
     */

   
public TableCellRenderer getDefaultRenderer(Class<?> columnClass) {
       
if (columnClass == null) {
           
return null;
       
}
       
else {
           
Object renderer = defaultRenderersByColumnClass.get(columnClass);
           
if (renderer != null) {
               
return (TableCellRenderer)renderer;
           
}
           
else {
               
return getDefaultRenderer(columnClass.getSuperclass());
           
}
       
}
   
}

   
/**
     * Sets a default cell editor to be used if no editor has been set in
     * a <code>TableColumn</code>. If no editing is required in a table, or a
     * particular column in a table, uses the <code>isCellEditable</code>
     * method in the <code>TableModel</code> interface to ensure that this
     * <code>JTable</code> will not start an editor in these columns.
     * If editor is <code>null</code>, removes the default editor for this
     * column class.
     *
     * @param  columnClass  set the default cell editor for this columnClass
     * @param  editor   default cell editor to be used for this columnClass
     * @see     TableModel#isCellEditable
     * @see     #getDefaultEditor
     * @see     #setDefaultRenderer
     */

   
public void setDefaultEditor(Class<?> columnClass, TableCellEditor editor) {
       
if (editor != null) {
            defaultEditorsByColumnClass
.put(columnClass, editor);
       
}
       
else {
            defaultEditorsByColumnClass
.remove(columnClass);
       
}
   
}

   
/**
     * Returns the editor to be used when no editor has been set in
     * a <code>TableColumn</code>. During the editing of cells the editor is fetched from
     * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
     * there is no entry for this <code>columnClass</code> the method returns
     * the entry for the most specific superclass. The <code>JTable</code> installs entries
     * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
     * or replaced.
     *
     * @param   columnClass  return the default cell editor for this columnClass
     * @return the default cell editor to be used for this columnClass
     * @see     #setDefaultEditor
     * @see     #getColumnClass
     */

   
public TableCellEditor getDefaultEditor(Class<?> columnClass) {
       
if (columnClass == null) {
           
return null;
       
}
       
else {
           
Object editor = defaultEditorsByColumnClass.get(columnClass);
           
if (editor != null) {
               
return (TableCellEditor)editor;
           
}
           
else {
               
return getDefaultEditor(columnClass.getSuperclass());
           
}
       
}
   
}

   
/**
     * Turns on or off automatic drag handling. In order to enable automatic
     * drag handling, this property should be set to {@code true}, and the
     * table's {@code TransferHandler} needs to be {@code non-null}.
     * The default value of the {@code dragEnabled} property is {@code false}.
     * <p>
     * The job of honoring this property, and recognizing a user drag gesture,
     * lies with the look and feel implementation, and in particular, the table's
     * {@code TableUI}. When automatic drag handling is enabled, most look and
     * feels (including those that subclass {@code BasicLookAndFeel}) begin a
     * drag and drop operation whenever the user presses the mouse button over
     * an item (in single selection mode) or a selection (in other selection
     * modes) and then moves the mouse a few pixels. Setting this property to
     * {@code true} can therefore have a subtle effect on how selections behave.
     * <p>
     * If a look and feel is used that ignores this property, you can still
     * begin a drag and drop operation by calling {@code exportAsDrag} on the
     * table's {@code TransferHandler}.
     *
     * @param b whether or not to enable automatic drag handling
     * @exception HeadlessException if
     *            <code>b</code> is <code>true</code> and
     *            <code>GraphicsEnvironment.isHeadless()</code>
     *            returns <code>true</code>
     * @see java.awt.GraphicsEnvironment#isHeadless
     * @see #getDragEnabled
     * @see #setTransferHandler
     * @see TransferHandler
     * @since 1.4
     *
     * @beaninfo
     *  description: determines whether automatic drag handling is enabled
     *        bound: false
     */

   
public void setDragEnabled(boolean b) {
       
if (b && GraphicsEnvironment.isHeadless()) {
           
throw new HeadlessException();
       
}
        dragEnabled
= b;
   
}

   
/**
     * Returns whether or not automatic drag handling is enabled.
     *
     * @return the value of the {@code dragEnabled} property
     * @see #setDragEnabled
     * @since 1.4
     */

   
public boolean getDragEnabled() {
       
return dragEnabled;
   
}

   
/**
     * Sets the drop mode for this component. For backward compatibility,
     * the default for this property is <code>DropMode.USE_SELECTION</code>.
     * Usage of one of the other modes is recommended, however, for an
     * improved user experience. <code>DropMode.ON</code>, for instance,
     * offers similar behavior of showing items as selected, but does so without
     * affecting the actual selection in the table.
     * <p>
     * <code>JTable</code> supports the following drop modes:
     * <ul>
     *    <li><code>DropMode.USE_SELECTION</code></li>
     *    <li><code>DropMode.ON</code></li>
     *    <li><code>DropMode.INSERT</code></li>
     *    <li><code>DropMode.INSERT_ROWS</code></li>
     *    <li><code>DropMode.INSERT_COLS</code></li>
     *    <li><code>DropMode.ON_OR_INSERT</code></li>
     *    <li><code>DropMode.ON_OR_INSERT_ROWS</code></li>
     *    <li><code>DropMode.ON_OR_INSERT_COLS</code></li>
     * </ul>
     * <p>
     * The drop mode is only meaningful if this component has a
     * <code>TransferHandler</code> that accepts drops.
     *
     * @param dropMode the drop mode to use
     * @throws IllegalArgumentException if the drop mode is unsupported
     *         or <code>null</code>
     * @see #getDropMode
     * @see #getDropLocation
     * @see #setTransferHandler
     * @see TransferHandler
     * @since 1.6
     */

   
public final void setDropMode(DropMode dropMode) {
       
if (dropMode != null) {
           
switch (dropMode) {
               
case USE_SELECTION:
               
case ON:
               
case INSERT:
               
case INSERT_ROWS:
               
case INSERT_COLS:
               
case ON_OR_INSERT:
               
case ON_OR_INSERT_ROWS:
               
case ON_OR_INSERT_COLS:
                   
this.dropMode = dropMode;
                   
return;
           
}
       
}

       
throw new IllegalArgumentException(dropMode + ": Unsupported drop mode for table");
   
}

   
/**
     * Returns the drop mode for this component.
     *
     * @return the drop mode for this component
     * @see #setDropMode
     * @since 1.6
     */

   
public final DropMode getDropMode() {
       
return dropMode;
   
}

   
/**
     * Calculates a drop location in this component, representing where a
     * drop at the given point should insert data.
     *
     * @param p the point to calculate a drop location for
     * @return the drop location, or <code>null</code>
     */

   
DropLocation dropLocationForPoint(Point p) {
       
DropLocation location = null;

       
int row = rowAtPoint(p);
       
int col = columnAtPoint(p);
       
boolean outside = Boolean.TRUE == getClientProperty("Table.isFileList")
                         
&& SwingUtilities2.pointOutsidePrefSize(this, row, col, p);

       
Rectangle rect = getCellRect(row, col, true);
       
Section xSection, ySection;
       
boolean between = false;
       
boolean ltr = getComponentOrientation().isLeftToRight();

       
switch(dropMode) {
           
case USE_SELECTION:
           
case ON:
               
if (row == -1 || col == -1 || outside) {
                    location
= new DropLocation(p, -1, -1, false, false);
               
} else {
                    location
= new DropLocation(p, row, col, false, false);
               
}
               
break;
           
case INSERT:
               
if (row == -1 && col == -1) {
                    location
= new DropLocation(p, 0, 0, true, true);
                   
break;
               
}

                xSection
= SwingUtilities2.liesInHorizontal(rect, p, ltr, true);

               
if (row == -1) {
                   
if (xSection == LEADING) {
                        location
= new DropLocation(p, getRowCount(), col, true, true);
                   
} else if (xSection == TRAILING) {
                        location
= new DropLocation(p, getRowCount(), col + 1, true, true);
                   
} else {
                        location
= new DropLocation(p, getRowCount(), col, true, false);
                   
}
               
} else if (xSection == LEADING || xSection == TRAILING) {
                    ySection
= SwingUtilities2.liesInVertical(rect, p, true);
                   
if (ySection == LEADING) {
                        between
= true;
                   
} else if (ySection == TRAILING) {
                        row
++;
                        between
= true;
                   
}

                    location
= new DropLocation(p, row,
                                                xSection
== TRAILING ? col + 1 : col,
                                                between
, true);
               
} else {
                   
if (SwingUtilities2.liesInVertical(rect, p, false) == TRAILING) {
                        row
++;
                   
}

                    location
= new DropLocation(p, row, col, true, false);
               
}

               
break;
           
case INSERT_ROWS:
               
if (row == -1 && col == -1) {
                    location
= new DropLocation(p, -1, -1, false, false);
                   
break;
               
}

               
if (row == -1) {
                    location
= new DropLocation(p, getRowCount(), col, true, false);
                   
break;
               
}

               
if (SwingUtilities2.liesInVertical(rect, p, false) == TRAILING) {
                    row
++;
               
}

                location
= new DropLocation(p, row, col, true, false);
               
break;
           
case ON_OR_INSERT_ROWS:
               
if (row == -1 && col == -1) {
                    location
= new DropLocation(p, -1, -1, false, false);
                   
break;
               
}

               
if (row == -1) {
                    location
= new DropLocation(p, getRowCount(), col, true, false);
                   
break;
               
}

                ySection
= SwingUtilities2.liesInVertical(rect, p, true);
               
if (ySection == LEADING) {
                    between
= true;
               
} else if (ySection == TRAILING) {
                    row
++;
                    between
= true;
               
}

                location
= new DropLocation(p, row, col, between, false);
               
break;
           
case INSERT_COLS:
               
if (row == -1) {
                    location
= new DropLocation(p, -1, -1, false, false);
                   
break;
               
}

               
if (col == -1) {
                    location
= new DropLocation(p, getColumnCount(), col, false, true);
                   
break;
               
}

               
if (SwingUtilities2.liesInHorizontal(rect, p, ltr, false) == TRAILING) {
                    col
++;
               
}

                location
= new DropLocation(p, row, col, false, true);
               
break;
           
case ON_OR_INSERT_COLS:
               
if (row == -1) {
                    location
= new DropLocation(p, -1, -1, false, false);
                   
break;
               
}

               
if (col == -1) {
                    location
= new DropLocation(p, row, getColumnCount(), false, true);
                   
break;
               
}

                xSection
= SwingUtilities2.liesInHorizontal(rect, p, ltr, true);
               
if (xSection == LEADING) {
                    between
= true;
               
} else if (xSection == TRAILING) {
                    col
++;
                    between
= true;
               
}

                location
= new DropLocation(p, row, col, false, between);
               
break;
           
case ON_OR_INSERT:
               
if (row == -1 && col == -1) {
                    location
= new DropLocation(p, 0, 0, true, true);
                   
break;
               
}

                xSection
= SwingUtilities2.liesInHorizontal(rect, p, ltr, true);

               
if (row == -1) {
                   
if (xSection == LEADING) {
                        location
= new DropLocation(p, getRowCount(), col, true, true);
                   
} else if (xSection == TRAILING) {
                        location
= new DropLocation(p, getRowCount(), col + 1, true, true);
                   
} else {
                        location
= new DropLocation(p, getRowCount(), col, true, false);
                   
}

                   
break;
               
}

                ySection
= SwingUtilities2.liesInVertical(rect, p, true);
               
if (ySection == LEADING) {
                    between
= true;
               
} else if (ySection == TRAILING) {
                    row
++;
                    between
= true;
               
}

                location
= new DropLocation(p, row,
                                            xSection
== TRAILING ? col + 1 : col,
                                            between
,
                                            xSection
!= MIDDLE);

               
break;
           
default:
               
assert false : "Unexpected drop mode";
       
}

       
return location;
   
}

   
/**
     * Called to set or clear the drop location during a DnD operation.
     * In some cases, the component may need to use it's internal selection
     * temporarily to indicate the drop location. To help facilitate this,
     * this method returns and accepts as a parameter a state object.
     * This state object can be used to store, and later restore, the selection
     * state. Whatever this method returns will be passed back to it in
     * future calls, as the state parameter. If it wants the DnD system to
     * continue storing the same state, it must pass it back every time.
     * Here's how this is used:
     * <p>
     * Let's say that on the first call to this method the component decides
     * to save some state (because it is about to use the selection to show
     * a drop index). It can return a state object to the caller encapsulating
     * any saved selection state. On a second call, let's say the drop location
     * is being changed to something else. The component doesn't need to
     * restore anything yet, so it simply passes back the same state object
     * to have the DnD system continue storing it. Finally, let's say this
     * method is messaged with <code>null</code>. This means DnD
     * is finished with this component for now, meaning it should restore
     * state. At this point, it can use the state parameter to restore
     * said state, and of course return <code>null</code> since there's
     * no longer anything to store.
     *
     * @param location the drop location (as calculated by
     *        <code>dropLocationForPoint</code>) or <code>null</code>
     *        if there's no longer a valid drop location
     * @param state the state object saved earlier for this component,
     *        or <code>null</code>
     * @param forDrop whether or not the method is being called because an
     *        actual drop occurred
     * @return any saved state for this component, or <code>null</code> if none
     */

   
Object setDropLocation(TransferHandler.DropLocation location,
                           
Object state,
                           
boolean forDrop) {

       
Object retVal = null;
       
DropLocation tableLocation = (DropLocation)location;

       
if (dropMode == DropMode.USE_SELECTION) {
           
if (tableLocation == null) {
               
if (!forDrop && state != null) {
                    clearSelection
();

                   
int[] rows = (int[])((int[][])state)[0];
                   
int[] cols = (int[])((int[][])state)[1];
                   
int[] anchleads = (int[])((int[][])state)[2];

                   
for (int i = 0; i < rows.length; i++) {
                        addRowSelectionInterval
(rows[i], rows[i]);
                   
}

                   
for (int i = 0; i < cols.length; i++) {
                        addColumnSelectionInterval
(cols[i], cols[i]);
                   
}

                   
SwingUtilities2.setLeadAnchorWithoutSelection(
                            getSelectionModel
(), anchleads[1], anchleads[0]);

                   
SwingUtilities2.setLeadAnchorWithoutSelection(
                            getColumnModel
().getSelectionModel(),
                            anchleads
[3], anchleads[2]);
               
}
           
} else {
               
if (dropLocation == null) {
                    retVal
= new int[][]{
                        getSelectedRows
(),
                        getSelectedColumns
(),
                       
{getAdjustedIndex(getSelectionModel()
                             
.getAnchorSelectionIndex(), true),
                         getAdjustedIndex
(getSelectionModel()
                             
.getLeadSelectionIndex(), true),
                         getAdjustedIndex
(getColumnModel().getSelectionModel()
                             
.getAnchorSelectionIndex(), false),
                         getAdjustedIndex
(getColumnModel().getSelectionModel()
                             
.getLeadSelectionIndex(), false)}};
               
} else {
                    retVal
= state;
               
}

               
if (tableLocation.getRow() == -1) {
                    clearSelectionAndLeadAnchor
();
               
} else {
                    setRowSelectionInterval
(tableLocation.getRow(),
                                            tableLocation
.getRow());
                    setColumnSelectionInterval
(tableLocation.getColumn(),
                                               tableLocation
.getColumn());
               
}
           
}
       
}

       
DropLocation old = dropLocation;
        dropLocation
= tableLocation;
        firePropertyChange
("dropLocation", old, dropLocation);

       
return retVal;
   
}

   
/**
     * Returns the location that this component should visually indicate
     * as the drop location during a DnD operation over the component,
     * or {@code null} if no location is to currently be shown.
     * <p>
     * This method is not meant for querying the drop location
     * from a {@code TransferHandler}, as the drop location is only
     * set after the {@code TransferHandler}'s <code>canImport</code>
     * has returned and has allowed for the location to be shown.
     * <p>
     * When this property changes, a property change event with
     * name "dropLocation" is fired by the component.
     *
     * @return the drop location
     * @see #setDropMode
     * @see TransferHandler#canImport(TransferHandler.TransferSupport)
     * @since 1.6
     */

   
public final DropLocation getDropLocation() {
       
return dropLocation;
   
}

   
/**
     * Specifies whether a {@code RowSorter} should be created for the
     * table whenever its model changes.
     * <p>
     * When {@code setAutoCreateRowSorter(true)} is invoked, a {@code
     * TableRowSorter} is immediately created and installed on the
     * table.  While the {@code autoCreateRowSorter} property remains
     * {@code true}, every time the model is changed, a new {@code
     * TableRowSorter} is created and set as the table's row sorter.
     *
     * @param autoCreateRowSorter whether or not a {@code RowSorter}
     *        should be automatically created
     * @see javax.swing.table.TableRowSorter
     * @beaninfo
     *        bound: true
     *    preferred: true
     *  description: Whether or not to turn on sorting by default.
     * @since 1.6
     */

   
public void setAutoCreateRowSorter(boolean autoCreateRowSorter) {
       
boolean oldValue = this.autoCreateRowSorter;
       
this.autoCreateRowSorter = autoCreateRowSorter;
       
if (autoCreateRowSorter) {
            setRowSorter
(new TableRowSorter(getModel()));
       
}
        firePropertyChange
("autoCreateRowSorter", oldValue,
                           autoCreateRowSorter
);
   
}

   
/**
     * Returns {@code true} if whenever the model changes, a new
     * {@code RowSorter} should be created and installed
     * as the table's sorter; otherwise, returns {@code false}.
     *
     * @return true if a {@code RowSorter} should be created when
     *         the model changes
     * @since 1.6
     */

   
public boolean getAutoCreateRowSorter() {
       
return autoCreateRowSorter;
   
}

   
/**
     * Specifies whether the selection should be updated after sorting.
     * If true, on sorting the selection is reset such that
     * the same rows, in terms of the model, remain selected.  The default
     * is true.
     *
     * @param update whether or not to update the selection on sorting
     * @beaninfo
     *        bound: true
     *       expert: true
     *  description: Whether or not to update the selection on sorting
     * @since 1.6
     */

   
public void setUpdateSelectionOnSort(boolean update) {
       
if (updateSelectionOnSort != update) {
            updateSelectionOnSort
= update;
            firePropertyChange
("updateSelectionOnSort", !update, update);
       
}
   
}

   
/**
     * Returns true if the selection should be updated after sorting.
     *
     * @return whether to update the selection on a sort
     * @since 1.6
     */

   
public boolean getUpdateSelectionOnSort() {
       
return updateSelectionOnSort;
   
}

   
/**
     * Sets the <code>RowSorter</code>.  <code>RowSorter</code> is used
     * to provide sorting and filtering to a <code>JTable</code>.
     * <p>
     * This method clears the selection and resets any variable row heights.
     * <p>
     * If the underlying model of the <code>RowSorter</code> differs from
     * that of this <code>JTable</code> undefined behavior will result.
     *
     * @param sorter the <code>RowSorter</code>; <code>null</code> turns
     *        sorting off
     * @see javax.swing.table.TableRowSorter
     * @since 1.6
     */

   
public void setRowSorter(RowSorter<? extends TableModel> sorter) {
       
RowSorter<? extends TableModel> oldRowSorter = null;
       
if (sortManager != null) {
            oldRowSorter
= sortManager.sorter;
            sortManager
.dispose();
            sortManager
= null;
       
}
        rowModel
= null;
        clearSelectionAndLeadAnchor
();
       
if (sorter != null) {
            sortManager
= new SortManager(sorter);
       
}
        resizeAndRepaint
();
        firePropertyChange
("rowSorter", oldRowSorter, sorter);
        firePropertyChange
("sorter", oldRowSorter, sorter);
   
}

   
/**
     * Returns the object responsible for sorting.
     *
     * @return the object responsible for sorting
     * @since 1.6
     */

   
public RowSorter<? extends TableModel> getRowSorter() {
       
return (sortManager != null) ? sortManager.sorter : null;
   
}

//
// Selection methods
//
   
/**
     * Sets the table's selection mode to allow only single selections, a single
     * contiguous interval, or multiple intervals.
     * <P>
     * <bold>Note:</bold>
     * <code>JTable</code> provides all the methods for handling
     * column and row selection.  When setting states,
     * such as <code>setSelectionMode</code>, it not only
     * updates the mode for the row selection model but also sets similar
     * values in the selection model of the <code>columnModel</code>.
     * If you want to have the row and column selection models operating
     * in different modes, set them both directly.
     * <p>
     * Both the row and column selection models for <code>JTable</code>
     * default to using a <code>DefaultListSelectionModel</code>
     * so that <code>JTable</code> works the same way as the
     * <code>JList</code>. See the <code>setSelectionMode</code> method
     * in <code>JList</code> for details about the modes.
     *
     * @see JList#setSelectionMode
     * @beaninfo
     * description: The selection mode used by the row and column selection models.
     *        enum: SINGLE_SELECTION            ListSelectionModel.SINGLE_SELECTION
     *              SINGLE_INTERVAL_SELECTION   ListSelectionModel.SINGLE_INTERVAL_SELECTION
     *              MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
     */

   
public void setSelectionMode(int selectionMode) {
        clearSelection
();
        getSelectionModel
().setSelectionMode(selectionMode);
        getColumnModel
().getSelectionModel().setSelectionMode(selectionMode);
   
}

   
/**
     * Sets whether the rows in this model can be selected.
     *
     * @param rowSelectionAllowed   true if this model will allow row selection
     * @see #getRowSelectionAllowed
     * @beaninfo
     *  bound: true
     *    attribute: visualUpdate true
     *  description: If true, an entire row is selected for each selected cell.
     */

   
public void setRowSelectionAllowed(boolean rowSelectionAllowed) {
       
boolean old = this.rowSelectionAllowed;
       
this.rowSelectionAllowed = rowSelectionAllowed;
       
if (old != rowSelectionAllowed) {
            repaint
();
       
}
        firePropertyChange
("rowSelectionAllowed", old, rowSelectionAllowed);
   
}

   
/**
     * Returns true if rows can be selected.
     *
     * @return true if rows can be selected, otherwise false
     * @see #setRowSelectionAllowed
     */

   
public boolean getRowSelectionAllowed() {
       
return rowSelectionAllowed;
   
}

   
/**
     * Sets whether the columns in this model can be selected.
     *
     * @param columnSelectionAllowed   true if this model will allow column selection
     * @see #getColumnSelectionAllowed
     * @beaninfo
     *  bound: true
     *    attribute: visualUpdate true
     *  description: If true, an entire column is selected for each selected cell.
     */

   
public void setColumnSelectionAllowed(boolean columnSelectionAllowed) {
       
boolean old = columnModel.getColumnSelectionAllowed();
        columnModel
.setColumnSelectionAllowed(columnSelectionAllowed);
       
if (old != columnSelectionAllowed) {
            repaint
();
       
}
        firePropertyChange
("columnSelectionAllowed", old, columnSelectionAllowed);
   
}

   
/**
     * Returns true if columns can be selected.
     *
     * @return true if columns can be selected, otherwise false
     * @see #setColumnSelectionAllowed
     */

   
public boolean getColumnSelectionAllowed() {
       
return columnModel.getColumnSelectionAllowed();
   
}

   
/**
     * Sets whether this table allows both a column selection and a
     * row selection to exist simultaneously. When set,
     * the table treats the intersection of the row and column selection
     * models as the selected cells. Override <code>isCellSelected</code> to
     * change this default behavior. This method is equivalent to setting
     * both the <code>rowSelectionAllowed</code> property and
     * <code>columnSelectionAllowed</code> property of the
     * <code>columnModel</code> to the supplied value.
     *
     * @param  cellSelectionEnabled     true if simultaneous row and column
     *                                  selection is allowed
     * @see #getCellSelectionEnabled
     * @see #isCellSelected
     * @beaninfo
     *  bound: true
     *    attribute: visualUpdate true
     *  description: Select a rectangular region of cells rather than
     *               rows or columns.
     */

   
public void setCellSelectionEnabled(boolean cellSelectionEnabled) {
        setRowSelectionAllowed
(cellSelectionEnabled);
        setColumnSelectionAllowed
(cellSelectionEnabled);
       
boolean old = this.cellSelectionEnabled;
       
this.cellSelectionEnabled = cellSelectionEnabled;
        firePropertyChange
("cellSelectionEnabled", old, cellSelectionEnabled);
   
}

   
/**
     * Returns true if both row and column selection models are enabled.
     * Equivalent to <code>getRowSelectionAllowed() &&
     * getColumnSelectionAllowed()</code>.
     *
     * @return true if both row and column selection models are enabled
     *
     * @see #setCellSelectionEnabled
     */

   
public boolean getCellSelectionEnabled() {
       
return getRowSelectionAllowed() && getColumnSelectionAllowed();
   
}

   
/**
     *  Selects all rows, columns, and cells in the table.
     */

   
public void selectAll() {
       
// If I'm currently editing, then I should stop editing
       
if (isEditing()) {
            removeEditor
();
       
}
       
if (getRowCount() > 0 && getColumnCount() > 0) {
           
int oldLead;
           
int oldAnchor;
           
ListSelectionModel selModel;

            selModel
= selectionModel;
            selModel
.setValueIsAdjusting(true);
            oldLead
= getAdjustedIndex(selModel.getLeadSelectionIndex(), true);
            oldAnchor
= getAdjustedIndex(selModel.getAnchorSelectionIndex(), true);

            setRowSelectionInterval
(0, getRowCount()-1);

           
// this is done to restore the anchor and lead
           
SwingUtilities2.setLeadAnchorWithoutSelection(selModel, oldLead, oldAnchor);

            selModel
.setValueIsAdjusting(false);

            selModel
= columnModel.getSelectionModel();
            selModel
.setValueIsAdjusting(true);
            oldLead
= getAdjustedIndex(selModel.getLeadSelectionIndex(), false);
            oldAnchor
= getAdjustedIndex(selModel.getAnchorSelectionIndex(), false);

            setColumnSelectionInterval
(0, getColumnCount()-1);

           
// this is done to restore the anchor and lead
           
SwingUtilities2.setLeadAnchorWithoutSelection(selModel, oldLead, oldAnchor);

            selModel
.setValueIsAdjusting(false);
       
}
   
}

   
/**
     * Deselects all selected columns and rows.
     */

   
public void clearSelection() {
        selectionModel
.clearSelection();
        columnModel
.getSelectionModel().clearSelection();
   
}

   
private void clearSelectionAndLeadAnchor() {
        selectionModel
.setValueIsAdjusting(true);
        columnModel
.getSelectionModel().setValueIsAdjusting(true);

        clearSelection
();

        selectionModel
.setAnchorSelectionIndex(-1);
        selectionModel
.setLeadSelectionIndex(-1);
        columnModel
.getSelectionModel().setAnchorSelectionIndex(-1);
        columnModel
.getSelectionModel().setLeadSelectionIndex(-1);

        selectionModel
.setValueIsAdjusting(false);
        columnModel
.getSelectionModel().setValueIsAdjusting(false);
   
}

   
private int getAdjustedIndex(int index, boolean row) {
       
int compare = row ? getRowCount() : getColumnCount();
       
return index < compare ? index : -1;
   
}

   
private int boundRow(int row) throws IllegalArgumentException {
       
if (row < 0 || row >= getRowCount()) {
           
throw new IllegalArgumentException("Row index out of range");
       
}
       
return row;
   
}

   
private int boundColumn(int col) {
       
if (col< 0 || col >= getColumnCount()) {
           
throw new IllegalArgumentException("Column index out of range");
       
}
       
return col;
   
}

   
/**
     * Selects the rows from <code>index0</code> to <code>index1</code>,
     * inclusive.
     *
     * @exception IllegalArgumentException      if <code>index0</code> or
     *                                          <code>index1</code> lie outside
     *                                          [0, <code>getRowCount()</code>-1]
     * @param   index0 one end of the interval
     * @param   index1 the other end of the interval
     */

   
public void setRowSelectionInterval(int index0, int index1) {
        selectionModel
.setSelectionInterval(boundRow(index0), boundRow(index1));
   
}

   
/**
     * Selects the columns from <code>index0</code> to <code>index1</code>,
     * inclusive.
     *
     * @exception IllegalArgumentException      if <code>index0</code> or
     *                                          <code>index1</code> lie outside
     *                                          [0, <code>getColumnCount()</code>-1]
     * @param   index0 one end of the interval
     * @param   index1 the other end of the interval
     */

   
public void setColumnSelectionInterval(int index0, int index1) {
        columnModel
.getSelectionModel().setSelectionInterval(boundColumn(index0), boundColumn(index1));
   
}

   
/**
     * Adds the rows from <code>index0</code> to <code>index1</code>, inclusive, to
     * the current selection.
     *
     * @exception IllegalArgumentException      if <code>index0</code> or <code>index1</code>
     *                                          lie outside [0, <code>getRowCount()</code>-1]
     * @param   index0 one end of the interval
     * @param   index1 the other end of the interval
     */

   
public void addRowSelectionInterval(int index0, int index1) {
        selectionModel
.addSelectionInterval(boundRow(index0), boundRow(index1));
   
}

   
/**
     * Adds the columns from <code>index0</code> to <code>index1</code>,
     * inclusive, to the current selection.
     *
     * @exception IllegalArgumentException      if <code>index0</code> or
     *                                          <code>index1</code> lie outside
     *                                          [0, <code>getColumnCount()</code>-1]
     * @param   index0 one end of the interval
     * @param   index1 the other end of the interval
     */

   
public void addColumnSelectionInterval(int index0, int index1) {
        columnModel
.getSelectionModel().addSelectionInterval(boundColumn(index0), boundColumn(index1));
   
}

   
/**
     * Deselects the rows from <code>index0</code> to <code>index1</code>, inclusive.
     *
     * @exception IllegalArgumentException      if <code>index0</code> or
     *                                          <code>index1</code> lie outside
     *                                          [0, <code>getRowCount()</code>-1]
     * @param   index0 one end of the interval
     * @param   index1 the other end of the interval
     */

   
public void removeRowSelectionInterval(int index0, int index1) {
        selectionModel
.removeSelectionInterval(boundRow(index0), boundRow(index1));
   
}

   
/**
     * Deselects the columns from <code>index0</code> to <code>index1</code>, inclusive.
     *
     * @exception IllegalArgumentException      if <code>index0</code> or
     *                                          <code>index1</code> lie outside
     *                                          [0, <code>getColumnCount()</code>-1]
     * @param   index0 one end of the interval
     * @param   index1 the other end of the interval
     */

   
public void removeColumnSelectionInterval(int index0, int index1) {
        columnModel
.getSelectionModel().removeSelectionInterval(boundColumn(index0), boundColumn(index1));
   
}

   
/**
     * Returns the index of the first selected row, -1 if no row is selected.
     * @return the index of the first selected row
     */

   
public int getSelectedRow() {
       
return selectionModel.getMinSelectionIndex();
   
}

   
/**
     * Returns the index of the first selected column,
     * -1 if no column is selected.
     * @return the index of the first selected column
     */

   
public int getSelectedColumn() {
       
return columnModel.getSelectionModel().getMinSelectionIndex();
   
}

   
/**
     * Returns the indices of all selected rows.
     *
     * @return an array of integers containing the indices of all selected rows,
     *         or an empty array if no row is selected
     * @see #getSelectedRow
     */

   
public int[] getSelectedRows() {
       
int iMin = selectionModel.getMinSelectionIndex();
       
int iMax = selectionModel.getMaxSelectionIndex();

       
if ((iMin == -1) || (iMax == -1)) {
           
return new int[0];
       
}

       
int[] rvTmp = new int[1+ (iMax - iMin)];
       
int n = 0;
       
for(int i = iMin; i <= iMax; i++) {
           
if (selectionModel.isSelectedIndex(i)) {
                rvTmp
[n++] = i;
           
}
       
}
       
int[] rv = new int[n];
       
System.arraycopy(rvTmp, 0, rv, 0, n);
       
return rv;
   
}

   
/**
     * Returns the indices of all selected columns.
     *
     * @return an array of integers containing the indices of all selected columns,
     *         or an empty array if no column is selected
     * @see #getSelectedColumn
     */

   
public int[] getSelectedColumns() {
       
return columnModel.getSelectedColumns();
   
}

   
/**
     * Returns the number of selected rows.
     *
     * @return the number of selected rows, 0 if no rows are selected
     */

   
public int getSelectedRowCount() {
       
int iMin = selectionModel.getMinSelectionIndex();
       
int iMax = selectionModel.getMaxSelectionIndex();
       
int count = 0;

       
for(int i = iMin; i <= iMax; i++) {
           
if (selectionModel.isSelectedIndex(i)) {
                count
++;
           
}
       
}
       
return count;
   
}

   
/**
     * Returns the number of selected columns.
     *
     * @return the number of selected columns, 0 if no columns are selected
     */

   
public int getSelectedColumnCount() {
       
return columnModel.getSelectedColumnCount();
   
}

   
/**
     * Returns true if the specified index is in the valid range of rows,
     * and the row at that index is selected.
     *
     * @return true if <code>row</code> is a valid index and the row at
     *              that index is selected (where 0 is the first row)
     */

   
public boolean isRowSelected(int row) {
       
return selectionModel.isSelectedIndex(row);
   
}

   
/**
     * Returns true if the specified index is in the valid range of columns,
     * and the column at that index is selected.
     *
     * @param   column   the column in the column model
     * @return true if <code>column</code> is a valid index and the column at
     *              that index is selected (where 0 is the first column)
     */

   
public boolean isColumnSelected(int column) {
       
return columnModel.getSelectionModel().isSelectedIndex(column);
   
}

   
/**
     * Returns true if the specified indices are in the valid range of rows
     * and columns and the cell at the specified position is selected.
     * @param row   the row being queried
     * @param column  the column being queried
     *
     * @return true if <code>row</code> and <code>column</code> are valid indices
     *              and the cell at index <code>(row, column)</code> is selected,
     *              where the first row and first column are at index 0
     */

   
public boolean isCellSelected(int row, int column) {
       
if (!getRowSelectionAllowed() && !getColumnSelectionAllowed()) {
           
return false;
       
}
       
return (!getRowSelectionAllowed() || isRowSelected(row)) &&
               
(!getColumnSelectionAllowed() || isColumnSelected(column));
   
}

   
private void changeSelectionModel(ListSelectionModel sm, int index,
                                     
boolean toggle, boolean extend, boolean selected,
                                     
int anchor, boolean anchorSelected) {
       
if (extend) {
           
if (toggle) {
               
if (anchorSelected) {
                    sm
.addSelectionInterval(anchor, index);
               
} else {
                    sm
.removeSelectionInterval(anchor, index);
                   
// this is a Windows-only behavior that we want for file lists
                   
if (Boolean.TRUE == getClientProperty("Table.isFileList")) {
                        sm
.addSelectionInterval(index, index);
                        sm
.setAnchorSelectionIndex(anchor);
                   
}
               
}
           
}
           
else {
                sm
.setSelectionInterval(anchor, index);
           
}
       
}
       
else {
           
if (toggle) {
               
if (selected) {
                    sm
.removeSelectionInterval(index, index);
               
}
               
else {
                    sm
.addSelectionInterval(index, index);
               
}
           
}
           
else {
                sm
.setSelectionInterval(index, index);
           
}
       
}
   
}

   
/**
     * Updates the selection models of the table, depending on the state of the
     * two flags: <code>toggle</code> and <code>extend</code>. Most changes
     * to the selection that are the result of keyboard or mouse events received
     * by the UI are channeled through this method so that the behavior may be
     * overridden by a subclass. Some UIs may need more functionality than
     * this method provides, such as when manipulating the lead for discontiguous
     * selection, and may not call into this method for some selection changes.
     * <p>
     * This implementation uses the following conventions:
     * <ul>
     * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>false</em>.
     *      Clear the previous selection and ensure the new cell is selected.
     * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>true</em>.
     *      Extend the previous selection from the anchor to the specified cell,
     *      clearing all other selections.
     * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>false</em>.
     *      If the specified cell is selected, deselect it. If it is not selected, select it.
     * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>true</em>.
     *      Apply the selection state of the anchor to all cells between it and the
     *      specified cell.
     * </ul>
     * @param  rowIndex   affects the selection at <code>row</code>
     * @param  columnIndex  affects the selection at <code>column</code>
     * @param  toggle  see description above
     * @param  extend  if true, extend the current selection
     *
     * @since 1.3
     */

   
public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
       
ListSelectionModel rsm = getSelectionModel();
       
ListSelectionModel csm = getColumnModel().getSelectionModel();

       
int anchorRow = getAdjustedIndex(rsm.getAnchorSelectionIndex(), true);
       
int anchorCol = getAdjustedIndex(csm.getAnchorSelectionIndex(), false);

       
boolean anchorSelected = true;

       
if (anchorRow == -1) {
           
if (getRowCount() > 0) {
                anchorRow
= 0;
           
}
            anchorSelected
= false;
       
}

       
if (anchorCol == -1) {
           
if (getColumnCount() > 0) {
                anchorCol
= 0;
           
}
            anchorSelected
= false;
       
}

       
// Check the selection here rather than in each selection model.
       
// This is significant in cell selection mode if we are supposed
       
// to be toggling the selection. In this case it is better to
       
// ensure that the cell's selection state will indeed be changed.
       
// If this were done in the code for the selection model it
       
// might leave a cell in selection state if the row was
       
// selected but the column was not - as it would toggle them both.
       
boolean selected = isCellSelected(rowIndex, columnIndex);
        anchorSelected
= anchorSelected && isCellSelected(anchorRow, anchorCol);

        changeSelectionModel
(csm, columnIndex, toggle, extend, selected,
                             anchorCol
, anchorSelected);
        changeSelectionModel
(rsm, rowIndex, toggle, extend, selected,
                             anchorRow
, anchorSelected);

       
// Scroll after changing the selection as blit scrolling is immediate,
       
// so that if we cause the repaint after the scroll we end up painting
       
// everything!
       
if (getAutoscrolls()) {
           
Rectangle cellRect = getCellRect(rowIndex, columnIndex, false);
           
if (cellRect != null) {
                scrollRectToVisible
(cellRect);
           
}
       
}
   
}

   
/**
     * Returns the foreground color for selected cells.
     *
     * @return the <code>Color</code> object for the foreground property
     * @see #setSelectionForeground
     * @see #setSelectionBackground
     */

   
public Color getSelectionForeground() {
       
return selectionForeground;
   
}

   
/**
     * Sets the foreground color for selected cells.  Cell renderers
     * can use this color to render text and graphics for selected
     * cells.
     * <p>
     * The default value of this property is defined by the look
     * and feel implementation.
     * <p>
     * This is a <a href="http://java.sun.com/docs/books/tutorial/javabeans/whatis/beanDefinition.html">JavaBeans</a> bound property.
     *
     * @param selectionForeground  the <code>Color</code> to use in the foreground
     *                             for selected list items
     * @see #getSelectionForeground
     * @see #setSelectionBackground
     * @see #setForeground
     * @see #setBackground
     * @see #setFont
     * @beaninfo
     *       bound: true
     * description: A default foreground color for selected cells.
     */

   
public void setSelectionForeground(Color selectionForeground) {
       
Color old = this.selectionForeground;
       
this.selectionForeground = selectionForeground;
        firePropertyChange
("selectionForeground", old, selectionForeground);
       
if ( !selectionForeground.equals(old) )
       
{
            repaint
();
       
}
   
}

   
/**
     * Returns the background color for selected cells.
     *
     * @return the <code>Color</code> used for the background of selected list items
     * @see #setSelectionBackground
     * @see #setSelectionForeground
     */

   
public Color getSelectionBackground() {
       
return selectionBackground;
   
}

   
/**
     * Sets the background color for selected cells.  Cell renderers
     * can use this color to the fill selected cells.
     * <p>
     * The default value of this property is defined by the look
     * and feel implementation.
     * <p>
     * This is a <a href="http://java.sun.com/docs/books/tutorial/javabeans/whatis/beanDefinition.html">JavaBeans</a> bound property.
     *
     * @param selectionBackground  the <code>Color</code> to use for the background
     *                             of selected cells
     * @see #getSelectionBackground
     * @see #setSelectionForeground
     * @see #setForeground
     * @see #setBackground
     * @see #setFont
     * @beaninfo
     *       bound: true
     * description: A default background color for selected cells.
     */

   
public void setSelectionBackground(Color selectionBackground) {
       
Color old = this.selectionBackground;
       
this.selectionBackground = selectionBackground;
        firePropertyChange
("selectionBackground", old, selectionBackground);
       
if ( !selectionBackground.equals(old) )
       
{
            repaint
();
       
}
   
}

   
/**
     * Returns the <code>TableColumn</code> object for the column in the table
     * whose identifier is equal to <code>identifier</code>, when compared using
     * <code>equals</code>.
     *
     * @return  the <code>TableColumn</code> object that matches the identifier
     * @exception IllegalArgumentException      if <code>identifier</code> is <code>null</code> or no <code>TableColumn</code> has this identifier
     *
     * @param   identifier                      the identifier object
     */

   
public TableColumn getColumn(Object identifier) {
       
TableColumnModel cm = getColumnModel();
       
int columnIndex = cm.getColumnIndex(identifier);
       
return cm.getColumn(columnIndex);
   
}

//
// Informally implement the TableModel interface.
//

   
/**
     * Maps the index of the column in the view at
     * <code>viewColumnIndex</code> to the index of the column
     * in the table model.  Returns the index of the corresponding
     * column in the model.  If <code>viewColumnIndex</code>
     * is less than zero, returns <code>viewColumnIndex</code>.
     *
     * @param   viewColumnIndex     the index of the column in the view
     * @return  the index of the corresponding column in the model
     *
     * @see #convertColumnIndexToView
     */

   
public int convertColumnIndexToModel(int viewColumnIndex) {
       
if (viewColumnIndex < 0) {
           
return viewColumnIndex;
       
}
       
return getColumnModel().getColumn(viewColumnIndex).getModelIndex();
   
}

   
/**
     * Maps the index of the column in the table model at
     * <code>modelColumnIndex</code> to the index of the column
     * in the view.  Returns the index of the
     * corresponding column in the view; returns -1 if this column is not
     * being displayed.  If <code>modelColumnIndex</code> is less than zero,
     * returns <code>modelColumnIndex</code>.
     *
     * @param   modelColumnIndex     the index of the column in the model
     * @return   the index of the corresponding column in the view
     *
     * @see #convertColumnIndexToModel
     */

   
public int convertColumnIndexToView(int modelColumnIndex) {
       
if (modelColumnIndex < 0) {
           
return modelColumnIndex;
       
}
       
TableColumnModel cm = getColumnModel();
       
for (int column = 0; column < getColumnCount(); column++) {
           
if (cm.getColumn(column).getModelIndex() == modelColumnIndex) {
               
return column;
           
}
       
}
       
return -1;
   
}

   
/**
     * Maps the index of the row in terms of the
     * <code>TableModel</code> to the view.  If the contents of the
     * model are not sorted the model and view indices are the same.
     *
     * @param modelRowIndex the index of the row in terms of the model
     * @return the index of the corresponding row in the view, or -1 if
     *         the row isn't visible
     * @throws IndexOutOfBoundsException if sorting is enabled and passed an
     *         index outside the number of rows of the <code>TableModel</code>
     * @see javax.swing.table.TableRowSorter
     * @since 1.6
     */

   
public int convertRowIndexToView(int modelRowIndex) {
       
RowSorter sorter = getRowSorter();
       
if (sorter != null) {
           
return sorter.convertRowIndexToView(modelRowIndex);
       
}
       
return modelRowIndex;
   
}

   
/**
     * Maps the index of the row in terms of the view to the
     * underlying <code>TableModel</code>.  If the contents of the
     * model are not sorted the model and view indices are the same.
     *
     * @param viewRowIndex the index of the row in the view
     * @return the index of the corresponding row in the model
     * @throws IndexOutOfBoundsException if sorting is enabled and passed an
     *         index outside the range of the <code>JTable</code> as
     *         determined by the method <code>getRowCount</code>
     * @see javax.swing.table.TableRowSorter
     * @see #getRowCount
     * @since 1.6
     */

   
public int convertRowIndexToModel(int viewRowIndex) {
       
RowSorter sorter = getRowSorter();
       
if (sorter != null) {
           
return sorter.convertRowIndexToModel(viewRowIndex);
       
}
       
return viewRowIndex;
   
}

   
/**
     * Returns the number of rows that can be shown in the
     * <code>JTable</code>, given unlimited space.  If a
     * <code>RowSorter</code> with a filter has been specified, the
     * number of rows returned may differ from that of the underlying
     * <code>TableModel</code>.
     *
     * @return the number of rows shown in the <code>JTable</code>
     * @see #getColumnCount
     */

   
public int getRowCount() {
       
RowSorter sorter = getRowSorter();
       
if (sorter != null) {
           
return sorter.getViewRowCount();
       
}
       
return getModel().getRowCount();
   
}

   
/**
     * Returns the number of columns in the column model. Note that this may
     * be different from the number of columns in the table model.
     *
     * @return  the number of columns in the table
     * @see #getRowCount
     * @see #removeColumn
     */

   
public int getColumnCount() {
       
return getColumnModel().getColumnCount();
   
}

   
/**
     * Returns the name of the column appearing in the view at
     * column position <code>column</code>.
     *
     * @param  column    the column in the view being queried
     * @return the name of the column at position <code>column</code>
                        in the view where the first column is column 0
     */

   
public String getColumnName(int column) {
       
return getModel().getColumnName(convertColumnIndexToModel(column));
   
}

   
/**
     * Returns the type of the column appearing in the view at
     * column position <code>column</code>.
     *
     * @param   column   the column in the view being queried
     * @return the type of the column at position <code>column</code>
     *          in the view where the first column is column 0
     */

   
public Class<?> getColumnClass(int column) {
       
return getModel().getColumnClass(convertColumnIndexToModel(column));
   
}

   
/**
     * Returns the cell value at <code>row</code> and <code>column</code>.
     * <p>
     * <b>Note</b>: The column is specified in the table view's display
     *              order, and not in the <code>TableModel</code>'s column
     *              order.  This is an important distinction because as the
     *              user rearranges the columns in the table,
     *              the column at a given index in the view will change.
     *              Meanwhile the user's actions never affect the model's
     *              column ordering.
     *
     * @param   row             the row whose value is to be queried
     * @param   column          the column whose value is to be queried
     * @return  the Object at the specified cell
     */

   
public Object getValueAt(int row, int column) {
       
return getModel().getValueAt(convertRowIndexToModel(row),
                                     convertColumnIndexToModel
(column));
   
}

   
/**
     * Sets the value for the cell in the table model at <code>row</code>
     * and <code>column</code>.
     * <p>
     * <b>Note</b>: The column is specified in the table view's display
     *              order, and not in the <code>TableModel</code>'s column
     *              order.  This is an important distinction because as the
     *              user rearranges the columns in the table,
     *              the column at a given index in the view will change.
     *              Meanwhile the user's actions never affect the model's
     *              column ordering.
     *
     * <code>aValue</code> is the new value.
     *
     * @param   aValue          the new value
     * @param   row             the row of the cell to be changed
     * @param   column          the column of the cell to be changed
     * @see #getValueAt
     */

   
public void setValueAt(Object aValue, int row, int column) {
        getModel
().setValueAt(aValue, convertRowIndexToModel(row),
                              convertColumnIndexToModel
(column));
   
}

   
/**
     * Returns true if the cell at <code>row</code> and <code>column</code>
     * is editable.  Otherwise, invoking <code>setValueAt</code> on the cell
     * will have no effect.
     * <p>
     * <b>Note</b>: The column is specified in the table view's display
     *              order, and not in the <code>TableModel</code>'s column
     *              order.  This is an important distinction because as the
     *              user rearranges the columns in the table,
     *              the column at a given index in the view will change.
     *              Meanwhile the user's actions never affect the model's
     *              column ordering.
     *
     *
     * @param   row      the row whose value is to be queried
     * @param   column   the column whose value is to be queried
     * @return  true if the cell is editable
     * @see #setValueAt
     */

   
public boolean isCellEditable(int row, int column) {
       
return getModel().isCellEditable(convertRowIndexToModel(row),
                                         convertColumnIndexToModel
(column));
   
}
//
// Adding and removing columns in the view
//

   
/**
     *  Appends <code>aColumn</code> to the end of the array of columns held by
     *  this <code>JTable</code>'s column model.
     *  If the column name of <code>aColumn</code> is <code>null</code>,
     *  sets the column name of <code>aColumn</code> to the name
     *  returned by <code>getModel().getColumnName()</code>.
     *  <p>
     *  To add a column to this <code>JTable</code> to display the
     *  <code>modelColumn</code>'th column of data in the model with a
     *  given <code>width</code>, <code>cellRenderer</code>,
     *  and <code>cellEditor</code> you can use:
     *  <pre>
     *
     *      addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
     *
     *  </pre>
     *  [Any of the <code>TableColumn</code> constructors can be used
     *  instead of this one.]
     *  The model column number is stored inside the <code>TableColumn</code>
     *  and is used during rendering and editing to locate the appropriates
     *  data values in the model. The model column number does not change
     *  when columns are reordered in the view.
     *
     *  @param  aColumn         the <code>TableColumn</code> to be added
     *  @see    #removeColumn
     */

   
public void addColumn(TableColumn aColumn) {
       
if (aColumn.getHeaderValue() == null) {
           
int modelColumn = aColumn.getModelIndex();
           
String columnName = getModel().getColumnName(modelColumn);
            aColumn
.setHeaderValue(columnName);
       
}
        getColumnModel
().addColumn(aColumn);
   
}

   
/**
     *  Removes <code>aColumn</code> from this <code>JTable</code>'s
     *  array of columns.  Note: this method does not remove the column
     *  of data from the model; it just removes the <code>TableColumn</code>
     *  that was responsible for displaying it.
     *
     *  @param  aColumn         the <code>TableColumn</code> to be removed
     *  @see    #addColumn
     */

   
public void removeColumn(TableColumn aColumn) {
        getColumnModel
().removeColumn(aColumn);
   
}

   
/**
     * Moves the column <code>column</code> to the position currently
     * occupied by the column <code>targetColumn</code> in the view.
     * The old column at <code>targetColumn</code> is
     * shifted left or right to make room.
     *
     * @param   column                  the index of column to be moved
     * @param   targetColumn            the new index of the column
     */

   
public void moveColumn(int column, int targetColumn) {
        getColumnModel
().moveColumn(column, targetColumn);
   
}

//
// Cover methods for various models and helper methods
//

   
/**
     * Returns the index of the column that <code>point</code> lies in,
     * or -1 if the result is not in the range
     * [0, <code>getColumnCount()</code>-1].
     *
     * @param   point   the location of interest
     * @return  the index of the column that <code>point</code> lies in,
     *          or -1 if the result is not in the range
     *          [0, <code>getColumnCount()</code>-1]
     * @see     #rowAtPoint
     */

   
public int columnAtPoint(Point point) {
       
int x = point.x;
       
if( !getComponentOrientation().isLeftToRight() ) {
            x
= getWidth() - x - 1;
       
}
       
return getColumnModel().getColumnIndexAtX(x);
   
}

   
/**
     * Returns the index of the row that <code>point</code> lies in,
     * or -1 if the result is not in the range
     * [0, <code>getRowCount()</code>-1].
     *
     * @param   point   the location of interest
     * @return  the index of the row that <code>point</code> lies in,
     *          or -1 if the result is not in the range
     *          [0, <code>getRowCount()</code>-1]
     * @see     #columnAtPoint
     */

   
public int rowAtPoint(Point point) {
       
int y = point.y;
       
int result = (rowModel == null) ?  y/getRowHeight() : rowModel.getIndex(y);
       
if (result < 0) {
           
return -1;
       
}
       
else if (result >= getRowCount()) {
           
return -1;
       
}
       
else {
           
return result;
       
}
   
}

   
/**
     * Returns a rectangle for the cell that lies at the intersection of
     * <code>row</code> and <code>column</code>.
     * If <code>includeSpacing</code> is true then the value returned
     * has the full height and width of the row and column
     * specified. If it is false, the returned rectangle is inset by the
     * intercell spacing to return the true bounds of the rendering or
     * editing component as it will be set during rendering.
     * <p>
     * If the column index is valid but the row index is less
     * than zero the method returns a rectangle with the
     * <code>y</code> and <code>height</code> values set appropriately
     * and the <code>x</code> and <code>width</code> values both set
     * to zero. In general, when either the row or column indices indicate a
     * cell outside the appropriate range, the method returns a rectangle
     * depicting the closest edge of the closest cell that is within
     * the table's range. When both row and column indices are out
     * of range the returned rectangle covers the closest
     * point of the closest cell.
     * <p>
     * In all cases, calculations that use this method to calculate
     * results along one axis will not fail because of anomalies in
     * calculations along the other axis. When the cell is not valid
     * the <code>includeSpacing</code> parameter is ignored.
     *
     * @param   row                   the row index where the desired cell
     *                                is located
     * @param   column                the column index where the desired cell
     *                                is located in the display; this is not
     *                                necessarily the same as the column index
     *                                in the data model for the table; the
     *                                {@link #convertColumnIndexToView(int)}
     *                                method may be used to convert a data
     *                                model column index to a display
     *                                column index
     * @param   includeSpacing        if false, return the true cell bounds -
     *                                computed by subtracting the intercell
     *                                spacing from the height and widths of
     *                                the column and row models
     *
     * @return  the rectangle containing the cell at location
     *          <code>row</code>,<code>column</code>
     * @see #getIntercellSpacing
     */

   
public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
       
Rectangle r = new Rectangle();
       
boolean valid = true;
       
if (row < 0) {
           
// y = height = 0;
            valid
= false;
       
}
       
else if (row >= getRowCount()) {
            r
.y = getHeight();
            valid
= false;
       
}
       
else {
            r
.height = getRowHeight(row);
            r
.y = (rowModel == null) ? row * r.height : rowModel.getPosition(row);
       
}

       
if (column < 0) {
           
if( !getComponentOrientation().isLeftToRight() ) {
                r
.x = getWidth();
           
}
           
// otherwise, x = width = 0;
            valid
= false;
       
}
       
else if (column >= getColumnCount()) {
           
if( getComponentOrientation().isLeftToRight() ) {
                r
.x = getWidth();
           
}
           
// otherwise, x = width = 0;
            valid
= false;
       
}
       
else {
           
TableColumnModel cm = getColumnModel();
           
if( getComponentOrientation().isLeftToRight() ) {
               
for(int i = 0; i < column; i++) {
                    r
.x += cm.getColumn(i).getWidth();
               
}
           
} else {
               
for(int i = cm.getColumnCount()-1; i > column; i--) {
                    r
.x += cm.getColumn(i).getWidth();
               
}
           
}
            r
.width = cm.getColumn(column).getWidth();
       
}

       
if (valid && !includeSpacing) {
           
// Bound the margins by their associated dimensions to prevent
           
// returning bounds with negative dimensions.
           
int rm = Math.min(getRowMargin(), r.height);
           
int cm = Math.min(getColumnModel().getColumnMargin(), r.width);
           
// This is not the same as grow(), it rounds differently.
            r
.setBounds(r.x + cm/2, r.y + rm/2, r.width - cm, r.height - rm);
       
}
       
return r;
   
}

   
private int viewIndexForColumn(TableColumn aColumn) {
       
TableColumnModel cm = getColumnModel();
       
for (int column = 0; column < cm.getColumnCount(); column++) {
           
if (cm.getColumn(column) == aColumn) {
               
return column;
           
}
       
}
       
return -1;
   
}

   
/**
     * Causes this table to lay out its rows and columns.  Overridden so
     * that columns can be resized to accomodate a change in the size of
     * a containing parent.
     * Resizes one or more of the columns in the table
     * so that the total width of all of this <code>JTable</code>'s
     * columns is equal to the width of the table.
     * <p>
     * Before the layout begins the method gets the
     * <code>resizingColumn</code> of the <code>tableHeader</code>.
     * When the method is called as a result of the resizing of an enclosing window,
     * the <code>resizingColumn</code> is <code>null</code>. This means that resizing
     * has taken place "outside" the <code>JTable</code> and the change -
     * or "delta" - should be distributed to all of the columns regardless
     * of this <code>JTable</code>'s automatic resize mode.
     * <p>
     * If the <code>resizingColumn</code> is not <code>null</code>, it is one of
     * the columns in the table that has changed size rather than
     * the table itself. In this case the auto-resize modes govern
     * the way the extra (or deficit) space is distributed
     * amongst the available columns.
     * <p>
     * The modes are:
     * <ul>
     * <li>  AUTO_RESIZE_OFF: Don't automatically adjust the column's
     * widths at all. Use a horizontal scrollbar to accomodate the
     * columns when their sum exceeds the width of the
     * <code>Viewport</code>.  If the <code>JTable</code> is not
     * enclosed in a <code>JScrollPane</code> this may
     * leave parts of the table invisible.
     * <li>  AUTO_RESIZE_NEXT_COLUMN: Use just the column after the
     * resizing column. This results in the "boundary" or divider
     * between adjacent cells being independently adjustable.
     * <li>  AUTO_RESIZE_SUBSEQUENT_COLUMNS: Use all columns after the
     * one being adjusted to absorb the changes.  This is the
     * default behavior.
     * <li>  AUTO_RESIZE_LAST_COLUMN: Automatically adjust the
     * size of the last column only. If the bounds of the last column
     * prevent the desired size from being allocated, set the
     * width of the last column to the appropriate limit and make
     * no further adjustments.
     * <li>  AUTO_RESIZE_ALL_COLUMNS: Spread the delta amongst all the columns
     * in the <code>JTable</code>, including the one that is being
     * adjusted.
     * </ul>
     * <p>
     * <bold>Note:</bold> When a <code>JTable</code> makes adjustments
     *   to the widths of the columns it respects their minimum and
     *   maximum values absolutely.  It is therefore possible that,
     *   even after this method is called, the total width of the columns
     *   is still not equal to the width of the table. When this happens
     *   the <code>JTable</code> does not put itself
     *   in AUTO_RESIZE_OFF mode to bring up a scroll bar, or break other
     *   commitments of its current auto-resize mode -- instead it
     *   allows its bounds to be set larger (or smaller) than the total of the
     *   column minimum or maximum, meaning, either that there
     *   will not be enough room to display all of the columns, or that the
     *   columns will not fill the <code>JTable</code>'s bounds.
     *   These respectively, result in the clipping of some columns
     *   or an area being painted in the <code>JTable</code>'s
     *   background color during painting.
     * <p>
     *   The mechanism for distributing the delta amongst the available
     *   columns is provided in a private method in the <code>JTable</code>
     *   class:
     * <pre>
     *   adjustSizes(long targetSize, final Resizable3 r, boolean inverse)
     * </pre>
     *   an explanation of which is provided in the following section.
     *   <code>Resizable3</code> is a private
     *   interface that allows any data structure containing a collection
     *   of elements with a size, preferred size, maximum size and minimum size
     *   to have its elements manipulated by the algorithm.
     * <p>
     * <H3> Distributing the delta </H3>
     * <p>
     * <H4> Overview </H4>
     * <P>
     * Call "DELTA" the difference between the target size and the
     * sum of the preferred sizes of the elements in r. The individual
     * sizes are calculated by taking the original preferred
     * sizes and adding a share of the DELTA - that share being based on
     * how far each preferred size is from its limiting bound (minimum or
     * maximum).
     * <p>
     * <H4>Definition</H4>
     * <P>
     * Call the individual constraints min[i], max[i], and pref[i].
     * <p>
     * Call their respective sums: MIN, MAX, and PREF.
     * <p>
     * Each new size will be calculated using:
     * <p>
     * <pre>
     *          size[i] = pref[i] + delta[i]
     * </pre>
     * where each individual delta[i] is calculated according to:
     * <p>
     * If (DELTA < 0) we are in shrink mode where:
     * <p>
     * <PRE>
     *                        DELTA
     *          delta[i] = ------------ * (pref[i] - min[i])
     *                     (PREF - MIN)
     * </PRE>
     * If (DELTA > 0) we are in expand mode where:
     * <p>
     * <PRE>
     *                        DELTA
     *          delta[i] = ------------ * (max[i] - pref[i])
     *                      (MAX - PREF)
     * </PRE>
     * <P>
     * The overall effect is that the total size moves that same percentage,
     * k, towards the total minimum or maximum and that percentage guarantees
     * accomodation of the required space, DELTA.
     *
     * <H4>Details</H4>
     * <P>
     * Naive evaluation of the formulae presented here would be subject to
     * the aggregated rounding errors caused by doing this operation in finite
     * precision (using ints). To deal with this, the multiplying factor above,
     * is constantly recalculated and this takes account of the rounding
     * errors in the previous iterations. The result is an algorithm that
     * produces a set of integers whose values exactly sum to the supplied
     * <code>targetSize</code>, and does so by spreading the rounding
     * errors evenly over the given elements.
     *
     * <H4>When the MAX and MIN bounds are hit</H4>
     * <P>
     * When <code>targetSize</code> is outside the [MIN, MAX] range,
     * the algorithm sets all sizes to their appropriate limiting value
     * (maximum or minimum).
     *
     */

   
public void doLayout() {
       
TableColumn resizingColumn = getResizingColumn();
       
if (resizingColumn == null) {
            setWidthsFromPreferredWidths
(false);
       
}
       
else {
           
// JTable behaves like a layout manger - but one in which the
           
// user can come along and dictate how big one of the children
           
// (columns) is supposed to be.

           
// A column has been resized and JTable may need to distribute
           
// any overall delta to other columns, according to the resize mode.
           
int columnIndex = viewIndexForColumn(resizingColumn);
           
int delta = getWidth() - getColumnModel().getTotalColumnWidth();
            accommodateDelta
(columnIndex, delta);
            delta
= getWidth() - getColumnModel().getTotalColumnWidth();

           
// If the delta cannot be completely accomodated, then the
           
// resizing column will have to take any remainder. This means
           
// that the column is not being allowed to take the requested
           
// width. This happens under many circumstances: For example,
           
// AUTO_RESIZE_NEXT_COLUMN specifies that any delta be distributed
           
// to the column after the resizing column. If one were to attempt
           
// to resize the last column of the table, there would be no
           
// columns after it, and hence nowhere to distribute the delta.
           
// It would then be given entirely back to the resizing column,
           
// preventing it from changing size.
           
if (delta != 0) {
                resizingColumn
.setWidth(resizingColumn.getWidth() + delta);
           
}

           
// At this point the JTable has to work out what preferred sizes
           
// would have resulted in the layout the user has chosen.
           
// Thereafter, during window resizing etc. it has to work off
           
// the preferred sizes as usual - the idea being that, whatever
           
// the user does, everything stays in synch and things don't jump
           
// around.
            setWidthsFromPreferredWidths
(true);
       
}

       
super.doLayout();
   
}

   
private TableColumn getResizingColumn() {
       
return (tableHeader == null) ? null
                                     
: tableHeader.getResizingColumn();
   
}

   
/**
     * Sizes the table columns to fit the available space.
     * @deprecated As of Swing version 1.0.3,
     * replaced by <code>doLayout()</code>.
     * @see #doLayout
     */

   
@Deprecated
   
public void sizeColumnsToFit(boolean lastColumnOnly) {
       
int oldAutoResizeMode = autoResizeMode;
        setAutoResizeMode
(lastColumnOnly ? AUTO_RESIZE_LAST_COLUMN
                                         
: AUTO_RESIZE_ALL_COLUMNS);
        sizeColumnsToFit
(-1);
        setAutoResizeMode
(oldAutoResizeMode);
   
}

   
/**
     * Obsolete as of Java 2 platform v1.4.  Please use the
     * <code>doLayout()</code> method instead.
     * @param resizingColumn    the column whose resizing made this adjustment
     *                          necessary or -1 if there is no such column
     * @see  #doLayout
     */

   
public void sizeColumnsToFit(int resizingColumn) {
       
if (resizingColumn == -1) {
            setWidthsFromPreferredWidths
(false);
       
}
       
else {
           
if (autoResizeMode == AUTO_RESIZE_OFF) {
               
TableColumn aColumn = getColumnModel().getColumn(resizingColumn);
                aColumn
.setPreferredWidth(aColumn.getWidth());
           
}
           
else {
               
int delta = getWidth() - getColumnModel().getTotalColumnWidth();
                accommodateDelta
(resizingColumn, delta);
                setWidthsFromPreferredWidths
(true);
           
}
       
}
   
}

   
private void setWidthsFromPreferredWidths(final boolean inverse) {
       
int totalWidth     = getWidth();
       
int totalPreferred = getPreferredSize().width;
       
int target = !inverse ? totalWidth : totalPreferred;

       
final TableColumnModel cm = columnModel;
       
Resizable3 r = new Resizable3() {
           
public int  getElementCount()      { return cm.getColumnCount(); }
           
public int  getLowerBoundAt(int i) { return cm.getColumn(i).getMinWidth(); }
           
public int  getUpperBoundAt(int i) { return cm.getColumn(i).getMaxWidth(); }
           
public int  getMidPointAt(int i)  {
               
if (!inverse) {
                   
return cm.getColumn(i).getPreferredWidth();
               
}
               
else {
                   
return cm.getColumn(i).getWidth();
               
}
           
}
           
public void setSizeAt(int s, int i) {
               
if (!inverse) {
                    cm
.getColumn(i).setWidth(s);
               
}
               
else {
                    cm
.getColumn(i).setPreferredWidth(s);
               
}
           
}
       
};

        adjustSizes
(target, r, inverse);
   
}


   
// Distribute delta over columns, as indicated by the autoresize mode.
   
private void accommodateDelta(int resizingColumnIndex, int delta) {
       
int columnCount = getColumnCount();
       
int from = resizingColumnIndex;
       
int to = columnCount;

       
// Use the mode to determine how to absorb the changes.
       
switch(autoResizeMode) {
           
case AUTO_RESIZE_NEXT_COLUMN:
               
from = from + 1;
                to
= Math.min(from + 1, columnCount); break;
           
case AUTO_RESIZE_SUBSEQUENT_COLUMNS:
               
from = from + 1;
                to
= columnCount; break;
           
case AUTO_RESIZE_LAST_COLUMN:
               
from = columnCount - 1;
                to
= from + 1; break;
           
case AUTO_RESIZE_ALL_COLUMNS:
               
from = 0;
                to
= columnCount; break;
           
default:
               
return;
       
}

       
final int start = from;
       
final int end = to;
       
final TableColumnModel cm = columnModel;
       
Resizable3 r = new Resizable3() {
           
public int  getElementCount()       { return end-start; }
           
public int  getLowerBoundAt(int i)  { return cm.getColumn(i+start).getMinWidth(); }
           
public int  getUpperBoundAt(int i)  { return cm.getColumn(i+start).getMaxWidth(); }
           
public int  getMidPointAt(int i)    { return cm.getColumn(i+start).getWidth(); }
           
public void setSizeAt(int s, int i) {        cm.getColumn(i+start).setWidth(s); }
       
};

       
int totalWidth = 0;
       
for(int i = from; i < to; i++) {
           
TableColumn aColumn = columnModel.getColumn(i);
           
int input = aColumn.getWidth();
            totalWidth
= totalWidth + input;
       
}

        adjustSizes
(totalWidth + delta, r, false);

       
return;
   
}

   
private interface Resizable2 {
       
public int  getElementCount();
       
public int  getLowerBoundAt(int i);
       
public int  getUpperBoundAt(int i);
       
public void setSizeAt(int newSize, int i);
   
}

   
private interface Resizable3 extends Resizable2 {
       
public int  getMidPointAt(int i);
   
}


   
private void adjustSizes(long target, final Resizable3 r, boolean inverse) {
       
int N = r.getElementCount();
       
long totalPreferred = 0;
       
for(int i = 0; i < N; i++) {
            totalPreferred
+= r.getMidPointAt(i);
       
}
       
Resizable2 s;
       
if ((target < totalPreferred) == !inverse) {
            s
= new Resizable2() {
               
public int  getElementCount()      { return r.getElementCount(); }
               
public int  getLowerBoundAt(int i) { return r.getLowerBoundAt(i); }
               
public int  getUpperBoundAt(int i) { return r.getMidPointAt(i); }
               
public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }

           
};
       
}
       
else {
            s
= new Resizable2() {
               
public int  getElementCount()      { return r.getElementCount(); }
               
public int  getLowerBoundAt(int i) { return r.getMidPointAt(i); }
               
public int  getUpperBoundAt(int i) { return r.getUpperBoundAt(i); }
               
public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }

           
};
       
}
        adjustSizes
(target, s, !inverse);
   
}

   
private void adjustSizes(long target, Resizable2 r, boolean limitToRange) {
       
long totalLowerBound = 0;
       
long totalUpperBound = 0;
       
for(int i = 0; i < r.getElementCount(); i++) {
            totalLowerBound
+= r.getLowerBoundAt(i);
            totalUpperBound
+= r.getUpperBoundAt(i);
       
}

       
if (limitToRange) {
            target
= Math.min(Math.max(totalLowerBound, target), totalUpperBound);
       
}

       
for(int i = 0; i < r.getElementCount(); i++) {
           
int lowerBound = r.getLowerBoundAt(i);
           
int upperBound = r.getUpperBoundAt(i);
           
// Check for zero. This happens when the distribution of the delta
           
// finishes early due to a series of "fixed" entries at the end.
           
// In this case, lowerBound == upperBound, for all subsequent terms.
           
int newSize;
           
if (totalLowerBound == totalUpperBound) {
                newSize
= lowerBound;
           
}
           
else {
               
double f = (double)(target - totalLowerBound)/(totalUpperBound - totalLowerBound);
                newSize
= (int)Math.round(lowerBound+f*(upperBound - lowerBound));
               
// We'd need to round manually in an all integer version.
               
// size[i] = (int)(((totalUpperBound - target) * lowerBound +
               
//     (target - totalLowerBound) * upperBound)/(totalUpperBound-totalLowerBound));
           
}
            r
.setSizeAt(newSize, i);
            target
-= newSize;
            totalLowerBound
-= lowerBound;
            totalUpperBound
-= upperBound;
       
}
   
}

   
/**
     * Overrides <code>JComponent</code>'s <code>getToolTipText</code>
     * method in order to allow the renderer's tips to be used
     * if it has text set.
     * <p>
     * <bold>Note:</bold> For <code>JTable</code> to properly display
     * tooltips of its renderers
     * <code>JTable</code> must be a registered component with the
     * <code>ToolTipManager</code>.
     * This is done automatically in <code>initializeLocalVars</code>,
     * but if at a later point <code>JTable</code> is told
     * <code>setToolTipText(null)</code> it will unregister the table
     * component, and no tips from renderers will display anymore.
     *
     * @see JComponent#getToolTipText
     */

   
public String getToolTipText(MouseEvent event) {
       
String tip = null;
       
Point p = event.getPoint();

       
// Locate the renderer under the event location
       
int hitColumnIndex = columnAtPoint(p);
       
int hitRowIndex = rowAtPoint(p);

       
if ((hitColumnIndex != -1) && (hitRowIndex != -1)) {
           
TableCellRenderer renderer = getCellRenderer(hitRowIndex, hitColumnIndex);
           
Component component = prepareRenderer(renderer, hitRowIndex, hitColumnIndex);

           
// Now have to see if the component is a JComponent before
           
// getting the tip
           
if (component instanceof JComponent) {
               
// Convert the event to the renderer's coordinate system
               
Rectangle cellRect = getCellRect(hitRowIndex, hitColumnIndex, false);
                p
.translate(-cellRect.x, -cellRect.y);
               
MouseEvent newEvent = new MouseEvent(component, event.getID(),
                                         
event.getWhen(), event.getModifiers(),
                                          p
.x, p.y,
                                         
event.getXOnScreen(),
                                         
event.getYOnScreen(),
                                         
event.getClickCount(),
                                         
event.isPopupTrigger(),
                                         
MouseEvent.NOBUTTON);

                tip
= ((JComponent)component).getToolTipText(newEvent);
           
}
       
}

       
// No tip from the renderer get our own tip
       
if (tip == null)
            tip
= getToolTipText();

       
return tip;
   
}

//
// Editing Support
//

   
/**
     * Sets whether editors in this JTable get the keyboard focus
     * when an editor is activated as a result of the JTable
     * forwarding keyboard events for a cell.
     * By default, this property is false, and the JTable
     * retains the focus unless the cell is clicked.
     *
     * @param surrendersFocusOnKeystroke true if the editor should get the focus
     *          when keystrokes cause the editor to be
     *          activated
     *
     *
     * @see #getSurrendersFocusOnKeystroke
     * @since 1.4
     */

   
public void setSurrendersFocusOnKeystroke(boolean surrendersFocusOnKeystroke) {
       
this.surrendersFocusOnKeystroke = surrendersFocusOnKeystroke;
   
}

   
/**
     * Returns true if the editor should get the focus
     * when keystrokes cause the editor to be activated
     *
     * @return  true if the editor should get the focus
     *          when keystrokes cause the editor to be
     *          activated
     *
     * @see #setSurrendersFocusOnKeystroke
     * @since 1.4
     */

   
public boolean getSurrendersFocusOnKeystroke() {
       
return surrendersFocusOnKeystroke;
   
}

   
/**
     * Programmatically starts editing the cell at <code>row</code> and
     * <code>column</code>, if those indices are in the valid range, and
     * the cell at those indices is editable.
     * Note that this is a convenience method for
     * <code>editCellAt(int, int, null)</code>.
     *
     * @param   row                             the row to be edited
     * @param   column                          the column to be edited
     * @return  false if for any reason the cell cannot be edited,
     *                or if the indices are invalid
     */

   
public boolean editCellAt(int row, int column) {
       
return editCellAt(row, column, null);
   
}

   
/**
     * Programmatically starts editing the cell at <code>row</code> and
     * <code>column</code>, if those indices are in the valid range, and
     * the cell at those indices is editable.
     * To prevent the <code>JTable</code> from
     * editing a particular table, column or cell value, return false from
     * the <code>isCellEditable</code> method in the <code>TableModel</code>
     * interface.
     *
     * @param   row     the row to be edited
     * @param   column  the column to be edited
     * @param   e       event to pass into <code>shouldSelectCell</code>;
     *                  note that as of Java 2 platform v1.2, the call to
     *                  <code>shouldSelectCell</code> is no longer made
     * @return  false if for any reason the cell cannot be edited,
     *                or if the indices are invalid
     */

   
public boolean editCellAt(int row, int column, EventObject e){
       
if (cellEditor != null && !cellEditor.stopCellEditing()) {
           
return false;
       
}

       
if (row < 0 || row >= getRowCount() ||
            column
< 0 || column >= getColumnCount()) {
           
return false;
       
}

       
if (!isCellEditable(row, column))
           
return false;

       
if (editorRemover == null) {
           
KeyboardFocusManager fm =
               
KeyboardFocusManager.getCurrentKeyboardFocusManager();
            editorRemover
= new CellEditorRemover(fm);
            fm
.addPropertyChangeListener("permanentFocusOwner", editorRemover);
       
}

       
TableCellEditor editor = getCellEditor(row, column);
       
if (editor != null && editor.isCellEditable(e)) {
            editorComp
= prepareEditor(editor, row, column);
           
if (editorComp == null) {
                removeEditor
();
               
return false;
           
}
            editorComp
.setBounds(getCellRect(row, column, false));
            add
(editorComp);
            editorComp
.validate();
            editorComp
.repaint();

            setCellEditor
(editor);
            setEditingRow
(row);
            setEditingColumn
(column);
            editor
.addCellEditorListener(this);

           
return true;
       
}
       
return false;
   
}

   
/**
     * Returns true if a cell is being edited.
     *
     * @return  true if the table is editing a cell
     * @see     #editingColumn
     * @see     #editingRow
     */

   
public boolean isEditing() {
       
return (cellEditor == null)? false : true;
   
}

   
/**
     * Returns the component that is handling the editing session.
     * If nothing is being edited, returns null.
     *
     * @return  Component handling editing session
     */

   
public Component getEditorComponent() {
       
return editorComp;
   
}

   
/**
     * Returns the index of the column that contains the cell currently
     * being edited.  If nothing is being edited, returns -1.
     *
     * @return  the index of the column that contains the cell currently
     *          being edited; returns -1 if nothing being edited
     * @see #editingRow
     */

   
public int getEditingColumn() {
       
return editingColumn;
   
}

   
/**
     * Returns the index of the row that contains the cell currently
     * being edited.  If nothing is being edited, returns -1.
     *
     * @return  the index of the row that contains the cell currently
     *          being edited; returns -1 if nothing being edited
     * @see #editingColumn
     */

   
public int getEditingRow() {
       
return editingRow;
   
}

//
// Managing TableUI
//

   
/**
     * Returns the L&F object that renders this component.
     *
     * @return the <code>TableUI</code> object that renders this component
     */

   
public TableUI getUI() {
       
return (TableUI)ui;
   
}

   
/**
     * Sets the L&F object that renders this component and repaints.
     *
     * @param ui  the TableUI L&F object
     * @see UIDefaults#getUI
     * @beaninfo
     *        bound: true
     *       hidden: true
     *    attribute: visualUpdate true
     *  description: The UI object that implements the Component's LookAndFeel.
     */

   
public void setUI(TableUI ui) {
       
if (this.ui != ui) {
           
super.setUI(ui);
            repaint
();
       
}
   
}

   
/**
     * Notification from the <code>UIManager</code> that the L&F has changed.
     * Replaces the current UI object with the latest version from the
     * <code>UIManager</code>.
     *
     * @see JComponent#updateUI
     */

   
public void updateUI() {
       
// Update the UIs of the cell renderers, cell editors and header renderers.
       
TableColumnModel cm = getColumnModel();
       
for(int column = 0; column < cm.getColumnCount(); column++) {
           
TableColumn aColumn = cm.getColumn(column);
           
SwingUtilities.updateRendererOrEditorUI(aColumn.getCellRenderer());
           
SwingUtilities.updateRendererOrEditorUI(aColumn.getCellEditor());
           
SwingUtilities.updateRendererOrEditorUI(aColumn.getHeaderRenderer());
       
}

       
// Update the UIs of all the default renderers.
       
Enumeration defaultRenderers = defaultRenderersByColumnClass.elements();
       
while (defaultRenderers.hasMoreElements()) {
           
SwingUtilities.updateRendererOrEditorUI(defaultRenderers.nextElement());
       
}

       
// Update the UIs of all the default editors.
       
Enumeration defaultEditors = defaultEditorsByColumnClass.elements();
       
while (defaultEditors.hasMoreElements()) {
           
SwingUtilities.updateRendererOrEditorUI(defaultEditors.nextElement());
       
}

       
// Update the UI of the table header
       
if (tableHeader != null && tableHeader.getParent() == null) {
            tableHeader
.updateUI();
       
}

       
// Update UI applied to parent ScrollPane
        configureEnclosingScrollPaneUI
();

        setUI
((TableUI)UIManager.getUI(this));
   
}

   
/**
     * Returns the suffix used to construct the name of the L&F class used to
     * render this component.
     *
     * @return the string "TableUI"
     * @see JComponent#getUIClassID
     * @see UIDefaults#getUI
     */

   
public String getUIClassID() {
       
return uiClassID;
   
}


//
// Managing models
//

   
/**
     * Sets the data model for this table to <code>newModel</code> and registers
     * with it for listener notifications from the new data model.
     *
     * @param   dataModel        the new data source for this table
     * @exception IllegalArgumentException      if <code>newModel</code> is <code>null</code>
     * @see     #getModel
     * @beaninfo
     *  bound: true
     *  description: The model that is the source of the data for this view.
     */

   
public void setModel(TableModel dataModel) {
       
if (dataModel == null) {
           
throw new IllegalArgumentException("Cannot set a null TableModel");
       
}
       
if (this.dataModel != dataModel) {
           
TableModel old = this.dataModel;
           
if (old != null) {
                old
.removeTableModelListener(this);
           
}
           
this.dataModel = dataModel;
            dataModel
.addTableModelListener(this);

            tableChanged
(new TableModelEvent(dataModel, TableModelEvent.HEADER_ROW));

            firePropertyChange
("model", old, dataModel);

           
if (getAutoCreateRowSorter()) {
                setRowSorter
(new TableRowSorter(dataModel));
           
}
       
}
   
}

   
/**
     * Returns the <code>TableModel</code> that provides the data displayed by this
     * <code>JTable</code>.
     *
     * @return  the <code>TableModel</code> that provides the data displayed by this <code>JTable</code>
     * @see     #setModel
     */

   
public TableModel getModel() {
       
return dataModel;
   
}

   
/**
     * Sets the column model for this table to <code>newModel</code> and registers
     * for listener notifications from the new column model. Also sets
     * the column model of the <code>JTableHeader</code> to <code>columnModel</code>.
     *
     * @param   columnModel        the new data source for this table
     * @exception IllegalArgumentException      if <code>columnModel</code> is <code>null</code>
     * @see     #getColumnModel
     * @beaninfo
     *  bound: true
     *  description: The object governing the way columns appear in the view.
     */

   
public void setColumnModel(TableColumnModel columnModel) {
       
if (columnModel == null) {
           
throw new IllegalArgumentException("Cannot set a null ColumnModel");
       
}
       
TableColumnModel old = this.columnModel;
       
if (columnModel != old) {
           
if (old != null) {
                old
.removeColumnModelListener(this);
           
}
           
this.columnModel = columnModel;
            columnModel
.addColumnModelListener(this);

           
// Set the column model of the header as well.
           
if (tableHeader != null) {
                tableHeader
.setColumnModel(columnModel);
           
}

            firePropertyChange
("columnModel", old, columnModel);
            resizeAndRepaint
();
       
}
   
}

   
/**
     * Returns the <code>TableColumnModel</code> that contains all column information
     * of this table.
     *
     * @return  the object that provides the column state of the table
     * @see     #setColumnModel
     */

   
public TableColumnModel getColumnModel() {
       
return columnModel;
   
}

   
/**
     * Sets the row selection model for this table to <code>newModel</code>
     * and registers for listener notifications from the new selection model.
     *
     * @param   newModel        the new selection model
     * @exception IllegalArgumentException      if <code>newModel</code> is <code>null</code>
     * @see     #getSelectionModel
     * @beaninfo
     *      bound: true
     *      description: The selection model for rows.
     */

   
public void setSelectionModel(ListSelectionModel newModel) {
       
if (newModel == null) {
           
throw new IllegalArgumentException("Cannot set a null SelectionModel");
       
}

       
ListSelectionModel oldModel = selectionModel;

       
if (newModel != oldModel) {
           
if (oldModel != null) {
                oldModel
.removeListSelectionListener(this);
           
}

            selectionModel
= newModel;
            newModel
.addListSelectionListener(this);

            firePropertyChange
("selectionModel", oldModel, newModel);
            repaint
();
       
}
   
}

   
/**
     * Returns the <code>ListSelectionModel</code> that is used to maintain row
     * selection state.
     *
     * @return  the object that provides row selection state, <code>null</code>
     *          if row selection is not allowed
     * @see     #setSelectionModel
     */

   
public ListSelectionModel getSelectionModel() {
       
return selectionModel;
   
}

//
// RowSorterListener
//

   
/**
     * <code>RowSorterListener</code> notification that the
     * <code>RowSorter</code> has changed in some way.
     *
     * @param e the <code>RowSorterEvent</code> describing the change
     * @throws NullPointerException if <code>e</code> is <code>null</code>
     * @since 1.6
     */

   
public void sorterChanged(RowSorterEvent e) {
       
if (e.getType() == RowSorterEvent.Type.SORT_ORDER_CHANGED) {
           
JTableHeader header = getTableHeader();
           
if (header != null) {
                header
.repaint();
           
}
       
}
       
else if (e.getType() == RowSorterEvent.Type.SORTED) {
            sorterChanged
= true;
           
if (!ignoreSortChange) {
                sortedTableChanged
(e, null);
           
}
       
}
   
}


   
/**
     * SortManager provides support for managing the selection and variable
     * row heights when sorting is enabled. This information is encapsulated
     * into a class to avoid bulking up JTable.
     */

   
private final class SortManager {
       
RowSorter<? extends TableModel> sorter;

       
// Selection, in terms of the model. This is lazily created
       
// as needed.
       
private ListSelectionModel modelSelection;
       
private int modelLeadIndex;
       
// Set to true while in the process of changing the selection.
       
// If this is true the selection change is ignored.
       
private boolean syncingSelection;
       
// Temporary cache of selection, in terms of model. This is only used
       
// if we don't need the full weight of modelSelection.
       
private int[] lastModelSelection;

       
// Heights of the rows in terms of the model.
       
private SizeSequence modelRowSizes;


       
SortManager(RowSorter<? extends TableModel> sorter) {
           
this.sorter = sorter;
            sorter
.addRowSorterListener(JTable.this);
       
}

       
/**
         * Disposes any resources used by this SortManager.
         */

       
public void dispose() {
           
if (sorter != null) {
                sorter
.removeRowSorterListener(JTable.this);
           
}
       
}

       
/**
         * Sets the height for a row at a specified index.
         */

       
public void setViewRowHeight(int viewIndex, int rowHeight) {
           
if (modelRowSizes == null) {
                modelRowSizes
= new SizeSequence(getModel().getRowCount(),
                                                 getRowHeight
());
           
}
            modelRowSizes
.setSize(convertRowIndexToModel(viewIndex),rowHeight);
       
}

       
/**
         * Invoked when the underlying model has completely changed.
         */

       
public void allChanged() {
            modelLeadIndex
= -1;
            modelSelection
= null;
            modelRowSizes
= null;
       
}

       
/**
         * Invoked when the selection, on the view, has changed.
         */

       
public void viewSelectionChanged(ListSelectionEvent e) {
           
if (!syncingSelection && modelSelection != null) {
                modelSelection
= null;
           
}
       
}

       
/**
         * Invoked when either the table model has changed, or the RowSorter
         * has changed. This is invoked prior to notifying the sorter of the
         * change.
         */

       
public void prepareForChange(RowSorterEvent sortEvent,
                                     
ModelChange change) {
           
if (getUpdateSelectionOnSort()) {
                cacheSelection
(sortEvent, change);
           
}
       
}

       
/**
         * Updates the internal cache of the selection based on the change.
         */

       
private void cacheSelection(RowSorterEvent sortEvent,
                                   
ModelChange change) {
           
if (sortEvent != null) {
               
// sort order changed. If modelSelection is null and filtering
               
// is enabled we need to cache the selection in terms of the
               
// underlying model, this will allow us to correctly restore
               
// the selection even if rows are filtered out.
               
if (modelSelection == null &&
                        sorter
.getViewRowCount() != getModel().getRowCount()) {
                    modelSelection
= new DefaultListSelectionModel();
                   
ListSelectionModel viewSelection = getSelectionModel();
                   
int min = viewSelection.getMinSelectionIndex();
                   
int max = viewSelection.getMaxSelectionIndex();
                   
int modelIndex;
                   
for (int viewIndex = min; viewIndex <= max; viewIndex++) {
                       
if (viewSelection.isSelectedIndex(viewIndex)) {
                            modelIndex
= convertRowIndexToModel(
                                    sortEvent
, viewIndex);
                           
if (modelIndex != -1) {
                                modelSelection
.addSelectionInterval(
                                    modelIndex
, modelIndex);
                           
}
                       
}
                   
}
                    modelIndex
= convertRowIndexToModel(sortEvent,
                            viewSelection
.getLeadSelectionIndex());
                   
SwingUtilities2.setLeadAnchorWithoutSelection(
                            modelSelection
, modelIndex, modelIndex);
               
} else if (modelSelection == null) {
                   
// Sorting changed, haven't cached selection in terms
                   
// of model and no filtering. Temporarily cache selection.
                    cacheModelSelection
(sortEvent);
               
}
           
} else if (change.allRowsChanged) {
               
// All the rows have changed, chuck any cached selection.
                modelSelection
= null;
           
} else if (modelSelection != null) {
               
// Table changed, reflect changes in cached selection model.
               
switch(change.type) {
               
case TableModelEvent.DELETE:
                    modelSelection
.removeIndexInterval(change.startModelIndex,
                                                       change
.endModelIndex);
                   
break;
               
case TableModelEvent.INSERT:
                    modelSelection
.insertIndexInterval(change.startModelIndex,
                                                       change
.endModelIndex,
                                                       
true);
                   
break;
               
default:
                   
break;
               
}
           
} else {
               
// table changed, but haven't cached rows, temporarily
               
// cache them.
                cacheModelSelection
(null);
           
}
       
}

       
private void cacheModelSelection(RowSorterEvent sortEvent) {
            lastModelSelection
= convertSelectionToModel(sortEvent);
            modelLeadIndex
= convertRowIndexToModel(sortEvent,
                        selectionModel
.getLeadSelectionIndex());
       
}

       
/**
         * Inovked when either the table has changed or the sorter has changed
         * and after the sorter has been notified. If necessary this will
         * reapply the selection and variable row heights.
         */

       
public void processChange(RowSorterEvent sortEvent,
                                 
ModelChange change,
                                 
boolean sorterChanged) {
           
if (change != null) {
               
if (change.allRowsChanged) {
                    modelRowSizes
= null;
                    rowModel
= null;
               
} else if (modelRowSizes != null) {
                   
if (change.type == TableModelEvent.INSERT) {
                        modelRowSizes
.insertEntries(change.startModelIndex,
                                                    change
.endModelIndex -
                                                    change
.startModelIndex + 1,
                                                    getRowHeight
());
                   
} else if (change.type == TableModelEvent.DELETE) {
                        modelRowSizes
.removeEntries(change.startModelIndex,
                                                    change
.endModelIndex -
                                                    change
.startModelIndex +1 );
                   
}
               
}
           
}
           
if (sorterChanged) {
                setViewRowHeightsFromModel
();
                restoreSelection
(change);
           
}
       
}

       
/**
         * Resets the variable row heights in terms of the view from
         * that of the variable row heights in terms of the model.
         */

       
private void setViewRowHeightsFromModel() {
           
if (modelRowSizes != null) {
                rowModel
.setSizes(getRowCount(), getRowHeight());
               
for (int viewIndex = getRowCount() - 1; viewIndex >= 0;
                         viewIndex
--) {
                   
int modelIndex = convertRowIndexToModel(viewIndex);
                    rowModel
.setSize(viewIndex,
                                     modelRowSizes
.getSize(modelIndex));
               
}
           
}
       
}

       
/**
         * Restores the selection from that in terms of the model.
         */

       
private void restoreSelection(ModelChange change) {
            syncingSelection
= true;
           
if (lastModelSelection != null) {
                restoreSortingSelection
(lastModelSelection,
                                        modelLeadIndex
, change);
                lastModelSelection
= null;
           
} else if (modelSelection != null) {
               
ListSelectionModel viewSelection = getSelectionModel();
                viewSelection
.setValueIsAdjusting(true);
                viewSelection
.clearSelection();
               
int min = modelSelection.getMinSelectionIndex();
               
int max = modelSelection.getMaxSelectionIndex();
               
int viewIndex;
               
for (int modelIndex = min; modelIndex <= max; modelIndex++) {
                   
if (modelSelection.isSelectedIndex(modelIndex)) {
                        viewIndex
= convertRowIndexToView(modelIndex);
                       
if (viewIndex != -1) {
                            viewSelection
.addSelectionInterval(viewIndex,
                                                               viewIndex
);
                       
}
                   
}
               
}
               
// Restore the lead
               
int viewLeadIndex = modelSelection.getLeadSelectionIndex();
               
if (viewLeadIndex != -1) {
                    viewLeadIndex
= convertRowIndexToView(viewLeadIndex);
               
}
               
SwingUtilities2.setLeadAnchorWithoutSelection(
                        viewSelection
, viewLeadIndex, viewLeadIndex);
                viewSelection
.setValueIsAdjusting(false);
           
}
            syncingSelection
= false;
       
}
   
}


   
/**
     * ModelChange is used when sorting to restore state, it corresponds
     * to data from a TableModelEvent.  The values are precalculated as
     * they are used extensively.
     */

   
private final class ModelChange {
       
// Starting index of the change, in terms of the model
       
int startModelIndex;

       
// Ending index of the change, in terms of the model
       
int endModelIndex;

       
// Type of change
       
int type;

       
// Number of rows in the model
       
int modelRowCount;

       
// The event that triggered this.
       
TableModelEvent event;

       
// Length of the change (end - start + 1)
       
int length;

       
// True if the event indicates all the contents have changed
       
boolean allRowsChanged;

       
ModelChange(TableModelEvent e) {
            startModelIndex
= Math.max(0, e.getFirstRow());
            endModelIndex
= e.getLastRow();
            modelRowCount
= getModel().getRowCount();
           
if (endModelIndex < 0) {
                endModelIndex
= Math.max(0, modelRowCount - 1);
           
}
            length
= endModelIndex - startModelIndex + 1;
            type
= e.getType();
           
event = e;
            allRowsChanged
= (e.getLastRow() == Integer.MAX_VALUE);
       
}
   
}

   
/**
     * Invoked when <code>sorterChanged</code> is invoked, or
     * when <code>tableChanged</code> is invoked and sorting is enabled.
     */

   
private void sortedTableChanged(RowSorterEvent sortedEvent,
                                   
TableModelEvent e) {
       
int editingModelIndex = -1;
       
ModelChange change = (e != null) ? new ModelChange(e) : null;

       
if ((change == null || !change.allRowsChanged) &&
               
this.editingRow != -1) {
            editingModelIndex
= convertRowIndexToModel(sortedEvent,
                                                       
this.editingRow);
       
}

        sortManager
.prepareForChange(sortedEvent, change);

       
if (e != null) {
           
if (change.type == TableModelEvent.UPDATE) {
                repaintSortedRows
(change);
           
}
            notifySorter
(change);
           
if (change.type != TableModelEvent.UPDATE) {
               
// If the Sorter is unsorted we will not have received
               
// notification, force treating insert/delete as a change.
                sorterChanged
= true;
           
}
       
}
       
else {
            sorterChanged
= true;
       
}

        sortManager
.processChange(sortedEvent, change, sorterChanged);

       
if (sorterChanged) {
           
// Update the editing row
           
if (this.editingRow != -1) {
               
int newIndex = (editingModelIndex == -1) ? -1 :
                        convertRowIndexToView
(editingModelIndex,change);
                restoreSortingEditingRow
(newIndex);
           
}

           
// And handle the appropriate repainting.
           
if (e == null || change.type != TableModelEvent.UPDATE) {
                resizeAndRepaint
();
           
}
       
}

       
// Check if lead/anchor need to be reset.
       
if (change != null && change.allRowsChanged) {
            clearSelectionAndLeadAnchor
();
            resizeAndRepaint
();
       
}
   
}

   
/**
     * Repaints the sort of sorted rows in response to a TableModelEvent.
     */

   
private void repaintSortedRows(ModelChange change) {
       
if (change.startModelIndex > change.endModelIndex ||
                change
.startModelIndex + 10 < change.endModelIndex) {
           
// Too much has changed, punt
            repaint
();
           
return;
       
}
       
int eventColumn = change.event.getColumn();
       
int columnViewIndex = eventColumn;
       
if (columnViewIndex == TableModelEvent.ALL_COLUMNS) {
            columnViewIndex
= 0;
       
}
       
else {
            columnViewIndex
= convertColumnIndexToView(columnViewIndex);
           
if (columnViewIndex == -1) {
               
return;
           
}
       
}
       
int modelIndex = change.startModelIndex;
       
while (modelIndex <= change.endModelIndex) {
           
int viewIndex = convertRowIndexToView(modelIndex++);
           
if (viewIndex != -1) {
               
Rectangle dirty = getCellRect(viewIndex, columnViewIndex,
                                             
false);
               
int x = dirty.x;
               
int w = dirty.width;
               
if (eventColumn == TableModelEvent.ALL_COLUMNS) {
                    x
= 0;
                    w
= getWidth();
               
}
                repaint
(x, dirty.y, w, dirty.height);
           
}
       
}
   
}

   
/**
     * Restores the selection after a model event/sort order changes.
     * All coordinates are in terms of the model.
     */

   
private void restoreSortingSelection(int[] selection, int lead,
           
ModelChange change) {
       
// Convert the selection from model to view
       
for (int i = selection.length - 1; i >= 0; i--) {
            selection
[i] = convertRowIndexToView(selection[i], change);
       
}
        lead
= convertRowIndexToView(lead, change);

       
// Check for the common case of no change in selection for 1 row
       
if (selection.length == 0 ||
           
(selection.length == 1 && selection[0] == getSelectedRow())) {
           
return;
       
}

       
// And apply the new selection
        selectionModel
.setValueIsAdjusting(true);
        selectionModel
.clearSelection();
       
for (int i = selection.length - 1; i >= 0; i--) {
           
if (selection[i] != -1) {
                selectionModel
.addSelectionInterval(selection[i],
                                                    selection
[i]);
           
}
       
}
       
SwingUtilities2.setLeadAnchorWithoutSelection(
                selectionModel
, lead, lead);
        selectionModel
.setValueIsAdjusting(false);
   
}

   
/**
     * Restores the editing row after a model event/sort order change.
     *
     * @param editingRow new index of the editingRow, in terms of the view
     */

   
private void restoreSortingEditingRow(int editingRow) {
       
if (editingRow == -1) {
           
// Editing row no longer being shown, cancel editing
           
TableCellEditor editor = getCellEditor();
           
if (editor != null) {
               
// First try and cancel
                editor
.cancelCellEditing();
               
if (getCellEditor() != null) {
                   
// CellEditor didn't cede control, forcefully
                   
// remove it
                    removeEditor
();
               
}
           
}
       
}
       
else {
           
// Repositioning handled in BasicTableUI
           
this.editingRow = editingRow;
            repaint
();
       
}
   
}

   
/**
     * Notifies the sorter of a change in the underlying model.
     */

   
private void notifySorter(ModelChange change) {
       
try {
            ignoreSortChange
= true;
            sorterChanged
= false;
           
switch(change.type) {
           
case TableModelEvent.UPDATE:
               
if (change.event.getLastRow() == Integer.MAX_VALUE) {
                    sortManager
.sorter.allRowsChanged();
               
} else if (change.event.getColumn() ==
                           
TableModelEvent.ALL_COLUMNS) {
                    sortManager
.sorter.rowsUpdated(change.startModelIndex,
                                       change
.endModelIndex);
               
} else {
                    sortManager
.sorter.rowsUpdated(change.startModelIndex,
                                       change
.endModelIndex,
                                       change
.event.getColumn());
               
}
               
break;
           
case TableModelEvent.INSERT:
                sortManager
.sorter.rowsInserted(change.startModelIndex,
                                    change
.endModelIndex);
               
break;
           
case TableModelEvent.DELETE:
                sortManager
.sorter.rowsDeleted(change.startModelIndex,
                                   change
.endModelIndex);
               
break;
           
}
       
} finally {
            ignoreSortChange
= false;
       
}
   
}

   
/**
     * Converts a model index to view index.  This is called when the
     * sorter or model changes and sorting is enabled.
     *
     * @param change describes the TableModelEvent that initiated the change;
     *        will be null if called as the result of a sort
     */

   
private int convertRowIndexToView(int modelIndex, ModelChange change) {
       
if (modelIndex < 0) {
           
return -1;
       
}
       
if (change != null && modelIndex >= change.startModelIndex) {
           
if (change.type == TableModelEvent.INSERT) {
               
if (modelIndex + change.length >= change.modelRowCount) {
                   
return -1;
               
}
               
return sortManager.sorter.convertRowIndexToView(
                        modelIndex
+ change.length);
           
}
           
else if (change.type == TableModelEvent.DELETE) {
               
if (modelIndex <= change.endModelIndex) {
                   
// deleted
                   
return -1;
               
}
               
else {
                   
if (modelIndex - change.length >= change.modelRowCount) {
                       
return -1;
                   
}
                   
return sortManager.sorter.convertRowIndexToView(
                            modelIndex
- change.length);
               
}
           
}
           
// else, updated
       
}
       
if (modelIndex >= getModel().getRowCount()) {
           
return -1;
       
}
       
return sortManager.sorter.convertRowIndexToView(modelIndex);
   
}

   
/**
     * Converts the selection to model coordinates.  This is used when
     * the model changes or the sorter changes.
     */

   
private int[] convertSelectionToModel(RowSorterEvent e) {
       
int[] selection = getSelectedRows();
       
for (int i = selection.length - 1; i >= 0; i--) {
            selection
[i] = convertRowIndexToModel(e, selection[i]);
       
}
       
return selection;
   
}

   
private int convertRowIndexToModel(RowSorterEvent e, int viewIndex) {
       
if (e != null) {
           
if (e.getPreviousRowCount() == 0) {
               
return viewIndex;
           
}
           
// range checking handled by RowSorterEvent
           
return e.convertPreviousRowIndexToModel(viewIndex);
       
}
       
// Make sure the viewIndex is valid
       
if (viewIndex < 0 || viewIndex >= getRowCount()) {
           
return -1;
       
}
       
return convertRowIndexToModel(viewIndex);
   
}

//
// Implementing TableModelListener interface
//

   
/**
     * Invoked when this table's <code>TableModel</code> generates
     * a <code>TableModelEvent</code>.
     * The <code>TableModelEvent</code> should be constructed in the
     * coordinate system of the model; the appropriate mapping to the
     * view coordinate system is performed by this <code>JTable</code>
     * when it receives the event.
     * <p>
     * Application code will not use these methods explicitly, they
     * are used internally by <code>JTable</code>.
     * <p>
     * Note that as of 1.3, this method clears the selection, if any.
     */

   
public void tableChanged(TableModelEvent e) {
       
if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
           
// The whole thing changed
            clearSelectionAndLeadAnchor
();

            rowModel
= null;

           
if (sortManager != null) {
               
try {
                    ignoreSortChange
= true;
                    sortManager
.sorter.modelStructureChanged();
               
} finally {
                    ignoreSortChange
= false;
               
}
                sortManager
.allChanged();
           
}

           
if (getAutoCreateColumnsFromModel()) {
               
// This will effect invalidation of the JTable and JTableHeader.
                createDefaultColumnsFromModel
();
               
return;
           
}

            resizeAndRepaint
();
           
return;
       
}

       
if (sortManager != null) {
            sortedTableChanged
(null, e);
           
return;
       
}

       
// The totalRowHeight calculated below will be incorrect if
       
// there are variable height rows. Repaint the visible region,
       
// but don't return as a revalidate may be necessary as well.
       
if (rowModel != null) {
            repaint
();
       
}

       
if (e.getType() == TableModelEvent.INSERT) {
            tableRowsInserted
(e);
           
return;
       
}

       
if (e.getType() == TableModelEvent.DELETE) {
            tableRowsDeleted
(e);
           
return;
       
}

       
int modelColumn = e.getColumn();
       
int start = e.getFirstRow();
       
int end = e.getLastRow();

       
Rectangle dirtyRegion;
       
if (modelColumn == TableModelEvent.ALL_COLUMNS) {
           
// 1 or more rows changed
            dirtyRegion
= new Rectangle(0, start * getRowHeight(),
                                        getColumnModel
().getTotalColumnWidth(), 0);
       
}
       
else {
           
// A cell or column of cells has changed.
           
// Unlike the rest of the methods in the JTable, the TableModelEvent
           
// uses the coordinate system of the model instead of the view.
           
// This is the only place in the JTable where this "reverse mapping"
           
// is used.
           
int column = convertColumnIndexToView(modelColumn);
            dirtyRegion
= getCellRect(start, column, false);
       
}

       
// Now adjust the height of the dirty region according to the value of "end".
       
// Check for Integer.MAX_VALUE as this will cause an overflow.
       
if (end != Integer.MAX_VALUE) {
            dirtyRegion
.height = (end-start+1)*getRowHeight();
            repaint
(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
       
}
       
// In fact, if the end is Integer.MAX_VALUE we need to revalidate anyway
       
// because the scrollbar may need repainting.
       
else {
            clearSelectionAndLeadAnchor
();
            resizeAndRepaint
();
            rowModel
= null;
       
}
   
}

   
/*
     * Invoked when rows have been inserted into the table.
     * <p>
     * Application code will not use these methods explicitly, they
     * are used internally by JTable.
     *
     * @param e the TableModelEvent encapsulating the insertion
     */

   
private void tableRowsInserted(TableModelEvent e) {
       
int start = e.getFirstRow();
       
int end = e.getLastRow();
       
if (start < 0) {
            start
= 0;
       
}
       
if (end < 0) {
           
end = getRowCount()-1;
       
}

       
// Adjust the selection to account for the new rows.
       
int length = end - start + 1;
        selectionModel
.insertIndexInterval(start, length, true);

       
// If we have variable height rows, adjust the row model.
       
if (rowModel != null) {
            rowModel
.insertEntries(start, length, getRowHeight());
       
}
       
int rh = getRowHeight() ;
       
Rectangle drawRect = new Rectangle(0, start * rh,
                                        getColumnModel
().getTotalColumnWidth(),
                                           
(getRowCount()-start) * rh);

        revalidate
();
       
// PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
       
// repaint still required in the unusual case where there is no ScrollPane
        repaint
(drawRect);
   
}

   
/*
     * Invoked when rows have been removed from the table.
     * <p>
     * Application code will not use these methods explicitly, they
     * are used internally by JTable.
     *
     * @param e the TableModelEvent encapsulating the deletion
     */

   
private void tableRowsDeleted(TableModelEvent e) {
       
int start = e.getFirstRow();
       
int end = e.getLastRow();
       
if (start < 0) {
            start
= 0;
       
}
       
if (end < 0) {
           
end = getRowCount()-1;
       
}

       
int deletedCount = end - start + 1;
       
int previousRowCount = getRowCount() + deletedCount;
       
// Adjust the selection to account for the new rows
        selectionModel
.removeIndexInterval(start, end);

       
// If we have variable height rows, adjust the row model.
       
if (rowModel != null) {
            rowModel
.removeEntries(start, deletedCount);
       
}

       
int rh = getRowHeight();
       
Rectangle drawRect = new Rectangle(0, start * rh,
                                        getColumnModel
().getTotalColumnWidth(),
                                       
(previousRowCount - start) * rh);

        revalidate
();
       
// PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
       
// repaint still required in the unusual case where there is no ScrollPane
        repaint
(drawRect);
   
}

//
// Implementing TableColumnModelListener interface
//

   
/**
     * Invoked when a column is added to the table column model.
     * <p>
     * Application code will not use these methods explicitly, they
     * are used internally by JTable.
     *
     * @see TableColumnModelListener
     */

   
public void columnAdded(TableColumnModelEvent e) {
       
// If I'm currently editing, then I should stop editing
       
if (isEditing()) {
            removeEditor
();
       
}
        resizeAndRepaint
();
   
}

   
/**
     * Invoked when a column is removed from the table column model.
     * <p>
     * Application code will not use these methods explicitly, they
     * are used internally by JTable.
     *
     * @see TableColumnModelListener
     */

   
public void columnRemoved(TableColumnModelEvent e) {
       
// If I'm currently editing, then I should stop editing
       
if (isEditing()) {
            removeEditor
();
       
}
        resizeAndRepaint
();
   
}

   
/**
     * Invoked when a column is repositioned. If a cell is being
     * edited, then editing is stopped and the cell is redrawn.
     * <p>
     * Application code will not use these methods explicitly, they
     * are used internally by JTable.
     *
     * @param e   the event received
     * @see TableColumnModelListener
     */

   
public void columnMoved(TableColumnModelEvent e) {
       
// If I'm currently editing, then I should stop editing
       
if (isEditing()) {
            removeEditor
();
       
}
        repaint
();
   
}

   
/**
     * Invoked when a column is moved due to a margin change.
     * If a cell is being edited, then editing is stopped and the cell
     * is redrawn.
     * <p>
     * Application code will not use these methods explicitly, they
     * are used internally by JTable.
     *
     * @param  e    the event received
     * @see TableColumnModelListener
     */

   
public void columnMarginChanged(ChangeEvent e) {
       
if (isEditing()) {
            removeEditor
();
       
}
       
TableColumn resizingColumn = getResizingColumn();
       
// Need to do this here, before the parent's
       
// layout manager calls getPreferredSize().
       
if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF) {
            resizingColumn
.setPreferredWidth(resizingColumn.getWidth());
       
}
        resizeAndRepaint
();
   
}

   
private int limit(int i, int a, int b) {
       
return Math.min(b, Math.max(i, a));
   
}

   
/**
     * Invoked when the selection model of the <code>TableColumnModel</code>
     * is changed.
     * <p>
     * Application code will not use these methods explicitly, they
     * are used internally by JTable.
     *
     * @param  e  the event received
     * @see TableColumnModelListener
     */

   
public void columnSelectionChanged(ListSelectionEvent e) {
       
boolean isAdjusting = e.getValueIsAdjusting();
       
if (columnSelectionAdjusting && !isAdjusting) {
           
// The assumption is that when the model is no longer adjusting
           
// we will have already gotten all the changes, and therefore
           
// don't need to do an additional paint.
            columnSelectionAdjusting
= false;
           
return;
       
}
        columnSelectionAdjusting
= isAdjusting;
       
// The getCellRect() call will fail unless there is at least one row.
       
if (getRowCount() <= 0 || getColumnCount() <= 0) {
           
return;
       
}
       
int firstIndex = limit(e.getFirstIndex(), 0, getColumnCount()-1);
       
int lastIndex = limit(e.getLastIndex(), 0, getColumnCount()-1);
       
int minRow = 0;
       
int maxRow = getRowCount() - 1;
       
if (getRowSelectionAllowed()) {
            minRow
= selectionModel.getMinSelectionIndex();
            maxRow
= selectionModel.getMaxSelectionIndex();
           
int leadRow = getAdjustedIndex(selectionModel.getLeadSelectionIndex(), true);

           
if (minRow == -1 || maxRow == -1) {
               
if (leadRow == -1) {
                   
// nothing to repaint, return
                   
return;
               
}

               
// only thing to repaint is the lead
                minRow
= maxRow = leadRow;
           
} else {
               
// We need to consider more than just the range between
               
// the min and max selected index. The lead row, which could
               
// be outside this range, should be considered also.
               
if (leadRow != -1) {
                    minRow
= Math.min(minRow, leadRow);
                    maxRow
= Math.max(maxRow, leadRow);
               
}
           
}
       
}
       
Rectangle firstColumnRect = getCellRect(minRow, firstIndex, false);
       
Rectangle lastColumnRect = getCellRect(maxRow, lastIndex, false);
       
Rectangle dirtyRegion = firstColumnRect.union(lastColumnRect);
        repaint
(dirtyRegion);
   
}

//
// Implementing ListSelectionListener interface
//

   
/**
     * Invoked when the row selection changes -- repaints to show the new
     * selection.
     * <p>
     * Application code will not use these methods explicitly, they
     * are used internally by JTable.
     *
     * @param e   the event received
     * @see ListSelectionListener
     */

   
public void valueChanged(ListSelectionEvent e) {
       
if (sortManager != null) {
            sortManager
.viewSelectionChanged(e);
       
}
       
boolean isAdjusting = e.getValueIsAdjusting();
       
if (rowSelectionAdjusting && !isAdjusting) {
           
// The assumption is that when the model is no longer adjusting
           
// we will have already gotten all the changes, and therefore
           
// don't need to do an additional paint.
            rowSelectionAdjusting
= false;
           
return;
       
}
        rowSelectionAdjusting
= isAdjusting;
       
// The getCellRect() calls will fail unless there is at least one column.
       
if (getRowCount() <= 0 || getColumnCount() <= 0) {
           
return;
       
}
       
int firstIndex = limit(e.getFirstIndex(), 0, getRowCount()-1);
       
int lastIndex = limit(e.getLastIndex(), 0, getRowCount()-1);
       
Rectangle firstRowRect = getCellRect(firstIndex, 0, false);
       
Rectangle lastRowRect = getCellRect(lastIndex, getColumnCount()-1, false);
       
Rectangle dirtyRegion = firstRowRect.union(lastRowRect);
        repaint
(dirtyRegion);
   
}

//
// Implementing the CellEditorListener interface
//

   
/**
     * Invoked when editing is finished. The changes are saved and the
     * editor is discarded.
     * <p>
     * Application code will not use these methods explicitly, they
     * are used internally by JTable.
     *
     * @param  e  the event received
     * @see CellEditorListener
     */

   
public void editingStopped(ChangeEvent e) {
       
// Take in the new value
       
TableCellEditor editor = getCellEditor();
       
if (editor != null) {
           
Object value = editor.getCellEditorValue();
            setValueAt
(value, editingRow, editingColumn);
            removeEditor
();
       
}
   
}

   
/**
     * Invoked when editing is canceled. The editor object is discarded
     * and the cell is rendered once again.
     * <p>
     * Application code will not use these methods explicitly, they
     * are used internally by JTable.
     *
     * @param  e  the event received
     * @see CellEditorListener
     */

   
public void editingCanceled(ChangeEvent e) {
        removeEditor
();
   
}

//
// Implementing the Scrollable interface
//

   
/**
     * Sets the preferred size of the viewport for this table.
     *
     * @param size  a <code>Dimension</code> object specifying the <code>preferredSize</code> of a
     *              <code>JViewport</code> whose view is this table
     * @see Scrollable#getPreferredScrollableViewportSize
     * @beaninfo
     * description: The preferred size of the viewport.
     */

   
public void setPreferredScrollableViewportSize(Dimension size) {
        preferredViewportSize
= size;
   
}

   
/**
     * Returns the preferred size of the viewport for this table.
     *
     * @return a <code>Dimension</code> object containing the <code>preferredSize</code> of the <code>JViewport</code>
     *         which displays this table
     * @see Scrollable#getPreferredScrollableViewportSize
     */

   
public Dimension getPreferredScrollableViewportSize() {
       
return preferredViewportSize;
   
}

   
/**
     * Returns the scroll increment (in pixels) that completely exposes one new
     * row or column (depending on the orientation).
     * <p>
     * This method is called each time the user requests a unit scroll.
     *
     * @param visibleRect the view area visible within the viewport
     * @param orientation either <code>SwingConstants.VERTICAL</code>
     *                  or <code>SwingConstants.HORIZONTAL</code>
     * @param direction less than zero to scroll up/left,
     *                  greater than zero for down/right
     * @return the "unit" increment for scrolling in the specified direction
     * @see Scrollable#getScrollableUnitIncrement
     */

   
public int getScrollableUnitIncrement(Rectangle visibleRect,
                                         
int orientation,
                                         
int direction) {
       
int leadingRow;
       
int leadingCol;
       
Rectangle leadingCellRect;

       
int leadingVisibleEdge;
       
int leadingCellEdge;
       
int leadingCellSize;

        leadingRow
= getLeadingRow(visibleRect);
        leadingCol
= getLeadingCol(visibleRect);
       
if (orientation == SwingConstants.VERTICAL && leadingRow < 0) {
           
// Couldn't find leading row - return some default value
           
return getRowHeight();
       
}
       
else if (orientation == SwingConstants.HORIZONTAL && leadingCol < 0) {
           
// Couldn't find leading col - return some default value
           
return 100;
       
}

       
// Note that it's possible for one of leadingCol or leadingRow to be
       
// -1, depending on the orientation.  This is okay, as getCellRect()
       
// still provides enough information to calculate the unit increment.
        leadingCellRect
= getCellRect(leadingRow, leadingCol, true);
        leadingVisibleEdge
= leadingEdge(visibleRect, orientation);
        leadingCellEdge
= leadingEdge(leadingCellRect, orientation);

       
if (orientation == SwingConstants.VERTICAL) {
            leadingCellSize
= leadingCellRect.height;

       
}
       
else {
            leadingCellSize
= leadingCellRect.width;
       
}

       
// 4 cases:
       
// #1: Leading cell fully visible, reveal next cell
       
// #2: Leading cell fully visible, hide leading cell
       
// #3: Leading cell partially visible, hide rest of leading cell
       
// #4: Leading cell partially visible, reveal rest of leading cell

       
if (leadingVisibleEdge == leadingCellEdge) { // Leading cell is fully
                                                     
// visible
           
// Case #1: Reveal previous cell
           
if (direction < 0) {
               
int retVal = 0;

               
if (orientation == SwingConstants.VERTICAL) {
                   
// Loop past any zero-height rows
                   
while (--leadingRow >= 0) {
                        retVal
= getRowHeight(leadingRow);
                       
if (retVal != 0) {
                           
break;
                       
}
                   
}
               
}
               
else { // HORIZONTAL
                   
// Loop past any zero-width cols
                   
while (--leadingCol >= 0) {
                        retVal
= getCellRect(leadingRow, leadingCol, true).width;
                       
if (retVal != 0) {
                           
break;
                       
}
                   
}
               
}
               
return retVal;
           
}
           
else { // Case #2: hide leading cell
               
return leadingCellSize;
           
}
       
}
       
else { // Leading cell is partially hidden
           
// Compute visible, hidden portions
           
int hiddenAmt = Math.abs(leadingVisibleEdge - leadingCellEdge);
           
int visibleAmt = leadingCellSize - hiddenAmt;

           
if (direction > 0) {
               
// Case #3: hide showing portion of leading cell
               
return visibleAmt;
           
}
           
else { // Case #4: reveal hidden portion of leading cell
               
return hiddenAmt;
           
}
       
}
   
}

   
/**
     * Returns <code>visibleRect.height</code> or
     * <code>visibleRect.width</code>,
     * depending on this table's orientation.  Note that as of Swing 1.1.1
     * (Java 2 v 1.2.2) the value
     * returned will ensure that the viewport is cleanly aligned on
     * a row boundary.
     *
     * @return <code>visibleRect.height</code> or
     *                                  <code>visibleRect.width</code>
     *                                  per the orientation
     * @see Scrollable#getScrollableBlockIncrement
     */

   
public int getScrollableBlockIncrement(Rectangle visibleRect,
           
int orientation, int direction) {

       
if (getRowCount() == 0) {
           
// Short-circuit empty table model
           
if (SwingConstants.VERTICAL == orientation) {
               
int rh = getRowHeight();
               
return (rh > 0) ? Math.max(rh, (visibleRect.height / rh) * rh) :
                                  visibleRect
.height;
           
}
           
else {
               
return visibleRect.width;
           
}
       
}
       
// Shortcut for vertical scrolling of a table w/ uniform row height
       
if (null == rowModel && SwingConstants.VERTICAL == orientation) {
           
int row = rowAtPoint(visibleRect.getLocation());
           
assert row != -1;
           
int col = columnAtPoint(visibleRect.getLocation());
           
Rectangle cellRect = getCellRect(row, col, true);

           
if (cellRect.y == visibleRect.y) {
               
int rh = getRowHeight();
               
assert rh > 0;
               
return Math.max(rh, (visibleRect.height / rh) * rh);
           
}
       
}
       
if (direction < 0) {
           
return getPreviousBlockIncrement(visibleRect, orientation);
       
}
       
else {
           
return getNextBlockIncrement(visibleRect, orientation);
       
}
   
}

   
/**
     * Called to get the block increment for upward scrolling in cases of
     * horizontal scrolling, or for vertical scrolling of a table with
     * variable row heights.
     */

   
private int getPreviousBlockIncrement(Rectangle visibleRect,
                                         
int orientation) {
       
// Measure back from visible leading edge
       
// If we hit the cell on its leading edge, it becomes the leading cell.
       
// Else, use following cell

       
int row;
       
int col;

       
int   newEdge;
       
Point newCellLoc;

       
int visibleLeadingEdge = leadingEdge(visibleRect, orientation);
       
boolean leftToRight = getComponentOrientation().isLeftToRight();
       
int newLeadingEdge;

       
// Roughly determine the new leading edge by measuring back from the
       
// leading visible edge by the size of the visible rect, and find the
       
// cell there.
       
if (orientation == SwingConstants.VERTICAL) {
            newEdge
= visibleLeadingEdge - visibleRect.height;
           
int x = visibleRect.x + (leftToRight ? 0 : visibleRect.width);
            newCellLoc
= new Point(x, newEdge);
       
}
       
else if (leftToRight) {
            newEdge
= visibleLeadingEdge - visibleRect.width;
            newCellLoc
= new Point(newEdge, visibleRect.y);
       
}
       
else { // Horizontal, right-to-left
            newEdge
= visibleLeadingEdge + visibleRect.width;
            newCellLoc
= new Point(newEdge - 1, visibleRect.y);
       
}
        row
= rowAtPoint(newCellLoc);
        col
= columnAtPoint(newCellLoc);

       
// If we're measuring past the beginning of the table, we get an invalid
       
// cell.  Just go to the beginning of the table in this case.
       
if (orientation == SwingConstants.VERTICAL & row < 0) {
            newLeadingEdge
= 0;
       
}
       
else if (orientation == SwingConstants.HORIZONTAL & col < 0) {
           
if (leftToRight) {
                newLeadingEdge
= 0;
           
}
           
else {
                newLeadingEdge
= getWidth();
           
}
       
}
       
else {
           
// Refine our measurement
           
Rectangle newCellRect = getCellRect(row, col, true);
           
int newCellLeadingEdge = leadingEdge(newCellRect, orientation);
           
int newCellTrailingEdge = trailingEdge(newCellRect, orientation);

           
// Usually, we hit in the middle of newCell, and want to scroll to
           
// the beginning of the cell after newCell.  But there are a
           
// couple corner cases where we want to scroll to the beginning of
           
// newCell itself.  These cases are:
           
// 1) newCell is so large that it ends at or extends into the
           
//    visibleRect (newCell is the leading cell, or is adjacent to
           
//    the leading cell)
           
// 2) newEdge happens to fall right on the beginning of a cell

           
// Case 1
           
if ((orientation == SwingConstants.VERTICAL || leftToRight) &&
               
(newCellTrailingEdge >= visibleLeadingEdge)) {
                newLeadingEdge
= newCellLeadingEdge;
           
}
           
else if (orientation == SwingConstants.HORIZONTAL &&
                     
!leftToRight &&
                     newCellTrailingEdge
<= visibleLeadingEdge) {
                newLeadingEdge
= newCellLeadingEdge;
           
}
           
// Case 2:
           
else if (newEdge == newCellLeadingEdge) {
                newLeadingEdge
= newCellLeadingEdge;
           
}
           
// Common case: scroll to cell after newCell
           
else {
                newLeadingEdge
= newCellTrailingEdge;
           
}
       
}
       
return Math.abs(visibleLeadingEdge - newLeadingEdge);
   
}

   
/**
     * Called to get the block increment for downward scrolling in cases of
     * horizontal scrolling, or for vertical scrolling of a table with
     * variable row heights.
     */

   
private int getNextBlockIncrement(Rectangle visibleRect,
                                     
int orientation) {
       
// Find the cell at the trailing edge.  Return the distance to put
       
// that cell at the leading edge.
       
int trailingRow = getTrailingRow(visibleRect);
       
int trailingCol = getTrailingCol(visibleRect);

       
Rectangle cellRect;
       
boolean cellFillsVis;

       
int cellLeadingEdge;
       
int cellTrailingEdge;
       
int newLeadingEdge;
       
int visibleLeadingEdge = leadingEdge(visibleRect, orientation);

       
// If we couldn't find trailing cell, just return the size of the
       
// visibleRect.  Note that, for instance, we don't need the
       
// trailingCol to proceed if we're scrolling vertically, because
       
// cellRect will still fill in the required dimensions.  This would
       
// happen if we're scrolling vertically, and the table is not wide
       
// enough to fill the visibleRect.
       
if (orientation == SwingConstants.VERTICAL && trailingRow < 0) {
           
return visibleRect.height;
       
}
       
else if (orientation == SwingConstants.HORIZONTAL && trailingCol < 0) {
           
return visibleRect.width;
       
}
        cellRect
= getCellRect(trailingRow, trailingCol, true);
        cellLeadingEdge
= leadingEdge(cellRect, orientation);
        cellTrailingEdge
= trailingEdge(cellRect, orientation);

       
if (orientation == SwingConstants.VERTICAL ||
            getComponentOrientation
().isLeftToRight()) {
            cellFillsVis
= cellLeadingEdge <= visibleLeadingEdge;
       
}
       
else { // Horizontal, right-to-left
            cellFillsVis
= cellLeadingEdge >= visibleLeadingEdge;
       
}

       
if (cellFillsVis) {
           
// The visibleRect contains a single large cell.  Scroll to the end
           
// of this cell, so the following cell is the first cell.
            newLeadingEdge
= cellTrailingEdge;
       
}
       
else if (cellTrailingEdge == trailingEdge(visibleRect, orientation)) {
           
// The trailing cell happens to end right at the end of the
           
// visibleRect.  Again, scroll to the beginning of the next cell.
            newLeadingEdge
= cellTrailingEdge;
       
}
       
else {
           
// Common case: the trailing cell is partially visible, and isn't
           
// big enough to take up the entire visibleRect.  Scroll so it
           
// becomes the leading cell.
            newLeadingEdge
= cellLeadingEdge;
       
}
       
return Math.abs(newLeadingEdge - visibleLeadingEdge);
   
}

   
/*
     * Return the row at the top of the visibleRect
     *
     * May return -1
     */

   
private int getLeadingRow(Rectangle visibleRect) {
       
Point leadingPoint;

       
if (getComponentOrientation().isLeftToRight()) {
            leadingPoint
= new Point(visibleRect.x, visibleRect.y);
       
}
       
else {
            leadingPoint
= new Point(visibleRect.x + visibleRect.width - 1,
                                     visibleRect
.y);
       
}
       
return rowAtPoint(leadingPoint);
   
}

   
/*
     * Return the column at the leading edge of the visibleRect.
     *
     * May return -1
     */

   
private int getLeadingCol(Rectangle visibleRect) {
       
Point leadingPoint;

       
if (getComponentOrientation().isLeftToRight()) {
            leadingPoint
= new Point(visibleRect.x, visibleRect.y);
       
}
       
else {
            leadingPoint
= new Point(visibleRect.x + visibleRect.width - 1,
                                     visibleRect
.y);
       
}
       
return columnAtPoint(leadingPoint);
   
}

   
/*
     * Return the row at the bottom of the visibleRect.
     *
     * May return -1
     */

   
private int getTrailingRow(Rectangle visibleRect) {
       
Point trailingPoint;

       
if (getComponentOrientation().isLeftToRight()) {
            trailingPoint
= new Point(visibleRect.x,
                                      visibleRect
.y + visibleRect.height - 1);
       
}
       
else {
            trailingPoint
= new Point(visibleRect.x + visibleRect.width - 1,
                                      visibleRect
.y + visibleRect.height - 1);
       
}
       
return rowAtPoint(trailingPoint);
   
}

   
/*
     * Return the column at the trailing edge of the visibleRect.
     *
     * May return -1
     */

   
private int getTrailingCol(Rectangle visibleRect) {
       
Point trailingPoint;

       
if (getComponentOrientation().isLeftToRight()) {
            trailingPoint
= new Point(visibleRect.x + visibleRect.width - 1,
                                      visibleRect
.y);
       
}
       
else {
            trailingPoint
= new Point(visibleRect.x, visibleRect.y);
       
}
       
return columnAtPoint(trailingPoint);
   
}

   
/*
     * Returns the leading edge ("beginning") of the given Rectangle.
     * For VERTICAL, this is the top, for left-to-right, the left side, and for
     * right-to-left, the right side.
     */

   
private int leadingEdge(Rectangle rect, int orientation) {
       
if (orientation == SwingConstants.VERTICAL) {
           
return rect.y;
       
}
       
else if (getComponentOrientation().isLeftToRight()) {
           
return rect.x;
       
}
       
else { // Horizontal, right-to-left
           
return rect.x + rect.width;
       
}
   
}

   
/*
     * Returns the trailing edge ("end") of the given Rectangle.
     * For VERTICAL, this is the bottom, for left-to-right, the right side, and
     * for right-to-left, the left side.
     */

   
private int trailingEdge(Rectangle rect, int orientation) {
       
if (orientation == SwingConstants.VERTICAL) {
           
return rect.y + rect.height;
       
}
       
else if (getComponentOrientation().isLeftToRight()) {
           
return rect.x + rect.width;
       
}
       
else { // Horizontal, right-to-left
           
return rect.x;
       
}
   
}

   
/**
     * Returns false if <code>autoResizeMode</code> is set to
     * <code>AUTO_RESIZE_OFF</code>, which indicates that the
     * width of the viewport does not determine the width
     * of the table.  Otherwise returns true.
     *
     * @return false if <code>autoResizeMode</code> is set
     *   to <code>AUTO_RESIZE_OFF</code>, otherwise returns true
     * @see Scrollable#getScrollableTracksViewportWidth
     */

   
public boolean getScrollableTracksViewportWidth() {
       
return !(autoResizeMode == AUTO_RESIZE_OFF);
   
}

   
/**
     * Returns {@code false} to indicate that the height of the viewport does
     * not determine the height of the table, unless
     * {@code getFillsViewportHeight} is {@code true} and the preferred height
     * of the table is smaller than the viewport's height.
     *
     * @return {@code false} unless {@code getFillsViewportHeight} is
     *         {@code true} and the table needs to be stretched to fill
     *         the viewport
     * @see Scrollable#getScrollableTracksViewportHeight
     * @see #setFillsViewportHeight
     * @see #getFillsViewportHeight
     */

   
public boolean getScrollableTracksViewportHeight() {
       
return getFillsViewportHeight()
               
&& getParent() instanceof JViewport
               
&& (((JViewport)getParent()).getHeight() > getPreferredSize().height);
   
}

   
/**
     * Sets whether or not this table is always made large enough
     * to fill the height of an enclosing viewport. If the preferred
     * height of the table is smaller than the viewport, then the table
     * will be stretched to fill the viewport. In other words, this
     * ensures the table is never smaller than the viewport.
     * The default for this property is {@code false}.
     *
     * @param fillsViewportHeight whether or not this table is always
     *        made large enough to fill the height of an enclosing
     *        viewport
     * @see #getFillsViewportHeight
     * @see #getScrollableTracksViewportHeight
     * @since 1.6
     * @beaninfo
     *      bound: true
     *      description: Whether or not this table is always made large enough
     *                   to fill the height of an enclosing viewport
     */

   
public void setFillsViewportHeight(boolean fillsViewportHeight) {
       
boolean old = this.fillsViewportHeight;
       
this.fillsViewportHeight = fillsViewportHeight;
        resizeAndRepaint
();
        firePropertyChange
("fillsViewportHeight", old, fillsViewportHeight);
   
}

   
/**
     * Returns whether or not this table is always made large enough
     * to fill the height of an enclosing viewport.
     *
     * @return whether or not this table is always made large enough
     *         to fill the height of an enclosing viewport
     * @see #setFillsViewportHeight
     * @since 1.6
     */

   
public boolean getFillsViewportHeight() {
       
return fillsViewportHeight;
   
}

//
// Protected Methods
//

   
protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
                                       
int condition, boolean pressed) {
       
boolean retValue = super.processKeyBinding(ks, e, condition, pressed);

       
// Start editing when a key is typed. UI classes can disable this behavior
       
// by setting the client property JTable.autoStartsEdit to Boolean.FALSE.
       
if (!retValue && condition == WHEN_ANCESTOR_OF_FOCUSED_COMPONENT &&
            isFocusOwner
() &&
           
!Boolean.FALSE.equals((Boolean)getClientProperty("JTable.autoStartsEdit"))) {
           
// We do not have a binding for the event.
           
Component editorComponent = getEditorComponent();
           
if (editorComponent == null) {
               
// Only attempt to install the editor on a KEY_PRESSED,
               
if (e == null || e.getID() != KeyEvent.KEY_PRESSED) {
                   
return false;
               
}
               
// Don't start when just a modifier is pressed
               
int code = e.getKeyCode();
               
if (code == KeyEvent.VK_SHIFT || code == KeyEvent.VK_CONTROL ||
                    code
== KeyEvent.VK_ALT) {
                   
return false;
               
}
               
// Try to install the editor
               
int leadRow = getSelectionModel().getLeadSelectionIndex();
               
int leadColumn = getColumnModel().getSelectionModel().
                                   getLeadSelectionIndex
();
               
if (leadRow != -1 && leadColumn != -1 && !isEditing()) {
                   
if (!editCellAt(leadRow, leadColumn, e)) {
                       
return false;
                   
}
               
}
                editorComponent
= getEditorComponent();
               
if (editorComponent == null) {
                   
return false;
               
}
           
}
           
// If the editorComponent is a JComponent, pass the event to it.
           
if (editorComponent instanceof JComponent) {
                retValue
= ((JComponent)editorComponent).processKeyBinding
                                       
(ks, e, WHEN_FOCUSED, pressed);
               
// If we have started an editor as a result of the user
               
// pressing a key and the surrendersFocusOnKeystroke property
               
// is true, give the focus to the new editor.
               
if (getSurrendersFocusOnKeystroke()) {
                    editorComponent
.requestFocus();
               
}
           
}
       
}
       
return retValue;
   
}

   
private void setLazyValue(Hashtable h, Class c, String s) {
        h
.put(c, new SwingLazyValue(s));
   
}

   
private void setLazyRenderer(Class c, String s) {
        setLazyValue
(defaultRenderersByColumnClass, c, s);
   
}

   
/**
     * Creates default cell renderers for objects, numbers, doubles, dates,
     * booleans, and icons.
     * @see javax.swing.table.DefaultTableCellRenderer
     *
     */

   
protected void createDefaultRenderers() {
        defaultRenderersByColumnClass
= new UIDefaults(8, 0.75f);

       
// Objects
        setLazyRenderer
(Object.class, "javax.swing.table.DefaultTableCellRenderer$UIResource");

       
// Numbers
        setLazyRenderer
(Number.class, "javax.swing.JTable$NumberRenderer");

       
// Doubles and Floats
        setLazyRenderer
(Float.class, "javax.swing.JTable$DoubleRenderer");
        setLazyRenderer
(Double.class, "javax.swing.JTable$DoubleRenderer");

       
// Dates
        setLazyRenderer
(Date.class, "javax.swing.JTable$DateRenderer");

       
// Icons and ImageIcons
        setLazyRenderer
(Icon.class, "javax.swing.JTable$IconRenderer");
        setLazyRenderer
(ImageIcon.class, "javax.swing.JTable$IconRenderer");

       
// Booleans
        setLazyRenderer
(Boolean.class, "javax.swing.JTable$BooleanRenderer");
   
}

   
/**
     * Default Renderers
     **/

   
static class NumberRenderer extends DefaultTableCellRenderer.UIResource {
       
public NumberRenderer() {
           
super();
            setHorizontalAlignment
(JLabel.RIGHT);
       
}
   
}

   
static class DoubleRenderer extends NumberRenderer {
       
NumberFormat formatter;
       
public DoubleRenderer() { super(); }

       
public void setValue(Object value) {
           
if (formatter == null) {
                formatter
= NumberFormat.getInstance();
           
}
            setText
((value == null) ? "" : formatter.format(value));
       
}
   
}

   
static class DateRenderer extends DefaultTableCellRenderer.UIResource {
       
DateFormat formatter;
       
public DateRenderer() { super(); }

       
public void setValue(Object value) {
           
if (formatter==null) {
                formatter
= DateFormat.getDateInstance();
           
}
            setText
((value == null) ? "" : formatter.format(value));
       
}
   
}

   
static class IconRenderer extends DefaultTableCellRenderer.UIResource {
       
public IconRenderer() {
           
super();
            setHorizontalAlignment
(JLabel.CENTER);
       
}
       
public void setValue(Object value) { setIcon((value instanceof Icon) ? (Icon)value : null); }
   
}


   
static class BooleanRenderer extends JCheckBox implements TableCellRenderer, UIResource
   
{
       
private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);

       
public BooleanRenderer() {
           
super();
            setHorizontalAlignment
(JLabel.CENTER);
            setBorderPainted
(true);
       
}

       
public Component getTableCellRendererComponent(JTable table, Object value,
                                                       
boolean isSelected, boolean hasFocus, int row, int column) {
           
if (isSelected) {
                setForeground
(table.getSelectionForeground());
               
super.setBackground(table.getSelectionBackground());
           
}
           
else {
                setForeground
(table.getForeground());
                setBackground
(table.getBackground());
           
}
            setSelected
((value != null && ((Boolean)value).booleanValue()));

           
if (hasFocus) {
                setBorder
(UIManager.getBorder("Table.focusCellHighlightBorder"));
           
} else {
                setBorder
(noFocusBorder);
           
}

           
return this;
       
}
   
}

   
private void setLazyEditor(Class c, String s) {
        setLazyValue
(defaultEditorsByColumnClass, c, s);
   
}

   
/**
     * Creates default cell editors for objects, numbers, and boolean values.
     * @see DefaultCellEditor
     */

   
protected void createDefaultEditors() {
        defaultEditorsByColumnClass
= new UIDefaults(3, 0.75f);

       
// Objects
        setLazyEditor
(Object.class, "javax.swing.JTable$GenericEditor");

       
// Numbers
        setLazyEditor
(Number.class, "javax.swing.JTable$NumberEditor");

       
// Booleans
        setLazyEditor
(Boolean.class, "javax.swing.JTable$BooleanEditor");
   
}

   
/**
     * Default Editors
     */

   
static class GenericEditor extends DefaultCellEditor {

       
Class[] argTypes = new Class[]{String.class};
        java
.lang.reflect.Constructor constructor;
       
Object value;

       
public GenericEditor() {
           
super(new JTextField());
            getComponent
().setName("Table.editor");
       
}

       
public boolean stopCellEditing() {
           
String s = (String)super.getCellEditorValue();
           
// Here we are dealing with the case where a user
           
// has deleted the string value in a cell, possibly
           
// after a failed validation. Return null, so that
           
// they have the option to replace the value with
           
// null or use escape to restore the original.
           
// For Strings, return "" for backward compatibility.
           
if ("".equals(s)) {
               
if (constructor.getDeclaringClass() == String.class) {
                    value
= s;
               
}
               
super.stopCellEditing();
           
}

           
try {
                value
= constructor.newInstance(new Object[]{s});
           
}
           
catch (Exception e) {
               
((JComponent)getComponent()).setBorder(new LineBorder(Color.red));
               
return false;
           
}
           
return super.stopCellEditing();
       
}

       
public Component getTableCellEditorComponent(JTable table, Object value,
                                                 
boolean isSelected,
                                                 
int row, int column) {
           
this.value = null;
           
((JComponent)getComponent()).setBorder(new LineBorder(Color.black));
           
try {
               
Class type = table.getColumnClass(column);
               
// Since our obligation is to produce a value which is
               
// assignable for the required type it is OK to use the
               
// String constructor for columns which are declared
               
// to contain Objects. A String is an Object.
               
if (type == Object.class) {
                    type
= String.class;
               
}
                constructor
= type.getConstructor(argTypes);
           
}
           
catch (Exception e) {
               
return null;
           
}
           
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
       
}

       
public Object getCellEditorValue() {
           
return value;
       
}
   
}

   
static class NumberEditor extends GenericEditor {

       
public NumberEditor() {
           
((JTextField)getComponent()).setHorizontalAlignment(JTextField.RIGHT);
       
}
   
}

   
static class BooleanEditor extends DefaultCellEditor {
       
public BooleanEditor() {
           
super(new JCheckBox());
           
JCheckBox checkBox = (JCheckBox)getComponent();
            checkBox
.setHorizontalAlignment(JCheckBox.CENTER);
       
}
   
}

   
/**
     * Initializes table properties to their default values.
     */

   
protected void initializeLocalVars() {
        updateSelectionOnSort
= true;
        setOpaque
(true);
        createDefaultRenderers
();
        createDefaultEditors
();

        setTableHeader
(createDefaultTableHeader());

        setShowGrid
(true);
        setAutoResizeMode
(AUTO_RESIZE_SUBSEQUENT_COLUMNS);
        setRowHeight
(16);
        isRowHeightSet
= false;
        setRowMargin
(1);
        setRowSelectionAllowed
(true);
        setCellEditor
(null);
        setEditingColumn
(-1);
        setEditingRow
(-1);
        setSurrendersFocusOnKeystroke
(false);
        setPreferredScrollableViewportSize
(new Dimension(450, 400));

       
// I'm registered to do tool tips so we can draw tips for the renderers
       
ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
        toolTipManager
.registerComponent(this);

        setAutoscrolls
(true);
   
}

   
/**
     * Returns the default table model object, which is
     * a <code>DefaultTableModel</code>.  A subclass can override this
     * method to return a different table model object.
     *
     * @return the default table model object
     * @see javax.swing.table.DefaultTableModel
     */

   
protected TableModel createDefaultDataModel() {
       
return new DefaultTableModel();
   
}

   
/**
     * Returns the default column model object, which is
     * a <code>DefaultTableColumnModel</code>.  A subclass can override this
     * method to return a different column model object.
     *
     * @return the default column model object
     * @see javax.swing.table.DefaultTableColumnModel
     */

   
protected TableColumnModel createDefaultColumnModel() {
       
return new DefaultTableColumnModel();
   
}

   
/**
     * Returns the default selection model object, which is
     * a <code>DefaultListSelectionModel</code>.  A subclass can override this
     * method to return a different selection model object.
     *
     * @return the default selection model object
     * @see javax.swing.DefaultListSelectionModel
     */

   
protected ListSelectionModel createDefaultSelectionModel() {
       
return new DefaultListSelectionModel();
   
}

   
/**
     * Returns the default table header object, which is
     * a <code>JTableHeader</code>.  A subclass can override this
     * method to return a different table header object.
     *
     * @return the default table header object
     * @see javax.swing.table.JTableHeader
     */

   
protected JTableHeader createDefaultTableHeader() {
       
return new JTableHeader(columnModel);
   
}

   
/**
     * Equivalent to <code>revalidate</code> followed by <code>repaint</code>.
     */

   
protected void resizeAndRepaint() {
        revalidate
();
        repaint
();
   
}

   
/**
     * Returns the active cell editor, which is {@code null} if the table
     * is not currently editing.
     *
     * @return the {@code TableCellEditor} that does the editing,
     *         or {@code null} if the table is not currently editing.
     * @see #cellEditor
     * @see #getCellEditor(int, int)
     */

   
public TableCellEditor getCellEditor() {
       
return cellEditor;
   
}

   
/**
     * Sets the active cell editor.
     *
     * @param anEditor the active cell editor
     * @see #cellEditor
     * @beaninfo
     *  bound: true
     *  description: The table's active cell editor.
     */

   
public void setCellEditor(TableCellEditor anEditor) {
       
TableCellEditor oldEditor = cellEditor;
        cellEditor
= anEditor;
        firePropertyChange
("tableCellEditor", oldEditor, anEditor);
   
}

   
/**
     * Sets the <code>editingColumn</code> variable.
     * @param aColumn  the column of the cell to be edited
     *
     * @see #editingColumn
     */

   
public void setEditingColumn(int aColumn) {
        editingColumn
= aColumn;
   
}

   
/**
     * Sets the <code>editingRow</code> variable.
     * @param aRow  the row of the cell to be edited
     *
     * @see #editingRow
     */

   
public void setEditingRow(int aRow) {
        editingRow
= aRow;
   
}

   
/**
     * Returns an appropriate renderer for the cell specified by this row and
     * column. If the <code>TableColumn</code> for this column has a non-null
     * renderer, returns that.  If not, finds the class of the data in
     * this column (using <code>getColumnClass</code>)
     * and returns the default renderer for this type of data.
     * <p>
     * <b>Note:</b>
     * Throughout the table package, the internal implementations always
     * use this method to provide renderers so that this default behavior
     * can be safely overridden by a subclass.
     *
     * @param row       the row of the cell to render, where 0 is the first row
     * @param column    the column of the cell to render,
     *                  where 0 is the first column
     * @return the assigned renderer; if <code>null</code>
     *                  returns the default renderer
     *                  for this type of object
     * @see javax.swing.table.DefaultTableCellRenderer
     * @see javax.swing.table.TableColumn#setCellRenderer
     * @see #setDefaultRenderer
     */

   
public TableCellRenderer getCellRenderer(int row, int column) {
       
TableColumn tableColumn = getColumnModel().getColumn(column);
       
TableCellRenderer renderer = tableColumn.getCellRenderer();
       
if (renderer == null) {
            renderer
= getDefaultRenderer(getColumnClass(column));
       
}
       
return renderer;
   
}

   
/**
     * Prepares the renderer by querying the data model for the
     * value and selection state
     * of the cell at <code>row</code>, <code>column</code>.
     * Returns the component (may be a <code>Component</code>
     * or a <code>JComponent</code>) under the event location.
     * <p>
     * During a printing operation, this method will configure the
     * renderer without indicating selection or focus, to prevent
     * them from appearing in the printed output. To do other
     * customizations based on whether or not the table is being
     * printed, you can check the value of
     * {@link javax.swing.JComponent#isPaintingForPrint()}, either here
     * or within custom renderers.
     * <p>
     * <b>Note:</b>
     * Throughout the table package, the internal implementations always
     * use this method to prepare renderers so that this default behavior
     * can be safely overridden by a subclass.
     *
     * @param renderer  the <code>TableCellRenderer</code> to prepare
     * @param row       the row of the cell to render, where 0 is the first row
     * @param column    the column of the cell to render,
     *                  where 0 is the first column
     * @return          the <code>Component</code> under the event location
     */

   
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
       
Object value = getValueAt(row, column);

       
boolean isSelected = false;
       
boolean hasFocus = false;

       
// Only indicate the selection and focused cell if not printing
       
if (!isPaintingForPrint()) {
            isSelected
= isCellSelected(row, column);

           
boolean rowIsLead =
               
(selectionModel.getLeadSelectionIndex() == row);
           
boolean colIsLead =
               
(columnModel.getSelectionModel().getLeadSelectionIndex() == column);

            hasFocus
= (rowIsLead && colIsLead) && isFocusOwner();
       
}

       
return renderer.getTableCellRendererComponent(this, value,
                                                      isSelected
, hasFocus,
                                                      row
, column);
   
}

   
/**
     * Returns an appropriate editor for the cell specified by
     * <code>row</code> and <code>column</code>. If the
     * <code>TableColumn</code> for this column has a non-null editor,
     * returns that.  If not, finds the class of the data in this
     * column (using <code>getColumnClass</code>)
     * and returns the default editor for this type of data.
     * <p>
     * <b>Note:</b>
     * Throughout the table package, the internal implementations always
     * use this method to provide editors so that this default behavior
     * can be safely overridden by a subclass.
     *
     * @param row       the row of the cell to edit, where 0 is the first row
     * @param column    the column of the cell to edit,
     *                  where 0 is the first column
     * @return          the editor for this cell;
     *                  if <code>null</code> return the default editor for
     *                  this type of cell
     * @see DefaultCellEditor
     */

   
public TableCellEditor getCellEditor(int row, int column) {
       
TableColumn tableColumn = getColumnModel().getColumn(column);
       
TableCellEditor editor = tableColumn.getCellEditor();
       
if (editor == null) {
            editor
= getDefaultEditor(getColumnClass(column));
       
}
       
return editor;
   
}


   
/**
     * Prepares the editor by querying the data model for the value and
     * selection state of the cell at <code>row</code>, <code>column</code>.
     * <p>
     * <b>Note:</b>
     * Throughout the table package, the internal implementations always
     * use this method to prepare editors so that this default behavior
     * can be safely overridden by a subclass.
     *
     * @param editor  the <code>TableCellEditor</code> to set up
     * @param row     the row of the cell to edit,
     *                where 0 is the first row
     * @param column  the column of the cell to edit,
     *                where 0 is the first column
     * @return the <code>Component</code> being edited
     */

   
public Component prepareEditor(TableCellEditor editor, int row, int column) {
       
Object value = getValueAt(row, column);
       
boolean isSelected = isCellSelected(row, column);
       
Component comp = editor.getTableCellEditorComponent(this, value, isSelected,
                                                  row
, column);
       
if (comp instanceof JComponent) {
           
JComponent jComp = (JComponent)comp;
           
if (jComp.getNextFocusableComponent() == null) {
                jComp
.setNextFocusableComponent(this);
           
}
       
}
       
return comp;
   
}

   
/**
     * Discards the editor object and frees the real estate it used for
     * cell rendering.
     */

   
public void removeEditor() {
       
KeyboardFocusManager.getCurrentKeyboardFocusManager().
            removePropertyChangeListener
("permanentFocusOwner", editorRemover);
        editorRemover
= null;

       
TableCellEditor editor = getCellEditor();
       
if(editor != null) {
            editor
.removeCellEditorListener(this);
           
if (editorComp != null) {
               
Component focusOwner =
                       
KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
               
boolean isFocusOwnerInTheTable = focusOwner != null?
                       
SwingUtilities.isDescendingFrom(focusOwner, this):false;
                remove
(editorComp);
               
if(isFocusOwnerInTheTable) {
                    requestFocusInWindow
();
               
}
           
}

           
Rectangle cellRect = getCellRect(editingRow, editingColumn, false);

            setCellEditor
(null);
            setEditingColumn
(-1);
            setEditingRow
(-1);
            editorComp
= null;

            repaint
(cellRect);
       
}
   
}

//
// Serialization
//

   
/**
     * See readObject() and writeObject() in JComponent for more
     * information about serialization in Swing.
     */

   
private void writeObject(ObjectOutputStream s) throws IOException {
        s
.defaultWriteObject();
       
if (getUIClassID().equals(uiClassID)) {
           
byte count = JComponent.getWriteObjCounter(this);
           
JComponent.setWriteObjCounter(this, --count);
           
if (count == 0 && ui != null) {
                ui
.installUI(this);
           
}
       
}
   
}

   
private void readObject(ObjectInputStream s)
       
throws IOException, ClassNotFoundException
   
{
        s
.defaultReadObject();
       
if ((ui != null) && (getUIClassID().equals(uiClassID))) {
            ui
.installUI(this);
       
}
        createDefaultRenderers
();
        createDefaultEditors
();

       
// If ToolTipText != null, then the tooltip has already been
       
// registered by JComponent.readObject() and we don't want
       
// to re-register here
       
if (getToolTipText() == null) {
           
ToolTipManager.sharedInstance().registerComponent(this);
         
}
   
}

   
/* Called from the JComponent's EnableSerializationFocusListener to
     * do any Swing-specific pre-serialization configuration.
     */

   
void compWriteObjectNotify() {
       
super.compWriteObjectNotify();
       
// If ToolTipText != null, then the tooltip has already been
       
// unregistered by JComponent.compWriteObjectNotify()
       
if (getToolTipText() == null) {
           
ToolTipManager.sharedInstance().unregisterComponent(this);
       
}
   
}

   
/**
     * Returns a string representation of this table. This method
     * is intended to be used only for debugging purposes, and the
     * content and format of the returned string may vary between
     * implementations. The returned string may be empty but may not
     * be <code>null</code>.
     *
     * @return  a string representation of this table
     */

   
protected String paramString() {
       
String gridColorString = (gridColor != null ?
                                  gridColor
.toString() : "");
       
String showHorizontalLinesString = (showHorizontalLines ?
                                           
"true" : "false");
       
String showVerticalLinesString = (showVerticalLines ?
                                         
"true" : "false");
       
String autoResizeModeString;
       
if (autoResizeMode == AUTO_RESIZE_OFF) {
            autoResizeModeString
= "AUTO_RESIZE_OFF";
       
} else if (autoResizeMode == AUTO_RESIZE_NEXT_COLUMN) {
            autoResizeModeString
= "AUTO_RESIZE_NEXT_COLUMN";
       
} else if (autoResizeMode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) {
            autoResizeModeString
= "AUTO_RESIZE_SUBSEQUENT_COLUMNS";
       
} else if (autoResizeMode == AUTO_RESIZE_LAST_COLUMN) {
            autoResizeModeString
= "AUTO_RESIZE_LAST_COLUMN";
       
} else if (autoResizeMode == AUTO_RESIZE_ALL_COLUMNS)  {
            autoResizeModeString
= "AUTO_RESIZE_ALL_COLUMNS";
       
} else autoResizeModeString = "";
       
String autoCreateColumnsFromModelString = (autoCreateColumnsFromModel ?
                                                   
"true" : "false");
       
String preferredViewportSizeString = (preferredViewportSize != null ?
                                              preferredViewportSize
.toString()
                                             
: "");
       
String rowSelectionAllowedString = (rowSelectionAllowed ?
                                           
"true" : "false");
       
String cellSelectionEnabledString = (cellSelectionEnabled ?
                                           
"true" : "false");
       
String selectionForegroundString = (selectionForeground != null ?
                                            selectionForeground
.toString() :
                                           
"");
       
String selectionBackgroundString = (selectionBackground != null ?
                                            selectionBackground
.toString() :
                                           
"");

       
return super.paramString() +
       
",autoCreateColumnsFromModel=" + autoCreateColumnsFromModelString +
       
",autoResizeMode=" + autoResizeModeString +
       
",cellSelectionEnabled=" + cellSelectionEnabledString +
       
",editingColumn=" + editingColumn +
       
",editingRow=" + editingRow +
       
",gridColor=" + gridColorString +
       
",preferredViewportSize=" + preferredViewportSizeString +
       
",rowHeight=" + rowHeight +
       
",rowMargin=" + rowMargin +
       
",rowSelectionAllowed=" + rowSelectionAllowedString +
       
",selectionBackground=" + selectionBackgroundString +
       
",selectionForeground=" + selectionForegroundString +
       
",showHorizontalLines=" + showHorizontalLinesString +
       
",showVerticalLines=" + showVerticalLinesString;
   
}

   
// This class tracks changes in the keyboard focus state. It is used
   
// when the JTable is editing to determine when to cancel the edit.
   
// If focus switches to a component outside of the jtable, but in the
   
// same window, this will cancel editing.
   
class CellEditorRemover implements PropertyChangeListener {
       
KeyboardFocusManager focusManager;

       
public CellEditorRemover(KeyboardFocusManager fm) {
           
this.focusManager = fm;
       
}

       
public void propertyChange(PropertyChangeEvent ev) {
           
if (!isEditing() || getClientProperty("terminateEditOnFocusLost") != Boolean.TRUE) {
               
return;
           
}

           
Component c = focusManager.getPermanentFocusOwner();
           
while (c != null) {
               
if (c == JTable.this) {
                   
// focus remains inside the table
                   
return;
               
} else if ((c instanceof Window) ||
                           
(c instanceof Applet && c.getParent() == null)) {
                   
if (c == SwingUtilities.getRoot(JTable.this)) {
                       
if (!getCellEditor().stopCellEditing()) {
                            getCellEditor
().cancelCellEditing();
                       
}
                   
}
                   
break;
               
}
                c
= c.getParent();
           
}
       
}
   
}

/////////////////
// Printing Support
/////////////////

   
/**
     * A convenience method that displays a printing dialog, and then prints
     * this <code>JTable</code> in mode <code>PrintMode.FIT_WIDTH</code>,
     * with no header or footer text. A modal progress dialog, with an abort
     * option, will be shown for the duration of printing.
     * <p>
     * Note: In headless mode, no dialogs are shown and printing
     * occurs on the default printer.
     *
     * @return true, unless printing is cancelled by the user
     * @throws SecurityException if this thread is not allowed to
     *                           initiate a print job request
     * @throws PrinterException if an error in the print system causes the job
     *                          to be aborted
     * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
     *             boolean, PrintRequestAttributeSet, boolean, PrintService)
     * @see #getPrintable
     *
     * @since 1.5
     */

   
public boolean print() throws PrinterException {

       
return print(PrintMode.FIT_WIDTH);
   
}

   
/**
     * A convenience method that displays a printing dialog, and then prints
     * this <code>JTable</code> in the given printing mode,
     * with no header or footer text. A modal progress dialog, with an abort
     * option, will be shown for the duration of printing.
     * <p>
     * Note: In headless mode, no dialogs are shown and printing
     * occurs on the default printer.
     *
     * @param  printMode        the printing mode that the printable should use
     * @return true, unless printing is cancelled by the user
     * @throws SecurityException if this thread is not allowed to
     *                           initiate a print job request
     * @throws PrinterException if an error in the print system causes the job
     *                          to be aborted
     * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
     *             boolean, PrintRequestAttributeSet, boolean, PrintService)
     * @see #getPrintable
     *
     * @since 1.5
     */

   
public boolean print(PrintMode printMode) throws PrinterException {

       
return print(printMode, null, null);
   
}

   
/**
     * A convenience method that displays a printing dialog, and then prints
     * this <code>JTable</code> in the given printing mode,
     * with the specified header and footer text. A modal progress dialog,
     * with an abort option, will be shown for the duration of printing.
     * <p>
     * Note: In headless mode, no dialogs are shown and printing
     * occurs on the default printer.
     *
     * @param  printMode        the printing mode that the printable should use
     * @param  headerFormat     a <code>MessageFormat</code> specifying the text
     *                          to be used in printing a header,
     *                          or null for none
     * @param  footerFormat     a <code>MessageFormat</code> specifying the text
     *                          to be used in printing a footer,
     *                          or null for none
     * @return true, unless printing is cancelled by the user
     * @throws SecurityException if this thread is not allowed to
     *                           initiate a print job request
     * @throws PrinterException if an error in the print system causes the job
     *                          to be aborted
     * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
     *             boolean, PrintRequestAttributeSet, boolean, PrintService)
     * @see #getPrintable
     *
     * @since 1.5
     */

   
public boolean print(PrintMode printMode,
                         
MessageFormat headerFormat,
                         
MessageFormat footerFormat) throws PrinterException {

       
boolean showDialogs = !GraphicsEnvironment.isHeadless();
       
return print(printMode, headerFormat, footerFormat,
                     showDialogs
, null, showDialogs);
   
}

   
/**
     * Prints this table, as specified by the fully featured
     * {@link #print(JTable.PrintMode, MessageFormat, MessageFormat,
     * boolean, PrintRequestAttributeSet, boolean, PrintService) print}
     * method, with the default printer specified as the print service.
     *
     * @param  printMode        the printing mode that the printable should use
     * @param  headerFormat     a <code>MessageFormat</code> specifying the text
     *                          to be used in printing a header,
     *                          or <code>null</code> for none
     * @param  footerFormat     a <code>MessageFormat</code> specifying the text
     *                          to be used in printing a footer,
     *                          or <code>null</code> for none
     * @param  showPrintDialog  whether or not to display a print dialog
     * @param  attr             a <code>PrintRequestAttributeSet</code>
     *                          specifying any printing attributes,
     *                          or <code>null</code> for none
     * @param  interactive      whether or not to print in an interactive mode
     * @return true, unless printing is cancelled by the user
     * @throws HeadlessException if the method is asked to show a printing
     *                           dialog or run interactively, and
     *                           <code>GraphicsEnvironment.isHeadless</code>
     *                           returns <code>true</code>
     * @throws SecurityException if this thread is not allowed to
     *                           initiate a print job request
     * @throws PrinterException if an error in the print system causes the job
     *                          to be aborted
     * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
     *             boolean, PrintRequestAttributeSet, boolean, PrintService)
     * @see #getPrintable
     *
     * @since 1.5
     */

   
public boolean print(PrintMode printMode,
                         
MessageFormat headerFormat,
                         
MessageFormat footerFormat,
                         
boolean showPrintDialog,
                         
PrintRequestAttributeSet attr,
                         
boolean interactive) throws PrinterException,
                                                     
HeadlessException {

       
return print(printMode,
                     headerFormat
,
                     footerFormat
,
                     showPrintDialog
,
                     attr
,
                     interactive
,
                     
null);
   
}

   
/**
     * Prints this <code>JTable</code>. Takes steps that the majority of
     * developers would take in order to print a <code>JTable</code>.
     * In short, it prepares the table, calls <code>getPrintable</code> to
     * fetch an appropriate <code>Printable</code>, and then sends it to the
     * printer.
     * <p>
     * A <code>boolean</code> parameter allows you to specify whether or not
     * a printing dialog is displayed to the user. When it is, the user may
     * use the dialog to change the destination printer or printing attributes,
     * or even to cancel the print. Another two parameters allow for a
     * <code>PrintService</code> and printing attributes to be specified.
     * These parameters can be used either to provide initial values for the
     * print dialog, or to specify values when the dialog is not shown.
     * <p>
     * A second <code>boolean</code> parameter allows you to specify whether
     * or not to perform printing in an interactive mode. If <code>true</code>,
     * a modal progress dialog, with an abort option, is displayed for the
     * duration of printing . This dialog also prevents any user action which
     * may affect the table. However, it can not prevent the table from being
     * modified by code (for example, another thread that posts updates using
     * <code>SwingUtilities.invokeLater</code>). It is therefore the
     * responsibility of the developer to ensure that no other code modifies
     * the table in any way during printing (invalid modifications include
     * changes in: size, renderers, or underlying data). Printing behavior is
     * undefined when the table is changed during printing.
     * <p>
     * If <code>false</code> is specified for this parameter, no dialog will
     * be displayed and printing will begin immediately on the event-dispatch
     * thread. This blocks any other events, including repaints, from being
     * processed until printing is complete. Although this effectively prevents
     * the table from being changed, it doesn't provide a good user experience.
     * For this reason, specifying <code>false</code> is only recommended when
     * printing from an application with no visible GUI.
     * <p>
     * Note: Attempting to show the printing dialog or run interactively, while
     * in headless mode, will result in a <code>HeadlessException</code>.
     * <p>
     * Before fetching the printable, this method will gracefully terminate
     * editing, if necessary, to prevent an editor from showing in the printed
     * result. Additionally, <code>JTable</code> will prepare its renderers
     * during printing such that selection and focus are not indicated.
     * As far as customizing further how the table looks in the printout,
     * developers can provide custom renderers or paint code that conditionalize
     * on the value of {@link javax.swing.JComponent#isPaintingForPrint()}.
     * <p>
     * See {@link #getPrintable} for more description on how the table is
     * printed.
     *
     * @param  printMode        the printing mode that the printable should use
     * @param  headerFormat     a <code>MessageFormat</code> specifying the text
     *                          to be used in printing a header,
     *                          or <code>null</code> for none
     * @param  footerFormat     a <code>MessageFormat</code> specifying the text
     *                          to be used in printing a footer,
     *                          or <code>null</code> for none
     * @param  showPrintDialog  whether or not to display a print dialog
     * @param  attr             a <code>PrintRequestAttributeSet</code>
     *                          specifying any printing attributes,
     *                          or <code>null</code> for none
     * @param  interactive      whether or not to print in an interactive mode
     * @param  service          the destination <code>PrintService</code>,
     *                          or <code>null</code> to use the default printer
     * @return true, unless printing is cancelled by the user
     * @throws HeadlessException if the method is asked to show a printing
     *                           dialog or run interactively, and
     *                           <code>GraphicsEnvironment.isHeadless</code>
     *                           returns <code>true</code>
     * @throws  SecurityException if a security manager exists and its
     *          {@link java.lang.SecurityManager#checkPrintJobAccess}
     *          method disallows this thread from creating a print job request
     * @throws PrinterException if an error in the print system causes the job
     *                          to be aborted
     * @see #getPrintable
     * @see java.awt.GraphicsEnvironment#isHeadless
     *
     * @since 1.6
     */

   
public boolean print(PrintMode printMode,
                         
MessageFormat headerFormat,
                         
MessageFormat footerFormat,
                         
boolean showPrintDialog,
                         
PrintRequestAttributeSet attr,
                         
boolean interactive,
                         
PrintService service) throws PrinterException,
                                                     
HeadlessException {

       
// complain early if an invalid parameter is specified for headless mode
       
boolean isHeadless = GraphicsEnvironment.isHeadless();
       
if (isHeadless) {
           
if (showPrintDialog) {
               
throw new HeadlessException("Can't show print dialog.");
           
}

           
if (interactive) {
               
throw new HeadlessException("Can't run interactively.");
           
}
       
}

       
// Get a PrinterJob.
       
// Do this before anything with side-effects since it may throw a
       
// security exception - in which case we don't want to do anything else.
       
final PrinterJob job = PrinterJob.getPrinterJob();

       
if (isEditing()) {
           
// try to stop cell editing, and failing that, cancel it
           
if (!getCellEditor().stopCellEditing()) {
                getCellEditor
().cancelCellEditing();
           
}
       
}

       
if (attr == null) {
            attr
= new HashPrintRequestAttributeSet();
       
}

       
final PrintingStatus printingStatus;

         
// fetch the Printable
       
Printable printable =
             getPrintable
(printMode, headerFormat, footerFormat);

       
if (interactive) {
           
// wrap the Printable so that we can print on another thread
            printable
= new ThreadSafePrintable(printable);
            printingStatus
= PrintingStatus.createPrintingStatus(this, job);
            printable
= printingStatus.createNotificationPrintable(printable);
       
} else {
           
// to please compiler
            printingStatus
= null;
       
}

       
// set the printable on the PrinterJob
        job
.setPrintable(printable);

       
// if specified, set the PrintService on the PrinterJob
       
if (service != null) {
            job
.setPrintService(service);
       
}

       
// if requested, show the print dialog
       
if (showPrintDialog && !job.printDialog(attr)) {
           
// the user cancelled the print dialog
           
return false;
       
}

       
// if not interactive, just print on this thread (no dialog)
       
if (!interactive) {
           
// do the printing
            job
.print(attr);

           
// we're done
           
return true;
       
}

       
// make sure this is clear since we'll check it after
        printError
= null;

       
// to synchronize on
       
final Object lock = new Object();

       
// copied so we can access from the inner class
       
final PrintRequestAttributeSet copyAttr = attr;

       
// this runnable will be used to do the printing
       
// (and save any throwables) on another thread
       
Runnable runnable = new Runnable() {
           
public void run() {
               
try {
                   
// do the printing
                    job
.print(copyAttr);
               
} catch (Throwable t) {
                   
// save any Throwable to be rethrown
                   
synchronized(lock) {
                        printError
= t;
                   
}
               
} finally {
                   
// we're finished - hide the dialog
                    printingStatus
.dispose();
               
}
           
}
       
};

       
// start printing on another thread
       
Thread th = new Thread(runnable);
        th
.start();

        printingStatus
.showModal(true);

       
// look for any error that the printing may have generated
       
Throwable pe;
       
synchronized(lock) {
            pe
= printError;
            printError
= null;
       
}

       
// check the type of error and handle it
       
if (pe != null) {
           
// a subclass of PrinterException meaning the job was aborted,
           
// in this case, by the user
           
if (pe instanceof PrinterAbortException) {
               
return false;
           
} else if (pe instanceof PrinterException) {
               
throw (PrinterException)pe;
           
} else if (pe instanceof RuntimeException) {
               
throw (RuntimeException)pe;
           
} else if (pe instanceof Error) {
               
throw (Error)pe;
           
}

           
// can not happen
           
throw new AssertionError(pe);
       
}

       
return true;
   
}

   
/**
     * Return a <code>Printable</code> for use in printing this JTable.
     * <p>
     * This method is meant for those wishing to customize the default
     * <code>Printable</code> implementation used by <code>JTable</code>'s
     * <code>print</code> methods. Developers wanting simply to print the table
     * should use one of those methods directly.
     * <p>
     * The <code>Printable</code> can be requested in one of two printing modes.
     * In both modes, it spreads table rows naturally in sequence across
     * multiple pages, fitting as many rows as possible per page.
     * <code>PrintMode.NORMAL</code> specifies that the table be
     * printed at its current size. In this mode, there may be a need to spread
     * columns across pages in a similar manner to that of the rows. When the
     * need arises, columns are distributed in an order consistent with the
     * table's <code>ComponentOrientation</code>.
     * <code>PrintMode.FIT_WIDTH</code> specifies that the output be
     * scaled smaller, if necessary, to fit the table's entire width
     * (and thereby all columns) on each page. Width and height are scaled
     * equally, maintaining the aspect ratio of the output.
     * <p>
     * The <code>Printable</code> heads the portion of table on each page
     * with the appropriate section from the table's <code>JTableHeader</code>,
     * if it has one.
     * <p>
     * Header and footer text can be added to the output by providing
     * <code>MessageFormat</code> arguments. The printing code requests
     * Strings from the formats, providing a single item which may be included
     * in the formatted string: an <code>Integer</code> representing the current
     * page number.
     * <p>
     * You are encouraged to read the documentation for
     * <code>MessageFormat</code> as some characters, such as single-quote,
     * are special and need to be escaped.
     * <p>
     * Here's an example of creating a <code>MessageFormat</code> that can be
     * used to print "Duke's Table: Page - " and the current page number:
     * <p>
     * <pre>
     *     // notice the escaping of the single quote
     *     // notice how the page number is included with "{0}"
     *     MessageFormat format = new MessageFormat("Duke''s Table: Page - {0}");
     * </pre>
     * <p>
     * The <code>Printable</code> constrains what it draws to the printable
     * area of each page that it prints. Under certain circumstances, it may
     * find it impossible to fit all of a page's content into that area. In
     * these cases the output may be clipped, but the implementation
     * makes an effort to do something reasonable. Here are a few situations
     * where this is known to occur, and how they may be handled by this
     * particular implementation:
     * <ul>
     *   <li>In any mode, when the header or footer text is too wide to fit
     *       completely in the printable area -- print as much of the text as
     *       possible starting from the beginning, as determined by the table's
     *       <code>ComponentOrientation</code>.
     *   <li>In any mode, when a row is too tall to fit in the
     *       printable area -- print the upper-most portion of the row
     *       and paint no lower border on the table.
     *   <li>In <code>PrintMode.NORMAL</code> when a column
     *       is too wide to fit in the printable area -- print the center
     *       portion of the column and leave the left and right borders
     *       off the table.
     * </ul>
     * <p>
     * It is entirely valid for this <code>Printable</code> to be wrapped
     * inside another in order to create complex reports and documents. You may
     * even request that different pages be rendered into different sized
     * printable areas. The implementation must be prepared to handle this
     * (possibly by doing its layout calculations on the fly). However,
     * providing different heights to each page will likely not work well
     * with <code>PrintMode.NORMAL</code> when it has to spread columns
     * across pages.
     * <p>
     * As far as customizing how the table looks in the printed result,
     * <code>JTable</code> itself will take care of hiding the selection
     * and focus during printing. For additional customizations, your
     * renderers or painting code can customize the look based on the value
     * of {@link javax.swing.JComponent#isPaintingForPrint()}
     * <p>
     * Also, <i>before</i> calling this method you may wish to <i>first</i>
     * modify the state of the table, such as to cancel cell editing or
     * have the user size the table appropriately. However, you must not
     * modify the state of the table <i>after</i> this <code>Printable</code>
     * has been fetched (invalid modifications include changes in size or
     * underlying data). The behavior of the returned <code>Printable</code>
     * is undefined once the table has been changed.
     *
     * @param  printMode     the printing mode that the printable should use
     * @param  headerFormat  a <code>MessageFormat</code> specifying the text to
     *                       be used in printing a header, or null for none
     * @param  footerFormat  a <code>MessageFormat</code> specifying the text to
     *                       be used in printing a footer, or null for none
     * @return a <code>Printable</code> for printing this JTable
     * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
     *             boolean, PrintRequestAttributeSet, boolean)
     * @see Printable
     * @see PrinterJob
     *
     * @since 1.5
     */

   
public Printable getPrintable(PrintMode printMode,
                                 
MessageFormat headerFormat,
                                 
MessageFormat footerFormat) {

       
return new TablePrintable(this, printMode, headerFormat, footerFormat);
   
}


   
/**
     * A <code>Printable</code> implementation that wraps another
     * <code>Printable</code>, making it safe for printing on another thread.
     */

   
private class ThreadSafePrintable implements Printable {

       
/** The delegate <code>Printable</code>. */
       
private Printable printDelegate;

       
/**
         * To communicate any return value when delegating.
         */

       
private int retVal;

       
/**
         * To communicate any <code>Throwable</code> when delegating.
         */

       
private Throwable retThrowable;

       
/**
         * Construct a <code>ThreadSafePrintable</code> around the given
         * delegate.
         *
         * @param printDelegate the <code>Printable</code> to delegate to
         */

       
public ThreadSafePrintable(Printable printDelegate) {
           
this.printDelegate = printDelegate;
       
}

       
/**
         * Prints the specified page into the given {@link Graphics}
         * context, in the specified format.
         * <p>
         * Regardless of what thread this method is called on, all calls into
         * the delegate will be done on the event-dispatch thread.
         *
         * @param   graphics    the context into which the page is drawn
         * @param   pageFormat  the size and orientation of the page being drawn
         * @param   pageIndex   the zero based index of the page to be drawn
         * @return  PAGE_EXISTS if the page is rendered successfully, or
         *          NO_SUCH_PAGE if a non-existent page index is specified
         * @throws  PrinterException if an error causes printing to be aborted
         */

       
public int print(final Graphics graphics,
                         
final PageFormat pageFormat,
                         
final int pageIndex) throws PrinterException {

           
// We'll use this Runnable
           
Runnable runnable = new Runnable() {
               
public synchronized void run() {
                   
try {
                       
// call into the delegate and save the return value
                        retVal
= printDelegate.print(graphics, pageFormat, pageIndex);
                   
} catch (Throwable throwable) {
                       
// save any Throwable to be rethrown
                        retThrowable
= throwable;
                   
} finally {
                       
// notify the caller that we're done
                        notifyAll
();
                   
}
               
}
           
};

           
synchronized(runnable) {
               
// make sure these are initialized
                retVal
= -1;
                retThrowable
= null;

               
// call into the EDT
               
SwingUtilities.invokeLater(runnable);

               
// wait for the runnable to finish
               
while (retVal == -1 && retThrowable == null) {
                   
try {
                        runnable
.wait();
                   
} catch (InterruptedException ie) {
                       
// short process, safe to ignore interrupts
                   
}
               
}

               
// if the delegate threw a throwable, rethrow it here
               
if (retThrowable != null) {
                   
if (retThrowable instanceof PrinterException) {
                       
throw (PrinterException)retThrowable;
                   
} else if (retThrowable instanceof RuntimeException) {
                       
throw (RuntimeException)retThrowable;
                   
} else if (retThrowable instanceof Error) {
                       
throw (Error)retThrowable;
                   
}

                   
// can not happen
                   
throw new AssertionError(retThrowable);
               
}

               
return retVal;
           
}
       
}
   
}


/////////////////
// Accessibility support
////////////////

   
/**
     * Gets the AccessibleContext associated with this JTable.
     * For tables, the AccessibleContext takes the form of an
     * AccessibleJTable.
     * A new AccessibleJTable instance is created if necessary.
     *
     * @return an AccessibleJTable that serves as the
     *         AccessibleContext of this JTable
     */

   
public AccessibleContext getAccessibleContext() {
       
if (accessibleContext == null) {
            accessibleContext
= new AccessibleJTable();
       
}
       
return accessibleContext;
   
}

   
//
   
// *** should also implement AccessibleSelection?
   
// *** and what's up with keyboard navigation/manipulation?
   
//
   
/**
     * This class implements accessibility support for the
     * <code>JTable</code> class.  It provides an implementation of the
     * Java Accessibility API appropriate to table user-interface elements.
     * <p>
     * <strong>Warning:</strong>
     * Serialized objects of this class will not be compatible with
     * future Swing releases. The current serialization support is
     * appropriate for short term storage or RMI between applications running
     * the same version of Swing.  As of 1.4, support for long term storage
     * of all JavaBeans<sup><font size="-2">TM</font></sup>
     * has been added to the <code>java.beans</code> package.
     * Please see {@link java.beans.XMLEncoder}.
     */

   
protected class AccessibleJTable extends AccessibleJComponent
   
implements AccessibleSelection, ListSelectionListener, TableModelListener,
   
TableColumnModelListener, CellEditorListener, PropertyChangeListener,
   
AccessibleExtendedTable {

       
int lastSelectedRow;
       
int lastSelectedCol;

       
/**
         * AccessibleJTable constructor
         *
         * @since 1.5
         */

       
protected AccessibleJTable() {
           
super();
           
JTable.this.addPropertyChangeListener(this);
           
JTable.this.getSelectionModel().addListSelectionListener(this);
           
TableColumnModel tcm = JTable.this.getColumnModel();
            tcm
.addColumnModelListener(this);
            tcm
.getSelectionModel().addListSelectionListener(this);
           
JTable.this.getModel().addTableModelListener(this);
            lastSelectedRow
= JTable.this.getSelectedRow();
            lastSelectedCol
= JTable.this.getSelectedColumn();
       
}

   
// Listeners to track model, etc. changes to as to re-place the other
   
// listeners

       
/**
         * Track changes to selection model, column model, etc. so as to
         * be able to re-place listeners on those in order to pass on
         * information to the Accessibility PropertyChange mechanism
         */

       
public void propertyChange(PropertyChangeEvent e) {
           
String name = e.getPropertyName();
           
Object oldValue = e.getOldValue();
           
Object newValue = e.getNewValue();

               
// re-set tableModel listeners
           
if (name.compareTo("model") == 0) {

               
if (oldValue != null && oldValue instanceof TableModel) {
                   
((TableModel) oldValue).removeTableModelListener(this);
               
}
               
if (newValue != null && newValue instanceof TableModel) {
                   
((TableModel) newValue).addTableModelListener(this);
               
}

               
// re-set selectionModel listeners
           
} else if (name.compareTo("selectionModel") == 0) {

               
Object source = e.getSource();
               
if (source == JTable.this) {    // row selection model

                   
if (oldValue != null &&
                        oldValue
instanceof ListSelectionModel) {
                       
((ListSelectionModel) oldValue).removeListSelectionListener(this);
                   
}
                   
if (newValue != null &&
                        newValue
instanceof ListSelectionModel) {
                       
((ListSelectionModel) newValue).addListSelectionListener(this);
                   
}

               
} else if (source == JTable.this.getColumnModel()) {

                   
if (oldValue != null &&
                        oldValue
instanceof ListSelectionModel) {
                       
((ListSelectionModel) oldValue).removeListSelectionListener(this);
                   
}
                   
if (newValue != null &&
                        newValue
instanceof ListSelectionModel) {
                       
((ListSelectionModel) newValue).addListSelectionListener(this);
                   
}

               
} else {
                 
//        System.out.println("!!! Bug in source of selectionModel propertyChangeEvent");
               
}

               
// re-set columnModel listeners
               
// and column's selection property listener as well
           
} else if (name.compareTo("columnModel") == 0) {

               
if (oldValue != null && oldValue instanceof TableColumnModel) {
                   
TableColumnModel tcm = (TableColumnModel) oldValue;
                    tcm
.removeColumnModelListener(this);
                    tcm
.getSelectionModel().removeListSelectionListener(this);
               
}
               
if (newValue != null && newValue instanceof TableColumnModel) {
                   
TableColumnModel tcm = (TableColumnModel) newValue;
                    tcm
.addColumnModelListener(this);
                    tcm
.getSelectionModel().addListSelectionListener(this);
               
}

               
// re-se cellEditor listeners
           
} else if (name.compareTo("tableCellEditor") == 0) {

               
if (oldValue != null && oldValue instanceof TableCellEditor) {
                   
((TableCellEditor) oldValue).removeCellEditorListener((CellEditorListener) this);
               
}
               
if (newValue != null && newValue instanceof TableCellEditor) {
                   
((TableCellEditor) newValue).addCellEditorListener((CellEditorListener) this);
               
}
           
}
       
}


   
// Listeners to echo changes to the AccessiblePropertyChange mechanism

       
/*
         * Describes a change in the accessible table model.
         */

       
protected class AccessibleJTableModelChange
           
implements AccessibleTableModelChange {

           
protected int type;
           
protected int firstRow;
           
protected int lastRow;
           
protected int firstColumn;
           
protected int lastColumn;

           
protected AccessibleJTableModelChange(int type, int firstRow,
                                                 
int lastRow, int firstColumn,
                                                 
int lastColumn) {
               
this.type = type;
               
this.firstRow = firstRow;
               
this.lastRow = lastRow;
               
this.firstColumn = firstColumn;
               
this.lastColumn = lastColumn;
           
}

           
public int getType() {
               
return type;
           
}

           
public int getFirstRow() {
               
return firstRow;
           
}

           
public int getLastRow() {
               
return lastRow;
           
}

           
public int getFirstColumn() {
               
return firstColumn;
           
}

           
public int getLastColumn() {
               
return lastColumn;
           
}
       
}

       
/**
         * Track changes to the table contents
         */

       
public void tableChanged(TableModelEvent e) {
           firePropertyChange
(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
                             
null, null);
           
if (e != null) {
               
int firstColumn = e.getColumn();
               
int lastColumn = e.getColumn();
               
if (firstColumn == TableModelEvent.ALL_COLUMNS) {
                   firstColumn
= 0;
                   lastColumn
= getColumnCount() - 1;
               
}

               
// Fire a property change event indicating the table model
               
// has changed.
               
AccessibleJTableModelChange change =
                   
new AccessibleJTableModelChange(e.getType(),
                                                   e
.getFirstRow(),
                                                   e
.getLastRow(),
                                                   firstColumn
,
                                                   lastColumn
);
               firePropertyChange
(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
                                 
null, change);
           
}
       
}

       
/**
         * Track changes to the table contents (row insertions)
         */

       
public void tableRowsInserted(TableModelEvent e) {
           firePropertyChange
(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
                             
null, null);

           
// Fire a property change event indicating the table model
           
// has changed.
           
int firstColumn = e.getColumn();
           
int lastColumn = e.getColumn();
           
if (firstColumn == TableModelEvent.ALL_COLUMNS) {
               firstColumn
= 0;
               lastColumn
= getColumnCount() - 1;
           
}
           
AccessibleJTableModelChange change =
               
new AccessibleJTableModelChange(e.getType(),
                                               e
.getFirstRow(),
                                               e
.getLastRow(),
                                               firstColumn
,
                                               lastColumn
);
           firePropertyChange
(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
                             
null, change);
       
}

       
/**
         * Track changes to the table contents (row deletions)
         */

       
public void tableRowsDeleted(TableModelEvent e) {
           firePropertyChange
(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
                             
null, null);

           
// Fire a property change event indicating the table model
           
// has changed.
           
int firstColumn = e.getColumn();
           
int lastColumn = e.getColumn();
           
if (firstColumn == TableModelEvent.ALL_COLUMNS) {
               firstColumn
= 0;
               lastColumn
= getColumnCount() - 1;
           
}
           
AccessibleJTableModelChange change =
               
new AccessibleJTableModelChange(e.getType(),
                                               e
.getFirstRow(),
                                               e
.getLastRow(),
                                               firstColumn
,
                                               lastColumn
);
           firePropertyChange
(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
                             
null, change);
       
}

       
/**
         * Track changes to the table contents (column insertions)
         */

       
public void columnAdded(TableColumnModelEvent e) {
           firePropertyChange
(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
                             
null, null);

           
// Fire a property change event indicating the table model
           
// has changed.
           
int type = AccessibleTableModelChange.INSERT;
           
AccessibleJTableModelChange change =
               
new AccessibleJTableModelChange(type,
                                               
0,
                                               
0,
                                               e
.getFromIndex(),
                                               e
.getToIndex());
           firePropertyChange
(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
                             
null, change);
       
}

       
/**
         * Track changes to the table contents (column deletions)
         */

       
public void columnRemoved(TableColumnModelEvent e) {
           firePropertyChange
(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
                             
null, null);
           
// Fire a property change event indicating the table model
           
// has changed.
           
int type = AccessibleTableModelChange.DELETE;
           
AccessibleJTableModelChange change =
               
new AccessibleJTableModelChange(type,
                                               
0,
                                               
0,
                                               e
.getFromIndex(),
                                               e
.getToIndex());
           firePropertyChange
(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
                             
null, change);
       
}

       
/**
         * Track changes of a column repositioning.
         *
         * @see TableColumnModelListener
         */

       
public void columnMoved(TableColumnModelEvent e) {
           firePropertyChange
(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
                             
null, null);

           
// Fire property change events indicating the table model
           
// has changed.
           
int type = AccessibleTableModelChange.DELETE;
           
AccessibleJTableModelChange change =
               
new AccessibleJTableModelChange(type,
                                               
0,
                                               
0,
                                               e
.getFromIndex(),
                                               e
.getFromIndex());
           firePropertyChange
(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
                             
null, change);

           
int type2 = AccessibleTableModelChange.INSERT;
           
AccessibleJTableModelChange change2 =
               
new AccessibleJTableModelChange(type2,
                                               
0,
                                               
0,
                                               e
.getToIndex(),
                                               e
.getToIndex());
           firePropertyChange
(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
                             
null, change2);
       
}

       
/**
         * Track changes of a column moving due to margin changes.
         *
         * @see TableColumnModelListener
         */

       
public void columnMarginChanged(ChangeEvent e) {
           firePropertyChange
(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
                             
null, null);
       
}

       
/**
         * Track that the selection model of the TableColumnModel changed.
         *
         * @see TableColumnModelListener
         */

       
public void columnSelectionChanged(ListSelectionEvent e) {
           
// we should now re-place our TableColumn listener
       
}

       
/**
         * Track changes to a cell's contents.
         *
         * Invoked when editing is finished. The changes are saved, the
         * editor object is discarded, and the cell is rendered once again.
         *
         * @see CellEditorListener
         */

       
public void editingStopped(ChangeEvent e) {
           
// it'd be great if we could figure out which cell, and pass that
           
// somehow as a parameter
           firePropertyChange
(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
                             
null, null);
       
}

       
/**
         * Invoked when editing is canceled. The editor object is discarded
         * and the cell is rendered once again.
         *
         * @see CellEditorListener
         */

       
public void editingCanceled(ChangeEvent e) {
           
// nothing to report, 'cause nothing changed
       
}

       
/**
         * Track changes to table cell selections
         */

       
public void valueChanged(ListSelectionEvent e) {
            firePropertyChange
(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
                               
Boolean.valueOf(false), Boolean.valueOf(true));

           
int selectedRow = JTable.this.getSelectedRow();
           
int selectedCol = JTable.this.getSelectedColumn();
           
if (selectedRow != lastSelectedRow ||
                selectedCol
!= lastSelectedCol) {
               
Accessible oldA = getAccessibleAt(lastSelectedRow,
                                                  lastSelectedCol
);
               
Accessible newA = getAccessibleAt(selectedRow, selectedCol);
                firePropertyChange
(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
                                   oldA
, newA);
                 lastSelectedRow
= selectedRow;
                 lastSelectedCol
= selectedCol;
             
}
       
}




   
// AccessibleContext support

       
/**
         * Get the AccessibleSelection associated with this object.  In the
         * implementation of the Java Accessibility API for this class,
         * return this object, which is responsible for implementing the
         * AccessibleSelection interface on behalf of itself.
         *
         * @return this object
         */

       
public AccessibleSelection getAccessibleSelection() {
           
return this;
       
}

       
/**
         * Gets the role of this object.
         *
         * @return an instance of AccessibleRole describing the role of the
         * object
         * @see AccessibleRole
         */

       
public AccessibleRole getAccessibleRole() {
           
return AccessibleRole.TABLE;
       
}

       
/**
         * Returns the <code>Accessible</code> child, if one exists,
         * contained at the local coordinate <code>Point</code>.
         *
         * @param p the point defining the top-left corner of the
         *    <code>Accessible</code>, given in the coordinate space
         *    of the object's parent
         * @return the <code>Accessible</code>, if it exists,
         *    at the specified location; else <code>null</code>
         */

       
public Accessible getAccessibleAt(Point p) {
           
int column = columnAtPoint(p);
           
int row = rowAtPoint(p);

           
if ((column != -1) && (row != -1)) {
               
TableColumn aColumn = getColumnModel().getColumn(column);
               
TableCellRenderer renderer = aColumn.getCellRenderer();
               
if (renderer == null) {
                   
Class<?> columnClass = getColumnClass(column);
                    renderer
= getDefaultRenderer(columnClass);
               
}
               
Component component = renderer.getTableCellRendererComponent(
                                 
JTable.this, null, false, false,
                                  row
, column);
               
return new AccessibleJTableCell(JTable.this, row, column,
                      getAccessibleIndexAt
(row, column));
           
}
           
return null;
       
}

       
/**
         * Returns the number of accessible children in the object.  If all
         * of the children of this object implement <code>Accessible</code>,
         * then this method should return the number of children of this object.
         *
         * @return the number of accessible children in the object
         */

       
public int getAccessibleChildrenCount() {
           
return (JTable.this.getColumnCount() * JTable.this.getRowCount());
       
}

       
/**
         * Returns the nth <code>Accessible</code> child of the object.
         *
         * @param i zero-based index of child
         * @return the nth Accessible child of the object
         */

       
public Accessible getAccessibleChild(int i) {
           
if (i < 0 || i >= getAccessibleChildrenCount()) {
               
return null;
           
} else {
               
// children increase across, and then down, for tables
               
// (arbitrary decision)
               
int column = getAccessibleColumnAtIndex(i);
               
int row = getAccessibleRowAtIndex(i);

               
TableColumn aColumn = getColumnModel().getColumn(column);
               
TableCellRenderer renderer = aColumn.getCellRenderer();
               
if (renderer == null) {
                   
Class<?> columnClass = getColumnClass(column);
                    renderer
= getDefaultRenderer(columnClass);
               
}
               
Component component = renderer.getTableCellRendererComponent(
                                 
JTable.this, null, false, false,
                                  row
, column);
               
return new AccessibleJTableCell(JTable.this, row, column,
                      getAccessibleIndexAt
(row, column));
           
}
       
}

   
// AccessibleSelection support

       
/**
         * Returns the number of <code>Accessible</code> children
         * currently selected.
         * If no children are selected, the return value will be 0.
         *
         * @return the number of items currently selected
         */

       
public int getAccessibleSelectionCount() {
           
int rowsSel = JTable.this.getSelectedRowCount();
           
int colsSel = JTable.this.getSelectedColumnCount();

           
if (JTable.this.cellSelectionEnabled) { // a contiguous block
               
return rowsSel * colsSel;

           
} else {
               
// a column swath and a row swath, with a shared block
               
if (JTable.this.getRowSelectionAllowed() &&
                   
JTable.this.getColumnSelectionAllowed()) {
                   
return rowsSel * JTable.this.getColumnCount() +
                           colsSel
* JTable.this.getRowCount() -
                           rowsSel
* colsSel;

               
// just one or more rows in selection
               
} else if (JTable.this.getRowSelectionAllowed()) {
                   
return rowsSel * JTable.this.getColumnCount();

               
// just one or more rows in selection
               
} else if (JTable.this.getColumnSelectionAllowed()) {
                   
return colsSel * JTable.this.getRowCount();

               
} else {
                   
return 0;    // JTable doesn't allow selections
               
}
           
}
       
}

       
/**
         * Returns an <code>Accessible</code> representing the
         * specified selected child in the object.  If there
         * isn't a selection, or there are fewer children selected
         * than the integer passed in, the return
         * value will be <code>null</code>.
         * <p>Note that the index represents the i-th selected child, which
         * is different from the i-th child.
         *
         * @param i the zero-based index of selected children
         * @return the i-th selected child
         * @see #getAccessibleSelectionCount
         */

       
public Accessible getAccessibleSelection(int i) {
           
if (i < 0 || i > getAccessibleSelectionCount()) {
               
return (Accessible) null;
           
}

           
int rowsSel = JTable.this.getSelectedRowCount();
           
int colsSel = JTable.this.getSelectedColumnCount();
           
int rowIndicies[] = getSelectedRows();
           
int colIndicies[] = getSelectedColumns();
           
int ttlCols = JTable.this.getColumnCount();
           
int ttlRows = JTable.this.getRowCount();
           
int r;
           
int c;

           
if (JTable.this.cellSelectionEnabled) { // a contiguous block
                r
= rowIndicies[i / colsSel];
                c
= colIndicies[i % colsSel];
               
return getAccessibleChild((r * ttlCols) + c);
           
} else {

               
// a column swath and a row swath, with a shared block
               
if (JTable.this.getRowSelectionAllowed() &&
                   
JTable.this.getColumnSelectionAllowed()) {

                   
// Situation:
                   
//   We have a table, like the 6x3 table below,
                   
//   wherein three colums and one row selected
                   
//   (selected cells marked with "*", unselected "0"):
                   
//
                   
//            0 * 0 * * 0
                   
//            * * * * * *
                   
//            0 * 0 * * 0
                   
//

                   
// State machine below walks through the array of
                   
// selected rows in two states: in a selected row,
                   
// and not in one; continuing until we are in a row
                   
// in which the ith selection exists.  Then we return
                   
// the appropriate cell.  In the state machine, we
                   
// always do rows above the "current" selected row first,
                   
// then the cells in the selected row.  If we're done
                   
// with the state machine before finding the requested
                   
// selected child, we handle the rows below the last
                   
// selected row at the end.
                   
//
                   
int curIndex = i;
                   
final int IN_ROW = 0;
                   
final int NOT_IN_ROW = 1;
                   
int state = (rowIndicies[0] == 0 ? IN_ROW : NOT_IN_ROW);
                   
int j = 0;
                   
int prevRow = -1;
                   
while (j < rowIndicies.length) {
                       
switch (state) {

                       
case IN_ROW:   // on individual row full of selections
                           
if (curIndex < ttlCols) { // it's here!
                                c
= curIndex % ttlCols;
                                r
= rowIndicies[j];
                               
return getAccessibleChild((r * ttlCols) + c);
                           
} else {                               // not here
                                curIndex
-= ttlCols;
                           
}
                           
// is the next row in table selected or not?
                           
if (j + 1 == rowIndicies.length ||
                                rowIndicies
[j] != rowIndicies[j+1] - 1) {
                                state
= NOT_IN_ROW;
                                prevRow
= rowIndicies[j];
                           
}
                            j
++;  // we didn't return earlier, so go to next row
                           
break;

                       
case NOT_IN_ROW:  // sparse bunch of rows of selections
                           
if (curIndex <
                               
(colsSel * (rowIndicies[j] -
                               
(prevRow == -1 ? 0 : (prevRow + 1))))) {

                               
// it's here!
                                c
= colIndicies[curIndex % colsSel];
                                r
= (j > 0 ? rowIndicies[j-1] + 1 : 0)
                                   
+ curIndex / colsSel;
                               
return getAccessibleChild((r * ttlCols) + c);
                           
} else {                               // not here
                                curIndex
-= colsSel * (rowIndicies[j] -
                               
(prevRow == -1 ? 0 : (prevRow + 1)));
                           
}
                            state
= IN_ROW;
                           
break;
                       
}
                   
}
                   
// we got here, so we didn't find it yet; find it in
                   
// the last sparse bunch of rows
                   
if (curIndex <
                       
(colsSel * (ttlRows -
                       
(prevRow == -1 ? 0 : (prevRow + 1))))) { // it's here!
                        c
= colIndicies[curIndex % colsSel];
                        r
= rowIndicies[j-1] + curIndex / colsSel + 1;
                       
return getAccessibleChild((r * ttlCols) + c);
                   
} else {                               // not here
                       
// we shouldn't get to this spot in the code!
//                      System.out.println("Bug in AccessibleJTable.getAccessibleSelection()");
                   
}

               
// one or more rows selected
               
} else if (JTable.this.getRowSelectionAllowed()) {
                    c
= i % ttlCols;
                    r
= rowIndicies[i / ttlCols];
                   
return getAccessibleChild((r * ttlCols) + c);

               
// one or more columns selected
               
} else if (JTable.this.getColumnSelectionAllowed()) {
                    c
= colIndicies[i % colsSel];
                    r
= i / colsSel;
                   
return getAccessibleChild((r * ttlCols) + c);
               
}
           
}
           
return (Accessible) null;
       
}

       
/**
         * Determines if the current child of this object is selected.
         *
         * @param i the zero-based index of the child in this
         *    <code>Accessible</code> object
         * @return true if the current child of this object is selected
         * @see AccessibleContext#getAccessibleChild
         */

       
public boolean isAccessibleChildSelected(int i) {
           
int column = getAccessibleColumnAtIndex(i);
           
int row = getAccessibleRowAtIndex(i);
           
return JTable.this.isCellSelected(row, column);
       
}

       
/**
         * Adds the specified <code>Accessible</code> child of the
         * object to the object's selection.  If the object supports
         * multiple selections, the specified child is added to
         * any existing selection, otherwise
         * it replaces any existing selection in the object.  If the
         * specified child is already selected, this method has no effect.
         * <p>
         * This method only works on <code>JTable</code>s which have
         * individual cell selection enabled.
         *
         * @param i the zero-based index of the child
         * @see AccessibleContext#getAccessibleChild
         */

       
public void addAccessibleSelection(int i) {
           
// TIGER - 4495286
           
int column = getAccessibleColumnAtIndex(i);
           
int row = getAccessibleRowAtIndex(i);
           
JTable.this.changeSelection(row, column, true, false);
       
}

       
/**
         * Removes the specified child of the object from the object's
         * selection.  If the specified item isn't currently selected, this
         * method has no effect.
         * <p>
         * This method only works on <code>JTables</code> which have
         * individual cell selection enabled.
         *
         * @param i the zero-based index of the child
         * @see AccessibleContext#getAccessibleChild
         */

       
public void removeAccessibleSelection(int i) {
           
if (JTable.this.cellSelectionEnabled) {
               
int column = getAccessibleColumnAtIndex(i);
               
int row = getAccessibleRowAtIndex(i);
               
JTable.this.removeRowSelectionInterval(row, row);
               
JTable.this.removeColumnSelectionInterval(column, column);
           
}
       
}

       
/**
         * Clears the selection in the object, so that no children in the
         * object are selected.
         */

       
public void clearAccessibleSelection() {
           
JTable.this.clearSelection();
       
}

       
/**
         * Causes every child of the object to be selected, but only
         * if the <code>JTable</code> supports multiple selections,
         * and if individual cell selection is enabled.
         */

       
public void selectAllAccessibleSelection() {
           
if (JTable.this.cellSelectionEnabled) {
               
JTable.this.selectAll();
           
}
       
}

       
// begin AccessibleExtendedTable implementation -------------

       
/**
         * Returns the row number of an index in the table.
         *
         * @param index the zero-based index in the table
         * @return the zero-based row of the table if one exists;
         * otherwise -1.
         * @since 1.4
         */

       
public int getAccessibleRow(int index) {
           
return getAccessibleRowAtIndex(index);
       
}

       
/**
         * Returns the column number of an index in the table.
         *
         * @param index the zero-based index in the table
         * @return the zero-based column of the table if one exists;
         * otherwise -1.
         * @since 1.4
         */

       
public int getAccessibleColumn(int index) {
           
return getAccessibleColumnAtIndex(index);
       
}

       
/**
         * Returns the index at a row and column in the table.
         *
         * @param r zero-based row of the table
         * @param c zero-based column of the table
         * @return the zero-based index in the table if one exists;
         * otherwise -1.
         * @since 1.4
         */

       
public int getAccessibleIndex(int r, int c) {
           
return getAccessibleIndexAt(r, c);
       
}

       
// end of AccessibleExtendedTable implementation ------------

       
// start of AccessibleTable implementation ------------------

       
private Accessible caption;
       
private Accessible summary;
       
private Accessible [] rowDescription;
       
private Accessible [] columnDescription;

       
/**
         * Gets the <code>AccessibleTable</code> associated with this
         * object.  In the implementation of the Java Accessibility
         * API for this class, return this object, which is responsible
         * for implementing the <code>AccessibleTables</code> interface
         * on behalf of itself.
         *
         * @return this object
         * @since 1.3
         */

       
public AccessibleTable getAccessibleTable() {
           
return this;
       
}

       
/**
         * Returns the caption for the table.
         *
         * @return the caption for the table
         * @since 1.3
         */

       
public Accessible getAccessibleCaption() {
           
return this.caption;
       
}

       
/**
         * Sets the caption for the table.
         *
         * @param a the caption for the table
         * @since 1.3
         */

       
public void setAccessibleCaption(Accessible a) {
           
Accessible oldCaption = caption;
           
this.caption = a;
            firePropertyChange
(AccessibleContext.ACCESSIBLE_TABLE_CAPTION_CHANGED,
                               oldCaption
, this.caption);
       
}

       
/**
         * Returns the summary description of the table.
         *
         * @return the summary description of the table
         * @since 1.3
         */

       
public Accessible getAccessibleSummary() {
           
return this.summary;
       
}

       
/**
         * Sets the summary description of the table.
         *
         * @param a the summary description of the table
         * @since 1.3
         */

       
public void setAccessibleSummary(Accessible a) {
           
Accessible oldSummary = summary;
           
this.summary = a;
            firePropertyChange
(AccessibleContext.ACCESSIBLE_TABLE_SUMMARY_CHANGED,
                               oldSummary
, this.summary);
       
}

       
/*
         * Returns the total number of rows in this table.
         *
         * @return the total number of rows in this table
         */

       
public int getAccessibleRowCount() {
           
return JTable.this.getRowCount();
       
}

       
/*
         * Returns the total number of columns in the table.
         *
         * @return the total number of columns in the table
         */

       
public int getAccessibleColumnCount() {
           
return JTable.this.getColumnCount();
       
}

       
/*
         * Returns the <code>Accessible</code> at a specified row
         * and column in the table.
         *
         * @param r zero-based row of the table
         * @param c zero-based column of the table
         * @return the <code>Accessible</code> at the specified row and column
         * in the table
         */

       
public Accessible getAccessibleAt(int r, int c) {
           
return getAccessibleChild((r * getAccessibleColumnCount()) + c);
       
}

       
/**
         * Returns the number of rows occupied by the <code>Accessible</code>
         * at a specified row and column in the table.
         *
         * @return the number of rows occupied by the <code>Accessible</code>
         *     at a specified row and column in the table
         * @since 1.3
         */

       
public int getAccessibleRowExtentAt(int r, int c) {
           
return 1;
       
}

       
/**
         * Returns the number of columns occupied by the
         * <code>Accessible</code> at a given (row, column).
         *
         * @return the number of columns occupied by the <code>Accessible</code>
         *     at a specified row and column in the table
         * @since 1.3
         */

       
public int getAccessibleColumnExtentAt(int r, int c) {
           
return 1;
       
}

       
/**
         * Returns the row headers as an <code>AccessibleTable</code>.
         *
         * @return an <code>AccessibleTable</code> representing the row
         * headers
         * @since 1.3
         */

       
public AccessibleTable getAccessibleRowHeader() {
           
// row headers are not supported
           
return null;
       
}

       
/**
         * Sets the row headers as an <code>AccessibleTable</code>.
         *
         * @param a an <code>AccessibleTable</code> representing the row
         *  headers
         * @since 1.3
         */

       
public void setAccessibleRowHeader(AccessibleTable a) {
           
// row headers are not supported
       
}

       
/**
         * Returns the column headers as an <code>AccessibleTable</code>.
         *
         *  @return an <code>AccessibleTable</code> representing the column
         *          headers, or <code>null</code> if the table header is
         *          <code>null</code>
         * @since 1.3
         */

       
public AccessibleTable getAccessibleColumnHeader() {
           
JTableHeader header = JTable.this.getTableHeader();
           
return header == null ? null : new AccessibleTableHeader(header);
       
}

       
/*
         * Private class representing a table column header
         */

       
private class AccessibleTableHeader implements AccessibleTable {
           
private JTableHeader header;
           
private TableColumnModel headerModel;

           
AccessibleTableHeader(JTableHeader header) {
               
this.header = header;
               
this.headerModel = header.getColumnModel();
           
}

           
/**
             * Returns the caption for the table.
             *
             * @return the caption for the table
             */

           
public Accessible getAccessibleCaption() { return null; }


           
/**
             * Sets the caption for the table.
             *
             * @param a the caption for the table
             */

           
public void setAccessibleCaption(Accessible a) {}

           
/**
             * Returns the summary description of the table.
             *
             * @return the summary description of the table
             */

           
public Accessible getAccessibleSummary() { return null; }

           
/**
             * Sets the summary description of the table
             *
             * @param a the summary description of the table
             */

           
public void setAccessibleSummary(Accessible a) {}

           
/**
             * Returns the number of rows in the table.
             *
             * @return the number of rows in the table
             */

           
public int getAccessibleRowCount() { return 1; }

           
/**
             * Returns the number of columns in the table.
             *
             * @return the number of columns in the table
             */

           
public int getAccessibleColumnCount() {
               
return headerModel.getColumnCount();
           
}

           
/**
             * Returns the Accessible at a specified row and column
             * in the table.
             *
             * @param row zero-based row of the table
             * @param column zero-based column of the table
             * @return the Accessible at the specified row and column
             */

           
public Accessible getAccessibleAt(int row, int column) {


               
// TIGER - 4715503
               
TableColumn aColumn = headerModel.getColumn(column);
               
TableCellRenderer renderer = aColumn.getHeaderRenderer();
               
if (renderer == null) {
                    renderer
= header.getDefaultRenderer();
               
}
               
Component component = renderer.getTableCellRendererComponent(
                                  header
.getTable(),
                                  aColumn
.getHeaderValue(), false, false,
                                 
-1, column);

               
return new AccessibleJTableHeaderCell(row, column,
                                                     
JTable.this.getTableHeader(),
                                                      component
);
           
}

           
/**
             * Returns the number of rows occupied by the Accessible at
             * a specified row and column in the table.
             *
             * @return the number of rows occupied by the Accessible at a
             * given specified (row, column)
             */

           
public int getAccessibleRowExtentAt(int r, int c) { return 1; }

           
/**
             * Returns the number of columns occupied by the Accessible at
             * a specified row and column in the table.
             *
             * @return the number of columns occupied by the Accessible at a
             * given specified row and column
             */

           
public int getAccessibleColumnExtentAt(int r, int c) { return 1; }

           
/**
             * Returns the row headers as an AccessibleTable.
             *
             * @return an AccessibleTable representing the row
             * headers
             */

           
public AccessibleTable getAccessibleRowHeader() { return null; }

           
/**
             * Sets the row headers.
             *
             * @param table an AccessibleTable representing the
             * row headers
             */

           
public void setAccessibleRowHeader(AccessibleTable table) {}

           
/**
             * Returns the column headers as an AccessibleTable.
             *
             * @return an AccessibleTable representing the column
             * headers
             */

           
public AccessibleTable getAccessibleColumnHeader() { return null; }

           
/**
             * Sets the column headers.
             *
             * @param table an AccessibleTable representing the
             * column headers
             * @since 1.3
             */

           
public void setAccessibleColumnHeader(AccessibleTable table) {}

           
/**
             * Returns the description of the specified row in the table.
             *
             * @param r zero-based row of the table
             * @return the description of the row
             * @since 1.3
             */

           
public Accessible getAccessibleRowDescription(int r) { return null; }

           
/**
             * Sets the description text of the specified row of the table.
             *
             * @param r zero-based row of the table
             * @param a the description of the row
             * @since 1.3
             */

           
public void setAccessibleRowDescription(int r, Accessible a) {}

           
/**
             * Returns the description text of the specified column in the table.
             *
             * @param c zero-based column of the table
             * @return the text description of the column
             * @since 1.3
             */

           
public Accessible getAccessibleColumnDescription(int c) { return null; }

           
/**
             * Sets the description text of the specified column in the table.
             *
             * @param c zero-based column of the table
             * @param a the text description of the column
             * @since 1.3
             */

           
public void setAccessibleColumnDescription(int c, Accessible a) {}

           
/**
             * Returns a boolean value indicating whether the accessible at
             * a specified row and column is selected.
             *
             * @param r zero-based row of the table
             * @param c zero-based column of the table
             * @return the boolean value true if the accessible at the
             * row and column is selected. Otherwise, the boolean value
             * false
             * @since 1.3
             */

           
public boolean isAccessibleSelected(int r, int c) { return false; }

           
/**
             * Returns a boolean value indicating whether the specified row
             * is selected.
             *
             * @param r zero-based row of the table
             * @return the boolean value true if the specified row is selected.
             * Otherwise, false.
             * @since 1.3
             */

           
public boolean isAccessibleRowSelected(int r) { return false; }

           
/**
             * Returns a boolean value indicating whether the specified column
             * is selected.
             *
             * @param r zero-based column of the table
             * @return the boolean value true if the specified column is selected.
             * Otherwise, false.
             * @since 1.3
             */

           
public boolean isAccessibleColumnSelected(int c) { return false; }

           
/**
             * Returns the selected rows in a table.
             *
             * @return an array of selected rows where each element is a
             * zero-based row of the table
             * @since 1.3
             */

           
public int [] getSelectedAccessibleRows() { return new int[0]; }

           
/**
             * Returns the selected columns in a table.
             *
             * @return an array of selected columns where each element is a
             * zero-based column of the table
             * @since 1.3
             */

           
public int [] getSelectedAccessibleColumns() { return new int[0]; }
       
}


       
/**
         * Sets the column headers as an <code>AccessibleTable</code>.
         *
         * @param a an <code>AccessibleTable</code> representing the
         * column headers
         * @since 1.3
         */

       
public void setAccessibleColumnHeader(AccessibleTable a) {
           
// XXX not implemented
       
}

       
/**
         * Returns the description of the specified row in the table.
         *
         * @param r zero-based row of the table
         * @return the description of the row
         * @since 1.3
         */

       
public Accessible getAccessibleRowDescription(int r) {
           
if (r < 0 || r >= getAccessibleRowCount()) {
               
throw new IllegalArgumentException(new Integer(r).toString());
           
}
           
if (rowDescription == null) {
               
return null;
           
} else {
               
return rowDescription[r];
           
}
       
}

       
/**
         * Sets the description text of the specified row of the table.
         *
         * @param r zero-based row of the table
         * @param a the description of the row
         * @since 1.3
         */

       
public void setAccessibleRowDescription(int r, Accessible a) {
           
if (r < 0 || r >= getAccessibleRowCount()) {
               
throw new IllegalArgumentException(new Integer(r).toString());
           
}
           
if (rowDescription == null) {
               
int numRows = getAccessibleRowCount();
                rowDescription
= new Accessible[numRows];
           
}
            rowDescription
[r] = a;
       
}

       
/**
         * Returns the description of the specified column in the table.
         *
         * @param c zero-based column of the table
         * @return the description of the column
         * @since 1.3
         */

       
public Accessible getAccessibleColumnDescription(int c) {
           
if (c < 0 || c >= getAccessibleColumnCount()) {
               
throw new IllegalArgumentException(new Integer(c).toString());
           
}
           
if (columnDescription == null) {
               
return null;
           
} else {
               
return columnDescription[c];
           
}
       
}

       
/**
         * Sets the description text of the specified column of the table.
         *
         * @param c zero-based column of the table
         * @param a the description of the column
         * @since 1.3
         */

       
public void setAccessibleColumnDescription(int c, Accessible a) {
           
if (c < 0 || c >= getAccessibleColumnCount()) {
               
throw new IllegalArgumentException(new Integer(c).toString());
           
}
           
if (columnDescription == null) {
               
int numColumns = getAccessibleColumnCount();
                columnDescription
= new Accessible[numColumns];
           
}
            columnDescription
[c] = a;
       
}

       
/**
         * Returns a boolean value indicating whether the accessible at a
         * given (row, column) is selected.
         *
         * @param r zero-based row of the table
         * @param c zero-based column of the table
         * @return the boolean value true if the accessible at (row, column)
         *     is selected; otherwise, the boolean value false
         * @since 1.3
         */

       
public boolean isAccessibleSelected(int r, int c) {
           
return JTable.this.isCellSelected(r, c);
       
}

       
/**
         * Returns a boolean value indicating whether the specified row
         * is selected.
         *
         * @param r zero-based row of the table
         * @return the boolean value true if the specified row is selected;
         *     otherwise, false
         * @since 1.3
         */

       
public boolean isAccessibleRowSelected(int r) {
           
return JTable.this.isRowSelected(r);
       
}

       
/**
         * Returns a boolean value indicating whether the specified column
         * is selected.
         *
         * @param c zero-based column of the table
         * @return the boolean value true if the specified column is selected;
         *     otherwise, false
         * @since 1.3
         */

       
public boolean isAccessibleColumnSelected(int c) {
           
return JTable.this.isColumnSelected(c);
       
}

       
/**
         * Returns the selected rows in a table.
         *
         * @return an array of selected rows where each element is a
         *     zero-based row of the table
         * @since 1.3
         */

       
public int [] getSelectedAccessibleRows() {
           
return JTable.this.getSelectedRows();
       
}

       
/**
         * Returns the selected columns in a table.
         *
         * @return an array of selected columns where each element is a
         *     zero-based column of the table
         * @since 1.3
         */

       
public int [] getSelectedAccessibleColumns() {
           
return JTable.this.getSelectedColumns();
       
}

       
/**
         * Returns the row at a given index into the table.
         *
         * @param i zero-based index into the table
         * @return the row at a given index
         * @since 1.3
         */

       
public int getAccessibleRowAtIndex(int i) {
           
int columnCount = getAccessibleColumnCount();
           
if (columnCount == 0) {
               
return -1;
           
} else {
               
return (i / columnCount);
           
}
       
}

       
/**
         * Returns the column at a given index into the table.
         *
         * @param i zero-based index into the table
         * @return the column at a given index
         * @since 1.3
         */

       
public int getAccessibleColumnAtIndex(int i) {
           
int columnCount = getAccessibleColumnCount();
           
if (columnCount == 0) {
               
return -1;
           
} else {
               
return (i % columnCount);
           
}
       
}

       
/**
         * Returns the index at a given (row, column) in the table.
         *
         * @param r zero-based row of the table
         * @param c zero-based column of the table
         * @return the index into the table
         * @since 1.3
         */

       
public int getAccessibleIndexAt(int r, int c) {
           
return ((r * getAccessibleColumnCount()) + c);
       
}

       
// end of AccessibleTable implementation --------------------

       
/**
         * The class provides an implementation of the Java Accessibility
         * API appropriate to table cells.
         */

       
protected class AccessibleJTableCell extends AccessibleContext
           
implements Accessible, AccessibleComponent {

           
private JTable parent;
           
private int row;
           
private int column;
           
private int index;

           
/**
             *  Constructs an <code>AccessibleJTableHeaderEntry</code>.
             * @since 1.4
             */

           
public AccessibleJTableCell(JTable t, int r, int c, int i) {
                parent
= t;
                row
= r;
                column
= c;
                index
= i;
               
this.setAccessibleParent(parent);
           
}

           
/**
             * Gets the <code>AccessibleContext</code> associated with this
             * component. In the implementation of the Java Accessibility
             * API for this class, return this object, which is its own
             * <code>AccessibleContext</code>.
             *
             * @return this object
             */

           
public AccessibleContext getAccessibleContext() {
               
return this;
           
}

           
/**
             * Gets the AccessibleContext for the table cell renderer.
             *
             * @return the <code>AccessibleContext</code> for the table
             * cell renderer if one exists;
             * otherwise, returns <code>null</code>.
             * @since 1.6
             */

           
protected AccessibleContext getCurrentAccessibleContext() {
               
TableColumn aColumn = getColumnModel().getColumn(column);
               
TableCellRenderer renderer = aColumn.getCellRenderer();
               
if (renderer == null) {
                   
Class<?> columnClass = getColumnClass(column);
                    renderer
= getDefaultRenderer(columnClass);
               
}
               
Component component = renderer.getTableCellRendererComponent(
                                 
JTable.this, getValueAt(row, column),
                                 
false, false, row, column);
               
if (component instanceof Accessible) {
                   
return ((Accessible) component).getAccessibleContext();
               
} else {
                   
return null;
               
}
           
}

           
/**
             * Gets the table cell renderer component.
             *
             * @return the table cell renderer component if one exists;
             * otherwise, returns <code>null</code>.
             * @since 1.6
             */

           
protected Component getCurrentComponent() {
               
TableColumn aColumn = getColumnModel().getColumn(column);
               
TableCellRenderer renderer = aColumn.getCellRenderer();
               
if (renderer == null) {
                   
Class<?> columnClass = getColumnClass(column);
                    renderer
= getDefaultRenderer(columnClass);
               
}
               
return renderer.getTableCellRendererComponent(
                                 
JTable.this, null, false, false,
                                  row
, column);
           
}

       
// AccessibleContext methods

           
/**
             * Gets the accessible name of this object.
             *
             * @return the localized name of the object; <code>null</code>
             *     if this object does not have a name
             */

           
public String getAccessibleName() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                   
String name = ac.getAccessibleName();
                   
if ((name != null) && (name != "")) {
                       
// return the cell renderer's AccessibleName
                       
return name;
                   
}
               
}
               
if ((accessibleName != null) && (accessibleName != "")) {
                   
return accessibleName;
               
} else {
                   
// fall back to the client property
                   
return (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
               
}
           
}

           
/**
             * Sets the localized accessible name of this object.
             *
             * @param s the new localized name of the object
             */

           
public void setAccessibleName(String s) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                    ac
.setAccessibleName(s);
               
} else {
                   
super.setAccessibleName(s);
               
}
           
}

           
//
           
// *** should check toolTip text for desc. (needs MouseEvent)
           
//
           
/**
             * Gets the accessible description of this object.
             *
             * @return the localized description of the object;
             *     <code>null</code> if this object does not have
             *     a description
             */

           
public String getAccessibleDescription() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                   
return ac.getAccessibleDescription();
               
} else {
                   
return super.getAccessibleDescription();
               
}
           
}

           
/**
             * Sets the accessible description of this object.
             *
             * @param s the new localized description of the object
             */

           
public void setAccessibleDescription(String s) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                    ac
.setAccessibleDescription(s);
               
} else {
                   
super.setAccessibleDescription(s);
               
}
           
}

           
/**
             * Gets the role of this object.
             *
             * @return an instance of <code>AccessibleRole</code>
             *      describing the role of the object
             * @see AccessibleRole
             */

           
public AccessibleRole getAccessibleRole() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                   
return ac.getAccessibleRole();
               
} else {
                   
return AccessibleRole.UNKNOWN;
               
}
           
}

           
/**
             * Gets the state set of this object.
             *
             * @return an instance of <code>AccessibleStateSet</code>
             *     containing the current state set of the object
             * @see AccessibleState
             */

           
public AccessibleStateSet getAccessibleStateSet() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
AccessibleStateSet as = null;

               
if (ac != null) {
                   
as = ac.getAccessibleStateSet();
               
}
               
if (as == null) {
                   
as = new AccessibleStateSet();
               
}
               
Rectangle rjt = JTable.this.getVisibleRect();
               
Rectangle rcell = JTable.this.getCellRect(row, column, false);
               
if (rjt.intersects(rcell)) {
                   
as.add(AccessibleState.SHOWING);
               
} else {
                   
if (as.contains(AccessibleState.SHOWING)) {
                         
as.remove(AccessibleState.SHOWING);
                   
}
               
}
               
if (parent.isCellSelected(row, column)) {
                   
as.add(AccessibleState.SELECTED);
               
} else if (as.contains(AccessibleState.SELECTED)) {
                   
as.remove(AccessibleState.SELECTED);
               
}
               
if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
                   
as.add(AccessibleState.ACTIVE);
               
}
               
as.add(AccessibleState.TRANSIENT);
               
return as;
           
}

           
/**
             * Gets the <code>Accessible</code> parent of this object.
             *
             * @return the Accessible parent of this object;
             *     <code>null</code> if this object does not
             *     have an <code>Accessible</code> parent
             */

           
public Accessible getAccessibleParent() {
               
return parent;
           
}

           
/**
             * Gets the index of this object in its accessible parent.
             *
             * @return the index of this object in its parent; -1 if this
             *     object does not have an accessible parent
             * @see #getAccessibleParent
             */

           
public int getAccessibleIndexInParent() {
               
return index;
           
}

           
/**
             * Returns the number of accessible children in the object.
             *
             * @return the number of accessible children in the object
             */

           
public int getAccessibleChildrenCount() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                   
return ac.getAccessibleChildrenCount();
               
} else {
                   
return 0;
               
}
           
}

           
/**
             * Returns the specified <code>Accessible</code> child of the
             * object.
             *
             * @param i zero-based index of child
             * @return the <code>Accessible</code> child of the object
             */

           
public Accessible getAccessibleChild(int i) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                   
Accessible accessibleChild = ac.getAccessibleChild(i);
                    ac
.setAccessibleParent(this);
                   
return accessibleChild;
               
} else {
                   
return null;
               
}
           
}

           
/**
             * Gets the locale of the component. If the component
             * does not have a locale, then the locale of its parent
             * is returned.
             *
             * @return this component's locale; if this component does
             *    not have a locale, the locale of its parent is returned
             * @exception IllegalComponentStateException if the
             *    <code>Component</code> does not have its own locale
             *    and has not yet been added to a containment hierarchy
             *    such that the locale can be determined from the
             *    containing parent
             * @see #setLocale
             */

           
public Locale getLocale() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                   
return ac.getLocale();
               
} else {
                   
return null;
               
}
           
}

           
/**
             * Adds a <code>PropertyChangeListener</code> to the listener list.
             * The listener is registered for all properties.
             *
             * @param l  the <code>PropertyChangeListener</code>
             *     to be added
             */

           
public void addPropertyChangeListener(PropertyChangeListener l) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                    ac
.addPropertyChangeListener(l);
               
} else {
                   
super.addPropertyChangeListener(l);
               
}
           
}

           
/**
             * Removes a <code>PropertyChangeListener</code> from the
             * listener list. This removes a <code>PropertyChangeListener</code>
             * that was registered for all properties.
             *
             * @param l  the <code>PropertyChangeListener</code>
             *    to be removed
             */

           
public void removePropertyChangeListener(PropertyChangeListener l) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                    ac
.removePropertyChangeListener(l);
               
} else {
                   
super.removePropertyChangeListener(l);
               
}
           
}

           
/**
             * Gets the <code>AccessibleAction</code> associated with this
             * object if one exists.  Otherwise returns <code>null</code>.
             *
             * @return the <code>AccessibleAction</code>, or <code>null</code>
             */

           
public AccessibleAction getAccessibleAction() {
               
return getCurrentAccessibleContext().getAccessibleAction();
           
}

           
/**
             * Gets the <code>AccessibleComponent</code> associated with
             * this object if one exists.  Otherwise returns <code>null</code>.
             *
             * @return the <code>AccessibleComponent</code>, or
             *    <code>null</code>
             */

           
public AccessibleComponent getAccessibleComponent() {
               
return this; // to override getBounds()
           
}

           
/**
             * Gets the <code>AccessibleSelection</code> associated with
             * this object if one exists.  Otherwise returns <code>null</code>.
             *
             * @return the <code>AccessibleSelection</code>, or
             *    <code>null</code>
             */

           
public AccessibleSelection getAccessibleSelection() {
               
return getCurrentAccessibleContext().getAccessibleSelection();
           
}

           
/**
             * Gets the <code>AccessibleText</code> associated with this
             * object if one exists.  Otherwise returns <code>null</code>.
             *
             * @return the <code>AccessibleText</code>, or <code>null</code>
             */

           
public AccessibleText getAccessibleText() {
               
return getCurrentAccessibleContext().getAccessibleText();
           
}

           
/**
             * Gets the <code>AccessibleValue</code> associated with
             * this object if one exists.  Otherwise returns <code>null</code>.
             *
             * @return the <code>AccessibleValue</code>, or <code>null</code>
             */

           
public AccessibleValue getAccessibleValue() {
               
return getCurrentAccessibleContext().getAccessibleValue();
           
}


       
// AccessibleComponent methods

           
/**
             * Gets the background color of this object.
             *
             * @return the background color, if supported, of the object;
             *     otherwise, <code>null</code>
             */

           
public Color getBackground() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).getBackground();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.getBackground();
                   
} else {
                       
return null;
                   
}
               
}
           
}

           
/**
             * Sets the background color of this object.
             *
             * @param c the new <code>Color</code> for the background
             */

           
public void setBackground(Color c) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setBackground(c);
               
} else {
                   
Component cp = getCurrentComponent();
                   
if (cp != null) {
                        cp
.setBackground(c);
                   
}
               
}
           
}

           
/**
             * Gets the foreground color of this object.
             *
             * @return the foreground color, if supported, of the object;
             *     otherwise, <code>null</code>
             */

           
public Color getForeground() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).getForeground();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.getForeground();
                   
} else {
                       
return null;
                   
}
               
}
           
}

           
/**
             * Sets the foreground color of this object.
             *
             * @param c the new <code>Color</code> for the foreground
             */

           
public void setForeground(Color c) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setForeground(c);
               
} else {
                   
Component cp = getCurrentComponent();
                   
if (cp != null) {
                        cp
.setForeground(c);
                   
}
               
}
           
}

           
/**
             * Gets the <code>Cursor</code> of this object.
             *
             * @return the <code>Cursor</code>, if supported,
             *    of the object; otherwise, <code>null</code>
             */

           
public Cursor getCursor() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).getCursor();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.getCursor();
                   
} else {
                       
Accessible ap = getAccessibleParent();
                       
if (ap instanceof AccessibleComponent) {
                           
return ((AccessibleComponent) ap).getCursor();
                       
} else {
                           
return null;
                       
}
                   
}
               
}
           
}

           
/**
             * Sets the <code>Cursor</code> of this object.
             *
             * @param c the new <code>Cursor</code> for the object
             */

           
public void setCursor(Cursor c) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setCursor(c);
               
} else {
                   
Component cp = getCurrentComponent();
                   
if (cp != null) {
                        cp
.setCursor(c);
                   
}
               
}
           
}

           
/**
             * Gets the <code>Font</code> of this object.
             *
             * @return the <code>Font</code>,if supported,
             *   for the object; otherwise, <code>null</code>
             */

           
public Font getFont() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).getFont();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.getFont();
                   
} else {
                       
return null;
                   
}
               
}
           
}

           
/**
             * Sets the <code>Font</code> of this object.
             *
             * @param f the new <code>Font</code> for the object
             */

           
public void setFont(Font f) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setFont(f);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.setFont(f);
                   
}
               
}
           
}

           
/**
             * Gets the <code>FontMetrics</code> of this object.
             *
             * @param f the <code>Font</code>
             * @return the <code>FontMetrics</code> object, if supported;
             *    otherwise <code>null</code>
             * @see #getFont
             */

           
public FontMetrics getFontMetrics(Font f) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).getFontMetrics(f);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.getFontMetrics(f);
                   
} else {
                       
return null;
                   
}
               
}
           
}

           
/**
             * Determines if the object is enabled.
             *
             * @return true if object is enabled; otherwise, false
             */

           
public boolean isEnabled() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).isEnabled();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.isEnabled();
                   
} else {
                       
return false;
                   
}
               
}
           
}

           
/**
             * Sets the enabled state of the object.
             *
             * @param b if true, enables this object; otherwise, disables it
             */

           
public void setEnabled(boolean b) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setEnabled(b);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.setEnabled(b);
                   
}
               
}
           
}

           
/**
             * Determines if this object is visible.  Note: this means that the
             * object intends to be visible; however, it may not in fact be
             * showing on the screen because one of the objects that this object
             * is contained by is not visible.  To determine if an object is
             * showing on the screen, use <code>isShowing</code>.
             *
             * @return true if object is visible; otherwise, false
             */

           
public boolean isVisible() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).isVisible();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.isVisible();
                   
} else {
                       
return false;
                   
}
               
}
           
}

           
/**
             * Sets the visible state of the object.
             *
             * @param b if true, shows this object; otherwise, hides it
             */

           
public void setVisible(boolean b) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setVisible(b);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.setVisible(b);
                   
}
               
}
           
}

           
/**
             * Determines if the object is showing.  This is determined
             * by checking the visibility of the object and ancestors
             * of the object.  Note: this will return true even if the
             * object is obscured by another (for example,
             * it happens to be underneath a menu that was pulled down).
             *
             * @return true if the object is showing; otherwise, false
             */

           
public boolean isShowing() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
if (ac.getAccessibleParent() != null) {
                       
return ((AccessibleComponent) ac).isShowing();
                   
} else {
                       
// Fixes 4529616 - AccessibleJTableCell.isShowing()
                       
// returns false when the cell on the screen
                       
// if no parent
                       
return isVisible();
                   
}
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.isShowing();
                   
} else {
                       
return false;
                   
}
               
}
           
}

           
/**
             * Checks whether the specified point is within this
             * object's bounds, where the point's x and y coordinates
             * are defined to be relative to the coordinate system of
             * the object.
             *
             * @param p the <code>Point</code> relative to the
             *    coordinate system of the object
             * @return true if object contains <code>Point</code>;
             *    otherwise false
             */

           
public boolean contains(Point p) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
Rectangle r = ((AccessibleComponent) ac).getBounds();
                   
return r.contains(p);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
Rectangle r = c.getBounds();
                       
return r.contains(p);
                   
} else {
                       
return getBounds().contains(p);
                   
}
               
}
           
}

           
/**
             * Returns the location of the object on the screen.
             *
             * @return location of object on screen -- can be
             *    <code>null</code> if this object is not on the screen
             */

           
public Point getLocationOnScreen() {
               
if (parent != null) {
                   
Point parentLocation = parent.getLocationOnScreen();
                   
Point componentLocation = getLocation();
                    componentLocation
.translate(parentLocation.x, parentLocation.y);
                   
return componentLocation;
               
} else {
                   
return null;
               
}
           
}

           
/**
             * Gets the location of the object relative to the parent
             * in the form of a point specifying the object's
             * top-left corner in the screen's coordinate space.
             *
             * @return an instance of <code>Point</code> representing
             *    the top-left corner of the object's bounds in the
             *    coordinate space of the screen; <code>null</code> if
             *    this object or its parent are not on the screen
             */

           
public Point getLocation() {
               
if (parent != null) {
                   
Rectangle r = parent.getCellRect(row, column, false);
                   
if (r != null) {
                       
return r.getLocation();
                   
}
               
}
               
return null;
           
}

           
/**
             * Sets the location of the object relative to the parent.
             */

           
public void setLocation(Point p) {
//              if ((parent != null)  && (parent.contains(p))) {
//                  ensureIndexIsVisible(indexInParent);
//              }
           
}

           
public Rectangle getBounds() {
               
if (parent != null) {
                   
return parent.getCellRect(row, column, false);
               
} else {
                   
return null;
               
}
           
}

           
public void setBounds(Rectangle r) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setBounds(r);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.setBounds(r);
                   
}
               
}
           
}

           
public Dimension getSize() {
               
if (parent != null) {
                   
Rectangle r = parent.getCellRect(row, column, false);
                   
if (r != null) {
                       
return r.getSize();
                   
}
               
}
               
return null;
           
}

           
public void setSize (Dimension d) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setSize(d);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.setSize(d);
                   
}
               
}
           
}

           
public Accessible getAccessibleAt(Point p) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).getAccessibleAt(p);
               
} else {
                   
return null;
               
}
           
}

           
public boolean isFocusTraversable() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).isFocusTraversable();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.isFocusTraversable();
                   
} else {
                       
return false;
                   
}
               
}
           
}

           
public void requestFocus() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).requestFocus();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.requestFocus();
                   
}
               
}
           
}

           
public void addFocusListener(FocusListener l) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).addFocusListener(l);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.addFocusListener(l);
                   
}
               
}
           
}

           
public void removeFocusListener(FocusListener l) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).removeFocusListener(l);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.removeFocusListener(l);
                   
}
               
}
           
}

       
} // inner class AccessibleJTableCell

       
// Begin AccessibleJTableHeader ========== // TIGER - 4715503

       
/**
         * This class implements accessibility for JTable header cells.
         */

       
private class AccessibleJTableHeaderCell extends AccessibleContext
           
implements Accessible, AccessibleComponent {

           
private int row;
           
private int column;
           
private JTableHeader parent;
           
private Component rendererComponent;

           
/**
             * Constructs an <code>AccessibleJTableHeaderEntry</code> instance.
             *
             * @param row header cell row index
             * @param column header cell column index
             * @param parent header cell parent
             * @param rendererComponent component that renders the header cell
             */

           
public AccessibleJTableHeaderCell(int row, int column,
                                             
JTableHeader parent,
                                             
Component rendererComponent) {
               
this.row = row;
               
this.column = column;
               
this.parent = parent;
               
this.rendererComponent = rendererComponent;
               
this.setAccessibleParent(parent);
           
}

           
/**
             * Gets the <code>AccessibleContext</code> associated with this
             * component. In the implementation of the Java Accessibility
             * API for this class, return this object, which is its own
             * <code>AccessibleContext</code>.
             *
             * @return this object
             */

           
public AccessibleContext getAccessibleContext() {
               
return this;
           
}

           
/*
             * Returns the AccessibleContext for the header cell
             * renderer.
             */

           
private AccessibleContext getCurrentAccessibleContext() {
               
return rendererComponent.getAccessibleContext();
           
}

           
/*
             * Returns the component that renders the header cell.
             */

           
private Component getCurrentComponent() {
               
return rendererComponent;
           
}

           
// AccessibleContext methods ==========

           
/**
             * Gets the accessible name of this object.
             *
             * @return the localized name of the object; <code>null</code>
             *     if this object does not have a name
             */

           
public String getAccessibleName() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                   
String name = ac.getAccessibleName();
                   
if ((name != null) && (name != "")) {
                       
return ac.getAccessibleName();
                   
}
               
}
               
if ((accessibleName != null) && (accessibleName != "")) {
                   
return accessibleName;
               
} else {
                   
return null;
               
}
           
}

           
/**
             * Sets the localized accessible name of this object.
             *
             * @param s the new localized name of the object
             */

           
public void setAccessibleName(String s) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                    ac
.setAccessibleName(s);
               
} else {
                   
super.setAccessibleName(s);
               
}
           
}

           
/**
             * Gets the accessible description of this object.
             *
             * @return the localized description of the object;
             *     <code>null</code> if this object does not have
             *     a description
             */

           
public String getAccessibleDescription() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                   
return ac.getAccessibleDescription();
               
} else {
                   
return super.getAccessibleDescription();
               
}
           
}

           
/**
             * Sets the accessible description of this object.
             *
             * @param s the new localized description of the object
             */

           
public void setAccessibleDescription(String s) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                    ac
.setAccessibleDescription(s);
               
} else {
                   
super.setAccessibleDescription(s);
               
}
           
}

           
/**
             * Gets the role of this object.
             *
             * @return an instance of <code>AccessibleRole</code>
             *      describing the role of the object
             * @see AccessibleRole
             */

           
public AccessibleRole getAccessibleRole() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                   
return ac.getAccessibleRole();
               
} else {
                   
return AccessibleRole.UNKNOWN;
               
}
           
}

           
/**
             * Gets the state set of this object.
             *
             * @return an instance of <code>AccessibleStateSet</code>
             *     containing the current state set of the object
             * @see AccessibleState
             */

           
public AccessibleStateSet getAccessibleStateSet() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
AccessibleStateSet as = null;

               
if (ac != null) {
                   
as = ac.getAccessibleStateSet();
               
}
               
if (as == null) {
                   
as = new AccessibleStateSet();
               
}
               
Rectangle rjt = JTable.this.getVisibleRect();
               
Rectangle rcell = JTable.this.getCellRect(row, column, false);
               
if (rjt.intersects(rcell)) {
                   
as.add(AccessibleState.SHOWING);
               
} else {
                   
if (as.contains(AccessibleState.SHOWING)) {
                         
as.remove(AccessibleState.SHOWING);
                   
}
               
}
               
if (JTable.this.isCellSelected(row, column)) {
                   
as.add(AccessibleState.SELECTED);
               
} else if (as.contains(AccessibleState.SELECTED)) {
                   
as.remove(AccessibleState.SELECTED);
               
}
               
if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
                   
as.add(AccessibleState.ACTIVE);
               
}
               
as.add(AccessibleState.TRANSIENT);
               
return as;
           
}

           
/**
             * Gets the <code>Accessible</code> parent of this object.
             *
             * @return the Accessible parent of this object;
             *     <code>null</code> if this object does not
             *     have an <code>Accessible</code> parent
             */

           
public Accessible getAccessibleParent() {
               
return parent;
           
}

           
/**
             * Gets the index of this object in its accessible parent.
             *
             * @return the index of this object in its parent; -1 if this
             *     object does not have an accessible parent
             * @see #getAccessibleParent
             */

           
public int getAccessibleIndexInParent() {
               
return column;
           
}

           
/**
             * Returns the number of accessible children in the object.
             *
             * @return the number of accessible children in the object
             */

           
public int getAccessibleChildrenCount() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                   
return ac.getAccessibleChildrenCount();
               
} else {
                   
return 0;
               
}
           
}

           
/**
             * Returns the specified <code>Accessible</code> child of the
             * object.
             *
             * @param i zero-based index of child
             * @return the <code>Accessible</code> child of the object
             */

           
public Accessible getAccessibleChild(int i) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                   
Accessible accessibleChild = ac.getAccessibleChild(i);
                    ac
.setAccessibleParent(this);
                   
return accessibleChild;
               
} else {
                   
return null;
               
}
           
}

           
/**
             * Gets the locale of the component. If the component
             * does not have a locale, then the locale of its parent
             * is returned.
             *
             * @return this component's locale; if this component does
             *    not have a locale, the locale of its parent is returned
             * @exception IllegalComponentStateException if the
             *    <code>Component</code> does not have its own locale
             *    and has not yet been added to a containment hierarchy
             *    such that the locale can be determined from the
             *    containing parent
             * @see #setLocale
             */

           
public Locale getLocale() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                   
return ac.getLocale();
               
} else {
                   
return null;
               
}
           
}

           
/**
             * Adds a <code>PropertyChangeListener</code> to the listener list.
             * The listener is registered for all properties.
             *
             * @param l  the <code>PropertyChangeListener</code>
             *     to be added
             */

           
public void addPropertyChangeListener(PropertyChangeListener l) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                    ac
.addPropertyChangeListener(l);
               
} else {
                   
super.addPropertyChangeListener(l);
               
}
           
}

           
/**
             * Removes a <code>PropertyChangeListener</code> from the
             * listener list. This removes a <code>PropertyChangeListener</code>
             * that was registered for all properties.
             *
             * @param l  the <code>PropertyChangeListener</code>
             *    to be removed
             */

           
public void removePropertyChangeListener(PropertyChangeListener l) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac != null) {
                    ac
.removePropertyChangeListener(l);
               
} else {
                   
super.removePropertyChangeListener(l);
               
}
           
}

           
/**
             * Gets the <code>AccessibleAction</code> associated with this
             * object if one exists.  Otherwise returns <code>null</code>.
             *
             * @return the <code>AccessibleAction</code>, or <code>null</code>
             */

           
public AccessibleAction getAccessibleAction() {
               
return getCurrentAccessibleContext().getAccessibleAction();
           
}

           
/**
             * Gets the <code>AccessibleComponent</code> associated with
             * this object if one exists.  Otherwise returns <code>null</code>.
             *
             * @return the <code>AccessibleComponent</code>, or
             *    <code>null</code>
             */

           
public AccessibleComponent getAccessibleComponent() {
               
return this; // to override getBounds()
           
}

           
/**
             * Gets the <code>AccessibleSelection</code> associated with
             * this object if one exists.  Otherwise returns <code>null</code>.
             *
             * @return the <code>AccessibleSelection</code>, or
             *    <code>null</code>
             */

           
public AccessibleSelection getAccessibleSelection() {
               
return getCurrentAccessibleContext().getAccessibleSelection();
           
}

           
/**
             * Gets the <code>AccessibleText</code> associated with this
             * object if one exists.  Otherwise returns <code>null</code>.
             *
             * @return the <code>AccessibleText</code>, or <code>null</code>
             */

           
public AccessibleText getAccessibleText() {
               
return getCurrentAccessibleContext().getAccessibleText();
           
}

           
/**
             * Gets the <code>AccessibleValue</code> associated with
             * this object if one exists.  Otherwise returns <code>null</code>.
             *
             * @return the <code>AccessibleValue</code>, or <code>null</code>
             */

           
public AccessibleValue getAccessibleValue() {
               
return getCurrentAccessibleContext().getAccessibleValue();
           
}


           
// AccessibleComponent methods ==========

           
/**
             * Gets the background color of this object.
             *
             * @return the background color, if supported, of the object;
             *     otherwise, <code>null</code>
             */

           
public Color getBackground() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).getBackground();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.getBackground();
                   
} else {
                       
return null;
                   
}
               
}
           
}

           
/**
             * Sets the background color of this object.
             *
             * @param c the new <code>Color</code> for the background
             */

           
public void setBackground(Color c) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setBackground(c);
               
} else {
                   
Component cp = getCurrentComponent();
                   
if (cp != null) {
                        cp
.setBackground(c);
                   
}
               
}
           
}

           
/**
             * Gets the foreground color of this object.
             *
             * @return the foreground color, if supported, of the object;
             *     otherwise, <code>null</code>
             */

           
public Color getForeground() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).getForeground();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.getForeground();
                   
} else {
                       
return null;
                   
}
               
}
           
}

           
/**
             * Sets the foreground color of this object.
             *
             * @param c the new <code>Color</code> for the foreground
             */

           
public void setForeground(Color c) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setForeground(c);
               
} else {
                   
Component cp = getCurrentComponent();
                   
if (cp != null) {
                        cp
.setForeground(c);
                   
}
               
}
           
}

           
/**
             * Gets the <code>Cursor</code> of this object.
             *
             * @return the <code>Cursor</code>, if supported,
             *    of the object; otherwise, <code>null</code>
             */

           
public Cursor getCursor() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).getCursor();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.getCursor();
                   
} else {
                       
Accessible ap = getAccessibleParent();
                       
if (ap instanceof AccessibleComponent) {
                           
return ((AccessibleComponent) ap).getCursor();
                       
} else {
                           
return null;
                       
}
                   
}
               
}
           
}

           
/**
             * Sets the <code>Cursor</code> of this object.
             *
             * @param c the new <code>Cursor</code> for the object
             */

           
public void setCursor(Cursor c) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setCursor(c);
               
} else {
                   
Component cp = getCurrentComponent();
                   
if (cp != null) {
                        cp
.setCursor(c);
                   
}
               
}
           
}

           
/**
             * Gets the <code>Font</code> of this object.
             *
             * @return the <code>Font</code>,if supported,
             *   for the object; otherwise, <code>null</code>
             */

           
public Font getFont() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).getFont();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.getFont();
                   
} else {
                       
return null;
                   
}
               
}
           
}

           
/**
             * Sets the <code>Font</code> of this object.
             *
             * @param f the new <code>Font</code> for the object
             */

           
public void setFont(Font f) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setFont(f);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.setFont(f);
                   
}
               
}
           
}

           
/**
             * Gets the <code>FontMetrics</code> of this object.
             *
             * @param f the <code>Font</code>
             * @return the <code>FontMetrics</code> object, if supported;
             *    otherwise <code>null</code>
             * @see #getFont
             */

           
public FontMetrics getFontMetrics(Font f) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).getFontMetrics(f);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.getFontMetrics(f);
                   
} else {
                       
return null;
                   
}
               
}
           
}

           
/**
             * Determines if the object is enabled.
             *
             * @return true if object is enabled; otherwise, false
             */

           
public boolean isEnabled() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).isEnabled();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.isEnabled();
                   
} else {
                       
return false;
                   
}
               
}
           
}

           
/**
             * Sets the enabled state of the object.
             *
             * @param b if true, enables this object; otherwise, disables it
             */

           
public void setEnabled(boolean b) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setEnabled(b);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.setEnabled(b);
                   
}
               
}
           
}

           
/**
             * Determines if this object is visible.  Note: this means that the
             * object intends to be visible; however, it may not in fact be
             * showing on the screen because one of the objects that this object
             * is contained by is not visible.  To determine if an object is
             * showing on the screen, use <code>isShowing</code>.
             *
             * @return true if object is visible; otherwise, false
             */

           
public boolean isVisible() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).isVisible();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.isVisible();
                   
} else {
                       
return false;
                   
}
               
}
           
}

           
/**
             * Sets the visible state of the object.
             *
             * @param b if true, shows this object; otherwise, hides it
             */

           
public void setVisible(boolean b) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setVisible(b);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.setVisible(b);
                   
}
               
}
           
}

           
/**
             * Determines if the object is showing.  This is determined
             * by checking the visibility of the object and ancestors
             * of the object.  Note: this will return true even if the
             * object is obscured by another (for example,
             * it happens to be underneath a menu that was pulled down).
             *
             * @return true if the object is showing; otherwise, false
             */

           
public boolean isShowing() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
if (ac.getAccessibleParent() != null) {
                       
return ((AccessibleComponent) ac).isShowing();
                   
} else {
                       
// Fixes 4529616 - AccessibleJTableCell.isShowing()
                       
// returns false when the cell on the screen
                       
// if no parent
                       
return isVisible();
                   
}
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.isShowing();
                   
} else {
                       
return false;
                   
}
               
}
           
}

           
/**
             * Checks whether the specified point is within this
             * object's bounds, where the point's x and y coordinates
             * are defined to be relative to the coordinate system of
             * the object.
             *
             * @param p the <code>Point</code> relative to the
             *    coordinate system of the object
             * @return true if object contains <code>Point</code>;
             *    otherwise false
             */

           
public boolean contains(Point p) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
Rectangle r = ((AccessibleComponent) ac).getBounds();
                   
return r.contains(p);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
Rectangle r = c.getBounds();
                       
return r.contains(p);
                   
} else {
                       
return getBounds().contains(p);
                   
}
               
}
           
}

           
/**
             * Returns the location of the object on the screen.
             *
             * @return location of object on screen -- can be
             *    <code>null</code> if this object is not on the screen
             */

           
public Point getLocationOnScreen() {
               
if (parent != null) {
                   
Point parentLocation = parent.getLocationOnScreen();
                   
Point componentLocation = getLocation();
                    componentLocation
.translate(parentLocation.x, parentLocation.y);
                   
return componentLocation;
               
} else {
                   
return null;
               
}
           
}

           
/**
             * Gets the location of the object relative to the parent
             * in the form of a point specifying the object's
             * top-left corner in the screen's coordinate space.
             *
             * @return an instance of <code>Point</code> representing
             *    the top-left corner of the object's bounds in the
             *    coordinate space of the screen; <code>null</code> if
             *    this object or its parent are not on the screen
             */

           
public Point getLocation() {
               
if (parent != null) {
                   
Rectangle r = parent.getHeaderRect(column);
                   
if (r != null) {
                       
return r.getLocation();
                   
}
               
}
               
return null;
           
}

           
/**
             * Sets the location of the object relative to the parent.
             * @param p the new position for the top-left corner
             * @see #getLocation
             */

           
public void setLocation(Point p) {
           
}

           
/**
             * Gets the bounds of this object in the form of a Rectangle object.
             * The bounds specify this object's width, height, and location
             * relative to its parent.
             *
             * @return A rectangle indicating this component's bounds; null if
             * this object is not on the screen.
             * @see #contains
             */

           
public Rectangle getBounds() {
               
if (parent != null) {
                   
return parent.getHeaderRect(column);
               
} else {
                   
return null;
               
}
           
}

           
/**
             * Sets the bounds of this object in the form of a Rectangle object.
             * The bounds specify this object's width, height, and location
             * relative to its parent.
             *
             * @param r rectangle indicating this component's bounds
             * @see #getBounds
             */

           
public void setBounds(Rectangle r) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setBounds(r);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.setBounds(r);
                   
}
               
}
           
}

           
/**
             * Returns the size of this object in the form of a Dimension object.
             * The height field of the Dimension object contains this object's
             * height, and the width field of the Dimension object contains this
             * object's width.
             *
             * @return A Dimension object that indicates the size of this component;
             * null if this object is not on the screen
             * @see #setSize
             */

           
public Dimension getSize() {
               
if (parent != null) {
                   
Rectangle r = parent.getHeaderRect(column);
                   
if (r != null) {
                       
return r.getSize();
                   
}
               
}
               
return null;
           
}

           
/**
             * Resizes this object so that it has width and height.
             *
             * @param d The dimension specifying the new size of the object.
             * @see #getSize
             */

           
public void setSize (Dimension d) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).setSize(d);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.setSize(d);
                   
}
               
}
           
}

           
/**
             * Returns the Accessible child, if one exists, contained at the local
             * coordinate Point.
             *
             * @param p The point relative to the coordinate system of this object.
             * @return the Accessible, if it exists, at the specified location;
             * otherwise null
             */

           
public Accessible getAccessibleAt(Point p) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).getAccessibleAt(p);
               
} else {
                   
return null;
               
}
           
}

           
/**
             * Returns whether this object can accept focus or not.   Objects that
             * can accept focus will also have the AccessibleState.FOCUSABLE state
             * set in their AccessibleStateSets.
             *
             * @return true if object can accept focus; otherwise false
             * @see AccessibleContext#getAccessibleStateSet
             * @see AccessibleState#FOCUSABLE
             * @see AccessibleState#FOCUSED
             * @see AccessibleStateSet
             */

           
public boolean isFocusTraversable() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
return ((AccessibleComponent) ac).isFocusTraversable();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                       
return c.isFocusTraversable();
                   
} else {
                       
return false;
                   
}
               
}
           
}

           
/**
             * Requests focus for this object.  If this object cannot accept focus,
             * nothing will happen.  Otherwise, the object will attempt to take
             * focus.
             * @see #isFocusTraversable
             */

           
public void requestFocus() {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).requestFocus();
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.requestFocus();
                   
}
               
}
           
}

           
/**
             * Adds the specified focus listener to receive focus events from this
             * component.
             *
             * @param l the focus listener
             * @see #removeFocusListener
             */

           
public void addFocusListener(FocusListener l) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).addFocusListener(l);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.addFocusListener(l);
                   
}
               
}
           
}

           
/**
             * Removes the specified focus listener so it no longer receives focus
             * events from this component.
             *
             * @param l the focus listener
             * @see #addFocusListener
             */

           
public void removeFocusListener(FocusListener l) {
               
AccessibleContext ac = getCurrentAccessibleContext();
               
if (ac instanceof AccessibleComponent) {
                   
((AccessibleComponent) ac).removeFocusListener(l);
               
} else {
                   
Component c = getCurrentComponent();
                   
if (c != null) {
                        c
.removeFocusListener(l);
                   
}
               
}
           
}

       
} // inner class AccessibleJTableHeaderCell

   
}  // inner class AccessibleJTable

}  // End of Class JTable