KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > JTable


1 /*
2  * @(#)JTable.java 1.240 06/03/28
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing;
9
10 import java.util.*;
11
12 import java.applet.Applet JavaDoc;
13 import java.awt.*;
14 import java.awt.event.*;
15 import java.awt.print.*;
16
17 import java.beans.*;
18
19 import java.io.Serializable JavaDoc;
20 import java.io.ObjectOutputStream JavaDoc;
21 import java.io.ObjectInputStream JavaDoc;
22 import java.io.IOException JavaDoc;
23
24 import javax.accessibility.*;
25
26 import javax.swing.event.*;
27 import javax.swing.plaf.*;
28 import javax.swing.table.*;
29 import javax.swing.border.*;
30
31 import java.text.NumberFormat JavaDoc;
32 import java.text.DateFormat JavaDoc;
33 import java.text.MessageFormat JavaDoc;
34
35 import javax.print.attribute.*;
36
37 /**
38  * The <code>JTable</code> is used to display and edit regular two-dimensional tables
39  * of cells.
40  * See <a HREF="http://java.sun.com/docs/books/tutorial/uiswing/components/table.html">How to Use Tables</a>
41  * in <em>The Java Tutorial</em>
42  * for task-oriented documentation and examples of using <code>JTable</code>.
43  *
44  * <p>
45  * The <code>JTable</code> has many
46  * facilities that make it possible to customize its rendering and editing
47  * but provides defaults for these features so that simple tables can be
48  * set up easily. For example, to set up a table with 10 rows and 10
49  * columns of numbers:
50  * <p>
51  * <pre>
52  * TableModel dataModel = new AbstractTableModel() {
53  * public int getColumnCount() { return 10; }
54  * public int getRowCount() { return 10;}
55  * public Object getValueAt(int row, int col) { return new Integer(row*col); }
56  * };
57  * JTable table = new JTable(dataModel);
58  * JScrollPane scrollpane = new JScrollPane(table);
59  * </pre>
60  * <p>
61  * Note that if you wish to use a <code>JTable</code> in a standalone
62  * view (outside of a <code>JScrollPane</code>) and want the header
63  * displayed, you can get it using {@link #getTableHeader} and
64  * display it separately.
65  * <p>
66  * When designing applications that use the <code>JTable</code> it is worth paying
67  * close attention to the data structures that will represent the table's data.
68  * The <code>DefaultTableModel</code> is a model implementation that
69  * uses a <code>Vector</code> of <code>Vector</code>s of <code>Object</code>s to
70  * store the cell values. As well as copying the data from an
71  * application into the <code>DefaultTableModel</code>,
72  * it is also possible to wrap the data in the methods of the
73  * <code>TableModel</code> interface so that the data can be passed to the
74  * <code>JTable</code> directly, as in the example above. This often results
75  * in more efficient applications because the model is free to choose the
76  * internal representation that best suits the data.
77  * A good rule of thumb for deciding whether to use the <code>AbstractTableModel</code>
78  * or the <code>DefaultTableModel</code> is to use the <code>AbstractTableModel</code>
79  * as the base class for creating subclasses and the <code>DefaultTableModel</code>
80  * when subclassing is not required.
81  * <p>
82  * The "TableExample" directory in the demo area of the source distribution
83  * gives a number of complete examples of <code>JTable</code> usage,
84  * covering how the <code>JTable</code> can be used to provide an
85  * editable view of data taken from a database and how to modify
86  * the columns in the display to use specialized renderers and editors.
87  * <p>
88  * The <code>JTable</code> uses integers exclusively to refer to both the rows and the columns
89  * of the model that it displays. The <code>JTable</code> simply takes a tabular range of cells
90  * and uses <code>getValueAt(int, int)</code> to retrieve the
91  * values from the model during painting.
92  * <p>
93  * By default, columns may be rearranged in the <code>JTable</code> so that the
94  * view's columns appear in a different order to the columns in the model.
95  * This does not affect the implementation of the model at all: when the
96  * columns are reordered, the <code>JTable</code> maintains the new order of the columns
97  * internally and converts its column indices before querying the model.
98  * <p>
99  * So, when writing a <code>TableModel</code>, it is not necessary to listen for column
100  * reordering events as the model will be queried in its own coordinate
101  * system regardless of what is happening in the view.
102  * In the examples area there is a demonstration of a sorting algorithm making
103  * use of exactly this technique to interpose yet another coordinate system
104  * where the order of the rows is changed, rather than the order of the columns.
105  * <p>
106  * J2SE 5 adds methods to <code>JTable</code> to provide convenient access to some
107  * common printing needs. Simple new {@link #print()} methods allow for quick
108  * and easy addition of printing support to your application. In addition, a new
109  * {@link #getPrintable} method is available for more advanced printing needs.
110  * <p>
111  * As for all <code>JComponent</code> classes, you can use
112  * {@link InputMap} and {@link ActionMap} to associate an
113  * {@link Action} object with a {@link KeyStroke} and execute the
114  * action under specified conditions.
115  * <p>
116  * <strong>Warning:</strong>
117  * Serialized objects of this class will not be compatible with
118  * future Swing releases. The current serialization support is
119  * appropriate for short term storage or RMI between applications running
120  * the same version of Swing. As of 1.4, support for long term storage
121  * of all JavaBeans<sup><font size="-2">TM</font></sup>
122  * has been added to the <code>java.beans</code> package.
123  * Please see {@link java.beans.XMLEncoder}.
124  *
125  *
126  * @beaninfo
127  * attribute: isContainer false
128  * description: A component which displays data in a two dimensional grid.
129  *
130  * @version 1.240 03/28/06
131  * @author Philip Milne
132  * @author Shannon Hickey (printing support)
133  */

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

137 public class JTable extends JComponent JavaDoc implements TableModelListener, Scrollable JavaDoc,
138     TableColumnModelListener, ListSelectionListener, CellEditorListener,
139     Accessible
140 {
141 //
142
// Static Constants
143
//
144

145     /**
146      * @see #getUIClassID
147      * @see #readObject
148      */

149     private static final String JavaDoc uiClassID = "TableUI";
150
151     /** Do not adjust column widths automatically; use a scrollbar. */
152     public static final int AUTO_RESIZE_OFF = 0;
153
154     /** When a column is adjusted in the UI, adjust the next column the opposite way. */
155     public static final int AUTO_RESIZE_NEXT_COLUMN = 1;
156
157     /** During UI adjustment, change subsequent columns to preserve the total width;
158       * this is the default behavior. */

159     public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
160
161     /** During all resize operations, apply adjustments to the last column only. */
162     public static final int AUTO_RESIZE_LAST_COLUMN = 3;
163
164     /** During all resize operations, proportionately resize all columns. */
165     public static final int AUTO_RESIZE_ALL_COLUMNS = 4;
166
167
168     /**
169      * Printing modes, used in printing <code>JTable</code>s.
170      *
171      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
172      * boolean, PrintRequestAttributeSet, boolean)
173      * @see #getPrintable
174      * @since 1.5
175      */

176     public enum PrintMode {
177
178         /**
179          * Printing mode that prints the table at its current size,
180          * spreading both columns and rows across multiple pages if necessary.
181          */

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

189         FIT_WIDTH
190     }
191
192
193 //
194
// Instance Variables
195
//
196

197     /** The <code>TableModel</code> of the table. */
198     protected TableModel dataModel;
199
200     /** The <code>TableColumnModel</code> of the table. */
201     protected TableColumnModel columnModel;
202
203     /** The <code>ListSelectionModel</code> of the table, used to keep track of row selections. */
204     protected ListSelectionModel JavaDoc selectionModel;
205
206     /** The <code>TableHeader</code> working with the table. */
207     protected JTableHeader tableHeader;
208
209     /** The height in pixels of each row in the table. */
210     protected int rowHeight;
211
212     /** The height in pixels of the margin between the cells in each row. */
213     protected int rowMargin;
214
215     /** The color of the grid. */
216     protected Color gridColor;
217
218     /** The table draws horizontal lines between cells if <code>showHorizontalLines</code> is true. */
219     protected boolean showHorizontalLines;
220
221     /** The table draws vertical lines between cells if <code>showVerticalLines</code> is true. */
222     protected boolean showVerticalLines;
223
224     /**
225      * Determines if the table automatically resizes the
226      * width of the table's columns to take up the entire width of the
227      * table, and how it does the resizing.
228      */

229     protected int autoResizeMode;
230
231     /**
232      * The table will query the <code>TableModel</code> to build the default
233      * set of columns if this is true.
234      */

235     protected boolean autoCreateColumnsFromModel;
236
237     /** Used by the <code>Scrollable</code> interface to determine the initial visible area. */
238     protected Dimension preferredViewportSize;
239
240     /** True if row selection is allowed in this table. */
241     protected boolean rowSelectionAllowed;
242
243     /**
244      * Obsolete as of Java 2 platform v1.3. Please use the
245      * <code>rowSelectionAllowed</code> property and the
246      * <code>columnSelectionAllowed</code> property of the
247      * <code>columnModel</code> instead. Or use the
248      * method <code>getCellSelectionEnabled</code>.
249      */

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

255     protected boolean cellSelectionEnabled;
256
257     /** If editing, the <code>Component</code> that is handling the editing. */
258     transient protected Component editorComp;
259
260     /**
261      * The active cell editor object, that overwrites the screen real estate
262      * occupied by the current cell and allows the user to change its contents.
263      * {@code null} if the table isn't currently editing.
264      */

265     transient protected TableCellEditor cellEditor;
266
267     /** Identifies the column of the cell being edited. */
268     transient protected int editingColumn;
269
270     /** Identifies the row of the cell being edited. */
271     transient protected int editingRow;
272
273     /**
274      * A table of objects that display the contents of a cell,
275      * indexed by class as declared in <code>getColumnClass</code>
276      * in the <code>TableModel</code> interface.
277      */

278     transient protected Hashtable defaultRenderersByColumnClass;
279
280     /**
281      * A table of objects that display and edit the contents of a cell,
282      * indexed by class as declared in <code>getColumnClass</code>
283      * in the <code>TableModel</code> interface.
284      */

285     transient protected Hashtable defaultEditorsByColumnClass;
286
287     /** The foreground color of selected cells. */
288     protected Color selectionForeground;
289
290     /** The background color of selected cells. */
291     protected Color selectionBackground;
292
293 //
294
// Private state
295
//
296

297     private SizeSequence JavaDoc rowModel;
298     private boolean dragEnabled;
299     private boolean surrendersFocusOnKeystroke;
300     private PropertyChangeListener editorRemover = null;
301     /**
302      * The last value of getValueIsAdjusting from the column selection models
303      * columnSelectionChanged notification. Used to test if a repaint is
304      * needed.
305      */

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

311     private boolean rowSelectionAdjusting;
312
313     /**
314      * A flag to indicate whether or not the table is currently being printed.
315      * Used by print() and prepareRenderer() to disable indication of the
316      * selection and focused cell while printing.
317      */

318     private boolean isPrinting = false;
319
320     /**
321      * To communicate errors between threads during printing.
322      */

323     private Throwable JavaDoc printError;
324
325     /**
326      * True when setRowHeight(int) has been invoked.
327      */

328     private boolean isRowHeightSet;
329
330 //
331
// Constructors
332
//
333

334     /**
335      * Constructs a default <code>JTable</code> that is initialized with a default
336      * data model, a default column model, and a default selection
337      * model.
338      *
339      * @see #createDefaultDataModel
340      * @see #createDefaultColumnModel
341      * @see #createDefaultSelectionModel
342      */

343     public JTable() {
344         this(null, null, null);
345     }
346
347     /**
348      * Constructs a <code>JTable</code> that is initialized with
349      * <code>dm</code> as the data model, a default column model,
350      * and a default selection model.
351      *
352      * @param dm the data model for the table
353      * @see #createDefaultColumnModel
354      * @see #createDefaultSelectionModel
355      */

356     public JTable(TableModel dm) {
357         this(dm, null, null);
358     }
359
360     /**
361      * Constructs a <code>JTable</code> that is initialized with
362      * <code>dm</code> as the data model, <code>cm</code>
363      * as the column model, and a default selection model.
364      *
365      * @param dm the data model for the table
366      * @param cm the column model for the table
367      * @see #createDefaultSelectionModel
368      */

369     public JTable(TableModel dm, TableColumnModel cm) {
370         this(dm, cm, null);
371     }
372
373     /**
374      * Constructs a <code>JTable</code> that is initialized with
375      * <code>dm</code> as the data model, <code>cm</code> as the
376      * column model, and <code>sm</code> as the selection model.
377      * If any of the parameters are <code>null</code> this method
378      * will initialize the table with the corresponding default model.
379      * The <code>autoCreateColumnsFromModel</code> flag is set to false
380      * if <code>cm</code> is non-null, otherwise it is set to true
381      * and the column model is populated with suitable
382      * <code>TableColumns</code> for the columns in <code>dm</code>.
383      *
384      * @param dm the data model for the table
385      * @param cm the column model for the table
386      * @param sm the row selection model for the table
387      * @see #createDefaultDataModel
388      * @see #createDefaultColumnModel
389      * @see #createDefaultSelectionModel
390      */

391     public JTable(TableModel dm, TableColumnModel cm, ListSelectionModel JavaDoc sm) {
392         super();
393         setLayout(null);
394
395     setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
396                JComponent.getManagingFocusForwardTraversalKeys());
397     setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
398                JComponent.getManagingFocusBackwardTraversalKeys());
399
400         if (cm == null) {
401             cm = createDefaultColumnModel();
402             autoCreateColumnsFromModel = true;
403         }
404         setColumnModel(cm);
405
406         if (sm == null) {
407             sm = createDefaultSelectionModel();
408         }
409     setSelectionModel(sm);
410
411     // Set the model last, that way if the autoCreatColumnsFromModel has
412
// been set above, we will automatically populate an empty columnModel
413
// with suitable columns for the new model.
414
if (dm == null) {
415             dm = createDefaultDataModel();
416         }
417     setModel(dm);
418
419         initializeLocalVars();
420         updateUI();
421     }
422
423     /**
424      * Constructs a <code>JTable</code> with <code>numRows</code>
425      * and <code>numColumns</code> of empty cells using
426      * <code>DefaultTableModel</code>. The columns will have
427      * names of the form "A", "B", "C", etc.
428      *
429      * @param numRows the number of rows the table holds
430      * @param numColumns the number of columns the table holds
431      * @see javax.swing.table.DefaultTableModel
432      */

433     public JTable(int numRows, int numColumns) {
434         this(new DefaultTableModel(numRows, numColumns));
435     }
436
437     /**
438      * Constructs a <code>JTable</code> to display the values in the
439      * <code>Vector</code> of <code>Vectors</code>, <code>rowData</code>,
440      * with column names, <code>columnNames</code>. The
441      * <code>Vectors</code> contained in <code>rowData</code>
442      * should contain the values for that row. In other words,
443      * the value of the cell at row 1, column 5 can be obtained
444      * with the following code:
445      * <p>
446      * <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
447      * <p>
448      * @param rowData the data for the new table
449      * @param columnNames names of each column
450      */

451     public JTable(Vector rowData, Vector columnNames) {
452         this(new DefaultTableModel(rowData, columnNames));
453     }
454
455     /**
456      * Constructs a <code>JTable</code> to display the values in the two dimensional array,
457      * <code>rowData</code>, with column names, <code>columnNames</code>.
458      * <code>rowData</code> is an array of rows, so the value of the cell at row 1,
459      * column 5 can be obtained with the following code:
460      * <p>
461      * <pre> rowData[1][5]; </pre>
462      * <p>
463      * All rows must be of the same length as <code>columnNames</code>.
464      * <p>
465      * @param rowData the data for the new table
466      * @param columnNames names of each column
467      */

468     public JTable(final Object JavaDoc[][] rowData, final Object JavaDoc[] columnNames) {
469         this(new AbstractTableModel() {
470             public String JavaDoc getColumnName(int column) { return columnNames[column].toString(); }
471             public int getRowCount() { return rowData.length; }
472             public int getColumnCount() { return columnNames.length; }
473             public Object JavaDoc getValueAt(int row, int col) { return rowData[row][col]; }
474             public boolean isCellEditable(int row, int column) { return true; }
475             public void setValueAt(Object JavaDoc value, int row, int col) {
476                 rowData[row][col] = value;
477                 fireTableCellUpdated(row, col);
478             }
479         });
480     }
481
482     /**
483      * Calls the <code>configureEnclosingScrollPane</code> method.
484      *
485      * @see #configureEnclosingScrollPane
486      */

487     public void addNotify() {
488         super.addNotify();
489         configureEnclosingScrollPane();
490     }
491
492     /**
493      * If this <code>JTable</code> is the <code>viewportView</code> of an enclosing <code>JScrollPane</code>
494      * (the usual situation), configure this <code>ScrollPane</code> by, amongst other things,
495      * installing the table's <code>tableHeader</code> as the <code>columnHeaderView</code> of the scroll pane.
496      * When a <code>JTable</code> is added to a <code>JScrollPane</code> in the usual way,
497      * using <code>new JScrollPane(myTable)</code>, <code>addNotify</code> is
498      * called in the <code>JTable</code> (when the table is added to the viewport).
499      * <code>JTable</code>'s <code>addNotify</code> method in turn calls this method,
500      * which is protected so that this default installation procedure can
501      * be overridden by a subclass.
502      *
503      * @see #addNotify
504      */

505     protected void configureEnclosingScrollPane() {
506         Container p = getParent();
507         if (p instanceof JViewport JavaDoc) {
508             Container gp = p.getParent();
509             if (gp instanceof JScrollPane JavaDoc) {
510                 JScrollPane JavaDoc scrollPane = (JScrollPane JavaDoc)gp;
511                 // Make certain we are the viewPort's view and not, for
512
// example, the rowHeaderView of the scrollPane -
513
// an implementor of fixed columns might do this.
514
JViewport JavaDoc viewport = scrollPane.getViewport();
515                 if (viewport == null || viewport.getView() != this) {
516                     return;
517                 }
518                 scrollPane.setColumnHeaderView(getTableHeader());
519         // scrollPane.getViewport().setBackingStoreEnabled(true);
520
Border border = scrollPane.getBorder();
521                 if (border == null || border instanceof UIResource) {
522                     scrollPane.setBorder(UIManager.getBorder("Table.scrollPaneBorder"));
523                 }
524             }
525         }
526     }
527
528     /**
529      * Calls the <code>unconfigureEnclosingScrollPane</code> method.
530      *
531      * @see #unconfigureEnclosingScrollPane
532      */

533     public void removeNotify() {
534         KeyboardFocusManager.getCurrentKeyboardFocusManager().
535             removePropertyChangeListener("permanentFocusOwner", editorRemover);
536     editorRemover = null;
537         unconfigureEnclosingScrollPane();
538         super.removeNotify();
539     }
540
541     /**
542      * Reverses the effect of <code>configureEnclosingScrollPane</code>
543      * by replacing the <code>columnHeaderView</code> of the enclosing
544      * scroll pane with <code>null</code>. <code>JTable</code>'s
545      * <code>removeNotify</code> method calls
546      * this method, which is protected so that this default uninstallation
547      * procedure can be overridden by a subclass.
548      *
549      * @see #removeNotify
550      * @see #configureEnclosingScrollPane
551      */

552     protected void unconfigureEnclosingScrollPane() {
553         Container p = getParent();
554         if (p instanceof JViewport JavaDoc) {
555             Container gp = p.getParent();
556             if (gp instanceof JScrollPane JavaDoc) {
557                 JScrollPane JavaDoc scrollPane = (JScrollPane JavaDoc)gp;
558                 // Make certain we are the viewPort's view and not, for
559
// example, the rowHeaderView of the scrollPane -
560
// an implementor of fixed columns might do this.
561
JViewport JavaDoc viewport = scrollPane.getViewport();
562                 if (viewport == null || viewport.getView() != this) {
563                     return;
564                 }
565                 scrollPane.setColumnHeaderView(null);
566             }
567         }
568     }
569
570     void setUIProperty(String JavaDoc propertyName, Object JavaDoc value) {
571         if (propertyName == "rowHeight") {
572             if (!isRowHeightSet) {
573                 setRowHeight(((Number JavaDoc)value).intValue());
574                 isRowHeightSet = false;
575             }
576             return;
577         }
578         super.setUIProperty(propertyName, value);
579     }
580
581 //
582
// Static Methods
583
//
584

585     /**
586      * Equivalent to <code>new JScrollPane(aTable)</code>.
587      *
588      * @deprecated As of Swing version 1.0.2,
589      * replaced by <code>new JScrollPane(aTable)</code>.
590      */

591     @Deprecated JavaDoc
592     static public JScrollPane JavaDoc createScrollPaneForTable(JTable JavaDoc aTable) {
593         return new JScrollPane JavaDoc(aTable);
594     }
595
596 //
597
// Table Attributes
598
//
599

600     /**
601      * Sets the <code>tableHeader</code> working with this <code>JTable</code> to <code>newHeader</code>.
602      * It is legal to have a <code>null</code> <code>tableHeader</code>.
603      *
604      * @param tableHeader new tableHeader
605      * @see #getTableHeader
606      * @beaninfo
607      * bound: true
608      * description: The JTableHeader instance which renders the column headers.
609      */

610     public void setTableHeader(JTableHeader tableHeader) {
611         if (this.tableHeader != tableHeader) {
612         JTableHeader old = this.tableHeader;
613             // Release the old header
614
if (old != null) {
615                 old.setTable(null);
616         }
617             this.tableHeader = tableHeader;
618             if (tableHeader != null) {
619                 tableHeader.setTable(this);
620         }
621         firePropertyChange("tableHeader", old, tableHeader);
622         }
623     }
624
625     /**
626      * Returns the <code>tableHeader</code> used by this <code>JTable</code>.
627      *
628      * @return the <code>tableHeader</code> used by this table
629      * @see #setTableHeader
630      */

631     public JTableHeader getTableHeader() {
632         return tableHeader;
633     }
634
635     /**
636      * Sets the height, in pixels, of all cells to <code>rowHeight</code>,
637      * revalidates, and repaints.
638      * The height of the cells will be equal to the row height minus
639      * the row margin.
640      *
641      * @param rowHeight new row height
642      * @exception IllegalArgumentException if <code>rowHeight</code> is
643      * less than 1
644      * @see #getRowHeight
645      * @beaninfo
646      * bound: true
647      * description: The height of the specified row.
648      */

649     public void setRowHeight(int rowHeight) {
650         if (rowHeight <= 0) {
651             throw new IllegalArgumentException JavaDoc("New row height less than 1");
652         }
653     int old = this.rowHeight;
654         this.rowHeight = rowHeight;
655     rowModel = null;
656         isRowHeightSet = true;
657         resizeAndRepaint();
658     firePropertyChange("rowHeight", old, rowHeight);
659     }
660
661     /**
662      * Returns the height of a table row, in pixels.
663      * The default row height is 16.0.
664      *
665      * @return the height in pixels of a table row
666      * @see #setRowHeight
667      */

668     public int getRowHeight() {
669         return rowHeight;
670     }
671
672     private SizeSequence JavaDoc getRowModel() {
673     if (rowModel == null) {
674         rowModel = new SizeSequence JavaDoc(getRowCount(), getRowHeight());
675     }
676     return rowModel;
677     }
678
679     /**
680      * Sets the height for <code>row</code> to <code>rowHeight</code>,
681      * revalidates, and repaints. The height of the cells in this row
682      * will be equal to the row height minus the row margin.
683      *
684      * @param row the row whose height is being
685                         changed
686      * @param rowHeight new row height, in pixels
687      * @exception IllegalArgumentException if <code>rowHeight</code> is
688      * less than 1
689      * @beaninfo
690      * bound: true
691      * description: The height in pixels of the cells in <code>row</code>
692      */

693     public void setRowHeight(int row, int rowHeight) {
694         if (rowHeight <= 0) {
695             throw new IllegalArgumentException JavaDoc("New row height less than 1");
696         }
697     getRowModel().setSize(row, rowHeight);
698     resizeAndRepaint();
699     }
700
701     /**
702      * Returns the height, in pixels, of the cells in <code>row</code>.
703      * @param row the row whose height is to be returned
704      * @return the height, in pixels, of the cells in the row
705      */

706     public int getRowHeight(int row) {
707     return (rowModel == null) ? getRowHeight() : rowModel.getSize(row);
708     }
709
710     /**
711      * Sets the amount of empty space between cells in adjacent rows.
712      *
713      * @param rowMargin the number of pixels between cells in a row
714      * @see #getRowMargin
715      * @beaninfo
716      * bound: true
717      * description: The amount of space between cells.
718      */

719     public void setRowMargin(int rowMargin) {
720     int old = this.rowMargin;
721         this.rowMargin = rowMargin;
722         resizeAndRepaint();
723     firePropertyChange("rowMargin", old, rowMargin);
724     }
725
726     /**
727      * Gets the amount of empty space, in pixels, between cells. Equivalent to:
728      * <code>getIntercellSpacing().height</code>.
729      * @return the number of pixels between cells in a row
730      *
731      * @see #setRowMargin
732      */

733     public int getRowMargin() {
734         return rowMargin;
735     }
736
737     /**
738      * Sets the <code>rowMargin</code> and the <code>columnMargin</code> --
739      * the height and width of the space between cells -- to
740      * <code>intercellSpacing</code>.
741      *
742      * @param intercellSpacing a <code>Dimension</code>
743      * specifying the new width
744      * and height between cells
745      * @see #getIntercellSpacing
746      * @beaninfo
747      * description: The spacing between the cells,
748      * drawn in the background color of the JTable.
749      */

750     public void setIntercellSpacing(Dimension intercellSpacing) {
751         // Set the rowMargin here and columnMargin in the TableColumnModel
752
setRowMargin(intercellSpacing.height);
753         getColumnModel().setColumnMargin(intercellSpacing.width);
754
755         resizeAndRepaint();
756     }
757
758     /**
759      * Returns the horizontal and vertical space between cells.
760      * The default spacing is (1, 1), which provides room to draw the grid.
761      *
762      * @return the horizontal and vertical spacing between cells
763      * @see #setIntercellSpacing
764      */

765     public Dimension getIntercellSpacing() {
766         return new Dimension(getColumnModel().getColumnMargin(), rowMargin);
767     }
768
769     /**
770      * Sets the color used to draw grid lines to <code>gridColor</code> and redisplays.
771      * The default color is look and feel dependent.
772      *
773      * @param gridColor the new color of the grid lines
774      * @exception IllegalArgumentException if <code>gridColor</code> is <code>null</code>
775      * @see #getGridColor
776      * @beaninfo
777      * bound: true
778      * description: The grid color.
779      */

780     public void setGridColor(Color gridColor) {
781         if (gridColor == null) {
782             throw new IllegalArgumentException JavaDoc("New color is null");
783         }
784     Color old = this.gridColor;
785         this.gridColor = gridColor;
786     firePropertyChange("gridColor", old, gridColor);
787         // Redraw
788
repaint();
789     }
790
791     /**
792      * Returns the color used to draw grid lines.
793      * The default color is look and feel dependent.
794      *
795      * @return the color used to draw grid lines
796      * @see #setGridColor
797      */

798     public Color getGridColor() {
799         return gridColor;
800     }
801
802     /**
803      * Sets whether the table draws grid lines around cells.
804      * If <code>showGrid</code> is true it does; if it is false it doesn't.
805      * There is no <code>getShowGrid</code> method as this state is held
806      * in two variables -- <code>showHorizontalLines</code> and <code>showVerticalLines</code> --
807      * each of which can be queried independently.
808      *
809      * @param showGrid true if table view should draw grid lines
810      *
811      * @see #setShowVerticalLines
812      * @see #setShowHorizontalLines
813      * @beaninfo
814      * description: The color used to draw the grid lines.
815      */

816     public void setShowGrid(boolean showGrid) {
817         setShowHorizontalLines(showGrid);
818         setShowVerticalLines(showGrid);
819
820         // Redraw
821
repaint();
822     }
823
824     /**
825      * Sets whether the table draws horizontal lines between cells.
826      * If <code>showHorizontalLines</code> is true it does; if it is false it doesn't.
827      *
828      * @param showHorizontalLines true if table view should draw horizontal lines
829      * @see #getShowHorizontalLines
830      * @see #setShowGrid
831      * @see #setShowVerticalLines
832      * @beaninfo
833      * bound: true
834      * description: Whether horizontal lines should be drawn in between the cells.
835      */

836     public void setShowHorizontalLines(boolean showHorizontalLines) {
837         boolean old = this.showHorizontalLines;
838     this.showHorizontalLines = showHorizontalLines;
839     firePropertyChange("showHorizontalLines", old, showHorizontalLines);
840
841         // Redraw
842
repaint();
843     }
844
845     /**
846      * Sets whether the table draws vertical lines between cells.
847      * If <code>showVerticalLines</code> is true it does; if it is false it doesn't.
848      *
849      * @param showVerticalLines true if table view should draw vertical lines
850      * @see #getShowVerticalLines
851      * @see #setShowGrid
852      * @see #setShowHorizontalLines
853      * @beaninfo
854      * bound: true
855      * description: Whether vertical lines should be drawn in between the cells.
856      */

857     public void setShowVerticalLines(boolean showVerticalLines) {
858         boolean old = this.showVerticalLines;
859     this.showVerticalLines = showVerticalLines;
860     firePropertyChange("showVerticalLines", old, showVerticalLines);
861         // Redraw
862
repaint();
863     }
864
865     /**
866      * Returns true if the table draws horizontal lines between cells, false if it
867      * doesn't. The default is true.
868      *
869      * @return true if the table draws horizontal lines between cells, false if it
870      * doesn't
871      * @see #setShowHorizontalLines
872      */

873     public boolean getShowHorizontalLines() {
874         return showHorizontalLines;
875     }
876
877     /**
878      * Returns true if the table draws vertical lines between cells, false if it
879      * doesn't. The default is true.
880      *
881      * @return true if the table draws vertical lines between cells, false if it
882      * doesn't
883      * @see #setShowVerticalLines
884      */

885     public boolean getShowVerticalLines() {
886         return showVerticalLines;
887     }
888
889     /**
890      * Sets the table's auto resize mode when the table is resized.
891      *
892      * @param mode One of 5 legal values:
893      * AUTO_RESIZE_OFF,
894      * AUTO_RESIZE_NEXT_COLUMN,
895      * AUTO_RESIZE_SUBSEQUENT_COLUMNS,
896      * AUTO_RESIZE_LAST_COLUMN,
897      * AUTO_RESIZE_ALL_COLUMNS
898      *
899      * @see #getAutoResizeMode
900      * @see #doLayout
901      * @beaninfo
902      * bound: true
903      * description: Whether the columns should adjust themselves automatically.
904      * enum: AUTO_RESIZE_OFF JTable.AUTO_RESIZE_OFF
905      * AUTO_RESIZE_NEXT_COLUMN JTable.AUTO_RESIZE_NEXT_COLUMN
906      * AUTO_RESIZE_SUBSEQUENT_COLUMNS JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS
907      * AUTO_RESIZE_LAST_COLUMN JTable.AUTO_RESIZE_LAST_COLUMN
908      * AUTO_RESIZE_ALL_COLUMNS JTable.AUTO_RESIZE_ALL_COLUMNS
909      */

910     public void setAutoResizeMode(int mode) {
911         if ((mode == AUTO_RESIZE_OFF) ||
912             (mode == AUTO_RESIZE_NEXT_COLUMN) ||
913             (mode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) ||
914             (mode == AUTO_RESIZE_LAST_COLUMN) ||
915             (mode == AUTO_RESIZE_ALL_COLUMNS)) {
916         int old = autoResizeMode;
917             autoResizeMode = mode;
918             resizeAndRepaint();
919             if (tableHeader != null) {
920         tableHeader.resizeAndRepaint();
921         }
922         firePropertyChange("autoResizeMode", old, autoResizeMode);
923         }
924     }
925
926     /**
927      * Returns the auto resize mode of the table. The default mode
928      * is AUTO_RESIZE_SUBSEQUENT_COLUMNS.
929      *
930      * @return the autoResizeMode of the table
931      *
932      * @see #setAutoResizeMode
933      * @see #doLayout
934      */

935     public int getAutoResizeMode() {
936         return autoResizeMode;
937     }
938
939     /**
940      * Sets this table's <code>autoCreateColumnsFromModel</code> flag.
941      * This method calls <code>createDefaultColumnsFromModel</code> if
942      * <code>autoCreateColumnsFromModel</code> changes from false to true.
943      *
944      * @param autoCreateColumnsFromModel true if <code>JTable</code> should automatically create columns
945      * @see #getAutoCreateColumnsFromModel
946      * @see #createDefaultColumnsFromModel
947      * @beaninfo
948      * bound: true
949      * description: Automatically populates the columnModel when a new TableModel is submitted.
950      */

951     public void setAutoCreateColumnsFromModel(boolean autoCreateColumnsFromModel) {
952         if (this.autoCreateColumnsFromModel != autoCreateColumnsFromModel) {
953         boolean old = this.autoCreateColumnsFromModel;
954             this.autoCreateColumnsFromModel = autoCreateColumnsFromModel;
955             if (autoCreateColumnsFromModel) {
956                 createDefaultColumnsFromModel();
957         }
958         firePropertyChange("autoCreateColumnsFromModel", old, autoCreateColumnsFromModel);
959         }
960     }
961
962     /**
963      * Determines whether the table will create default columns from the model.
964      * If true, <code>setModel</code> will clear any existing columns and
965      * create new columns from the new model. Also, if the event in
966      * the <code>tableChanged</code> notification specifies that the
967      * entire table changed, then the columns will be rebuilt.
968      * The default is true.
969      *
970      * @return the autoCreateColumnsFromModel of the table
971      * @see #setAutoCreateColumnsFromModel
972      * @see #createDefaultColumnsFromModel
973      */

974     public boolean getAutoCreateColumnsFromModel() {
975         return autoCreateColumnsFromModel;
976     }
977
978     /**
979      * Creates default columns for the table from
980      * the data model using the <code>getColumnCount</code> method
981      * defined in the <code>TableModel</code> interface.
982      * <p>
983      * Clears any existing columns before creating the
984      * new columns based on information from the model.
985      *
986      * @see #getAutoCreateColumnsFromModel
987      */

988     public void createDefaultColumnsFromModel() {
989         TableModel m = getModel();
990         if (m != null) {
991             // Remove any current columns
992
TableColumnModel cm = getColumnModel();
993             while (cm.getColumnCount() > 0) {
994                 cm.removeColumn(cm.getColumn(0));
995         }
996
997             // Create new columns from the data model info
998
for (int i = 0; i < m.getColumnCount(); i++) {
999                 TableColumn newColumn = new TableColumn(i);
1000                addColumn(newColumn);
1001            }
1002        }
1003    }
1004
1005    /**
1006     * Sets a default cell renderer to be used if no renderer has been set in
1007     * a <code>TableColumn</code>. If renderer is <code>null</code>,
1008     * removes the default renderer for this column class.
1009     *
1010     * @param columnClass set the default cell renderer for this columnClass
1011     * @param renderer default cell renderer to be used for this
1012     * columnClass
1013     * @see #getDefaultRenderer
1014     * @see #setDefaultEditor
1015     */

1016    public void setDefaultRenderer(Class JavaDoc<?> columnClass, TableCellRenderer renderer) {
1017    if (renderer != null) {
1018        defaultRenderersByColumnClass.put(columnClass, renderer);
1019    }
1020    else {
1021        defaultRenderersByColumnClass.remove(columnClass);
1022    }
1023    }
1024
1025    /**
1026     * Returns the cell renderer to be used when no renderer has been set in
1027     * a <code>TableColumn</code>. During the rendering of cells the renderer is fetched from
1028     * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
1029     * there is no entry for this <code>columnClass</code> the method returns
1030     * the entry for the most specific superclass. The <code>JTable</code> installs entries
1031     * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
1032     * or replaced.
1033     *
1034     * @param columnClass return the default cell renderer
1035     * for this columnClass
1036     * @return the renderer for this columnClass
1037     * @see #setDefaultRenderer
1038     * @see #getColumnClass
1039     */

1040    public TableCellRenderer getDefaultRenderer(Class JavaDoc<?> columnClass) {
1041        if (columnClass == null) {
1042            return null;
1043        }
1044        else {
1045            Object JavaDoc renderer = defaultRenderersByColumnClass.get(columnClass);
1046            if (renderer != null) {
1047                return (TableCellRenderer)renderer;
1048            }
1049            else {
1050                return getDefaultRenderer(columnClass.getSuperclass());
1051            }
1052        }
1053    }
1054
1055    /**
1056     * Sets a default cell editor to be used if no editor has been set in
1057     * a <code>TableColumn</code>. If no editing is required in a table, or a
1058     * particular column in a table, uses the <code>isCellEditable</code>
1059     * method in the <code>TableModel</code> interface to ensure that this
1060     * <code>JTable</code> will not start an editor in these columns.
1061     * If editor is <code>null</code>, removes the default editor for this
1062     * column class.
1063     *
1064     * @param columnClass set the default cell editor for this columnClass
1065     * @param editor default cell editor to be used for this columnClass
1066     * @see TableModel#isCellEditable
1067     * @see #getDefaultEditor
1068     * @see #setDefaultRenderer
1069     */

1070    public void setDefaultEditor(Class JavaDoc<?> columnClass, TableCellEditor editor) {
1071        if (editor != null) {
1072        defaultEditorsByColumnClass.put(columnClass, editor);
1073    }
1074    else {
1075        defaultEditorsByColumnClass.remove(columnClass);
1076    }
1077    }
1078
1079    /**
1080     * Returns the editor to be used when no editor has been set in
1081     * a <code>TableColumn</code>. During the editing of cells the editor is fetched from
1082     * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
1083     * there is no entry for this <code>columnClass</code> the method returns
1084     * the entry for the most specific superclass. The <code>JTable</code> installs entries
1085     * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
1086     * or replaced.
1087     *
1088     * @param columnClass return the default cell editor for this columnClass
1089     * @return the default cell editor to be used for this columnClass
1090     * @see #setDefaultEditor
1091     * @see #getColumnClass
1092     */

1093    public TableCellEditor getDefaultEditor(Class JavaDoc<?> columnClass) {
1094        if (columnClass == null) {
1095            return null;
1096        }
1097        else {
1098            Object JavaDoc editor = defaultEditorsByColumnClass.get(columnClass);
1099            if (editor != null) {
1100                return (TableCellEditor)editor;
1101            }
1102            else {
1103                return getDefaultEditor(columnClass.getSuperclass());
1104            }
1105        }
1106    }
1107
1108    /**
1109     * Sets the <code>dragEnabled</code> property,
1110     * which must be <code>true</code> to enable
1111     * automatic drag handling (the first part of drag and drop)
1112     * on this component.
1113     * The <code>transferHandler</code> property needs to be set
1114     * to a non-<code>null</code> value for the drag to do
1115     * anything. The default value of the <code>dragEnabled</code
1116     * property
1117     * is <code>false</code>.
1118     *
1119     * <p>
1120     *
1121     * When automatic drag handling is enabled,
1122     * most look and feels begin a drag-and-drop operation
1123     * whenever the user presses the mouse button over a selection
1124     * and then moves the mouse a few pixels.
1125     * Setting this property to <code>true</code>
1126     * can therefore have a subtle effect on
1127     * how selections behave.
1128     *
1129     * <p>
1130     *
1131     * Some look and feels might not support automatic drag and drop;
1132     * they will ignore this property. You can work around such
1133     * look and feels by modifying the component
1134     * to directly call the <code>exportAsDrag</code> method of a
1135     * <code>TransferHandler</code>.
1136     *
1137     * @param b the value to set the <code>dragEnabled</code> property to
1138     * @exception HeadlessException if
1139     * <code>b</code> is <code>true</code> and
1140     * <code>GraphicsEnvironment.isHeadless()</code>
1141     * returns <code>true</code>
1142     * @see java.awt.GraphicsEnvironment#isHeadless
1143     * @see #getDragEnabled
1144     * @see #setTransferHandler
1145     * @see TransferHandler
1146     * @since 1.4
1147     *
1148     * @beaninfo
1149     * description: determines whether automatic drag handling is enabled
1150     * bound: false
1151     */

1152    public void setDragEnabled(boolean b) {
1153        if (b && GraphicsEnvironment.isHeadless()) {
1154            throw new HeadlessException();
1155        }
1156    dragEnabled = b;
1157    }
1158
1159    /**
1160     * Gets the value of the <code>dragEnabled</code> property.
1161     *
1162     * @return the value of the <code>dragEnabled</code> property
1163     * @see #setDragEnabled
1164     * @since 1.4
1165     */

1166    public boolean getDragEnabled() {
1167    return dragEnabled;
1168    }
1169
1170
1171//
1172
// Selection methods
1173
//
1174
/**
1175     * Sets the table's selection mode to allow only single selections, a single
1176     * contiguous interval, or multiple intervals.
1177     * <P>
1178     * <bold>Note:</bold>
1179     * <code>JTable</code> provides all the methods for handling
1180     * column and row selection. When setting states,
1181     * such as <code>setSelectionMode</code>, it not only
1182     * updates the mode for the row selection model but also sets similar
1183     * values in the selection model of the <code>columnModel</code>.
1184     * If you want to have the row and column selection models operating
1185     * in different modes, set them both directly.
1186     * <p>
1187     * Both the row and column selection models for <code>JTable</code>
1188     * default to using a <code>DefaultListSelectionModel</code>
1189     * so that <code>JTable</code> works the same way as the
1190     * <code>JList</code>. See the <code>setSelectionMode</code> method
1191     * in <code>JList</code> for details about the modes.
1192     *
1193     * @see JList#setSelectionMode
1194     * @beaninfo
1195     * description: The selection mode used by the row and column selection models.
1196     * enum: SINGLE_SELECTION ListSelectionModel.SINGLE_SELECTION
1197     * SINGLE_INTERVAL_SELECTION ListSelectionModel.SINGLE_INTERVAL_SELECTION
1198     * MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
1199     */

1200    public void setSelectionMode(int selectionMode) {
1201        clearSelection();
1202        getSelectionModel().setSelectionMode(selectionMode);
1203        getColumnModel().getSelectionModel().setSelectionMode(selectionMode);
1204    }
1205
1206    /**
1207     * Sets whether the rows in this model can be selected.
1208     *
1209     * @param rowSelectionAllowed true if this model will allow row selection
1210     * @see #getRowSelectionAllowed
1211     * @beaninfo
1212     * bound: true
1213     * attribute: visualUpdate true
1214     * description: If true, an entire row is selected for each selected cell.
1215     */

1216    public void setRowSelectionAllowed(boolean rowSelectionAllowed) {
1217    boolean old = this.rowSelectionAllowed;
1218        this.rowSelectionAllowed = rowSelectionAllowed;
1219        if (old != rowSelectionAllowed) {
1220            repaint();
1221        }
1222    firePropertyChange("rowSelectionAllowed", old, rowSelectionAllowed);
1223    }
1224
1225    /**
1226     * Returns true if rows can be selected.
1227     *
1228     * @return true if rows can be selected, otherwise false
1229     * @see #setRowSelectionAllowed
1230     */

1231    public boolean getRowSelectionAllowed() {
1232        return rowSelectionAllowed;
1233    }
1234
1235    /**
1236     * Sets whether the columns in this model can be selected.
1237     *
1238     * @param columnSelectionAllowed true if this model will allow column selection
1239     * @see #getColumnSelectionAllowed
1240     * @beaninfo
1241     * bound: true
1242     * attribute: visualUpdate true
1243     * description: If true, an entire column is selected for each selected cell.
1244     */

1245    public void setColumnSelectionAllowed(boolean columnSelectionAllowed) {
1246    boolean old = columnModel.getColumnSelectionAllowed();
1247        columnModel.setColumnSelectionAllowed(columnSelectionAllowed);
1248        if (old != columnSelectionAllowed) {
1249            repaint();
1250        }
1251    firePropertyChange("columnSelectionAllowed", old, columnSelectionAllowed);
1252    }
1253
1254    /**
1255     * Returns true if columns can be selected.
1256     *
1257     * @return true if columns can be selected, otherwise false
1258     * @see #setColumnSelectionAllowed
1259     */

1260    public boolean getColumnSelectionAllowed() {
1261        return columnModel.getColumnSelectionAllowed();
1262    }
1263
1264    /**
1265     * Sets whether this table allows both a column selection and a
1266     * row selection to exist simultaneously. When set,
1267     * the table treats the intersection of the row and column selection
1268     * models as the selected cells. Override <code>isCellSelected</code> to
1269     * change this default behavior. This method is equivalent to setting
1270     * both the <code>rowSelectionAllowed</code> property and
1271     * <code>columnSelectionAllowed</code> property of the
1272     * <code>columnModel</code> to the supplied value.
1273     *
1274     * @param cellSelectionEnabled true if simultaneous row and column
1275     * selection is allowed
1276     * @see #getCellSelectionEnabled
1277     * @see #isCellSelected
1278     * @beaninfo
1279     * bound: true
1280     * attribute: visualUpdate true
1281     * description: Select a rectangular region of cells rather than
1282     * rows or columns.
1283     */

1284    public void setCellSelectionEnabled(boolean cellSelectionEnabled) {
1285    setRowSelectionAllowed(cellSelectionEnabled);
1286    setColumnSelectionAllowed(cellSelectionEnabled);
1287        boolean old = this.cellSelectionEnabled;
1288    this.cellSelectionEnabled = cellSelectionEnabled;
1289    firePropertyChange("cellSelectionEnabled", old, cellSelectionEnabled);
1290    }
1291
1292    /**
1293     * Returns true if both row and column selection models are enabled.
1294     * Equivalent to <code>getRowSelectionAllowed() &&
1295     * getColumnSelectionAllowed()</code>.
1296     *
1297     * @return true if both row and column selection models are enabled
1298     *
1299     * @see #setCellSelectionEnabled
1300     */

1301    public boolean getCellSelectionEnabled() {
1302        return getRowSelectionAllowed() && getColumnSelectionAllowed();
1303    }
1304
1305    /**
1306     * Selects all rows, columns, and cells in the table.
1307     */

1308    public void selectAll() {
1309        // If I'm currently editing, then I should stop editing
1310
if (isEditing()) {
1311            removeEditor();
1312        }
1313    if (getRowCount() > 0 && getColumnCount() > 0) {
1314            int oldLead;
1315            int oldAnchor;
1316            ListSelectionModel JavaDoc selModel;
1317
1318            selModel = selectionModel;
1319            selModel.setValueIsAdjusting(true);
1320            oldLead = getAdjustedIndex(selModel.getLeadSelectionIndex(), true);
1321            oldAnchor = getAdjustedIndex(selModel.getAnchorSelectionIndex(), true);
1322
1323            setRowSelectionInterval(0, getRowCount()-1);
1324
1325            if (oldAnchor == -1) {
1326                oldAnchor = oldLead;
1327            }
1328
1329            // this is done to restore the anchor and lead
1330
if (oldLead == -1) {
1331                selModel.setAnchorSelectionIndex(-1);
1332                selModel.setLeadSelectionIndex(-1);
1333            } else {
1334                selModel.addSelectionInterval(oldAnchor, oldLead);
1335            }
1336
1337            selModel.setValueIsAdjusting(false);
1338
1339            selModel = columnModel.getSelectionModel();
1340            selModel.setValueIsAdjusting(true);
1341            oldLead = getAdjustedIndex(selModel.getLeadSelectionIndex(), false);
1342            oldAnchor = getAdjustedIndex(selModel.getAnchorSelectionIndex(), false);
1343
1344            setColumnSelectionInterval(0, getColumnCount()-1);
1345
1346            if (oldAnchor == -1) {
1347                oldAnchor = oldLead;
1348            }
1349
1350            // this is done to restore the anchor and lead
1351
if (oldLead == -1) {
1352                selModel.setAnchorSelectionIndex(-1);
1353                selModel.setLeadSelectionIndex(-1);
1354            } else {
1355                selModel.addSelectionInterval(oldAnchor, oldLead);
1356            }
1357
1358            selModel.setValueIsAdjusting(false);
1359    }
1360    }
1361
1362    /**
1363     * Deselects all selected columns and rows.
1364     */

1365    public void clearSelection() {
1366        selectionModel.clearSelection();
1367        columnModel.getSelectionModel().clearSelection();
1368    }
1369
1370    private void clearSelectionAndLeadAnchor() {
1371        selectionModel.setValueIsAdjusting(true);
1372        columnModel.getSelectionModel().setValueIsAdjusting(true);
1373        
1374        clearSelection();
1375
1376        selectionModel.setAnchorSelectionIndex(-1);
1377        selectionModel.setLeadSelectionIndex(-1);
1378        columnModel.getSelectionModel().setAnchorSelectionIndex(-1);
1379        columnModel.getSelectionModel().setLeadSelectionIndex(-1);
1380
1381        selectionModel.setValueIsAdjusting(false);
1382        columnModel.getSelectionModel().setValueIsAdjusting(false);
1383    }
1384
1385    private int getAdjustedIndex(int index, boolean row) {
1386        int compare = row ? getRowCount() : getColumnCount();
1387        return index < compare ? index : -1;
1388    }
1389
1390    private int boundRow(int row) throws IllegalArgumentException JavaDoc {
1391    if (row < 0 || row >= getRowCount()) {
1392        throw new IllegalArgumentException JavaDoc("Row index out of range");
1393    }
1394    return row;
1395    }
1396
1397    private int boundColumn(int col) {
1398    if (col< 0 || col >= getColumnCount()) {
1399        throw new IllegalArgumentException JavaDoc("Column index out of range");
1400    }
1401    return col;
1402    }
1403
1404    /**
1405     * Selects the rows from <code>index0</code> to <code>index1</code>,
1406     * inclusive.
1407     *
1408     * @exception IllegalArgumentException if <code>index0</code> or
1409     * <code>index1</code> lie outside
1410     * [0, <code>getRowCount()</code>-1]
1411     * @param index0 one end of the interval
1412     * @param index1 the other end of the interval
1413     */

1414    public void setRowSelectionInterval(int index0, int index1) {
1415        selectionModel.setSelectionInterval(boundRow(index0), boundRow(index1));
1416    }
1417
1418    /**
1419     * Selects the columns from <code>index0</code> to <code>index1</code>,
1420     * inclusive.
1421     *
1422     * @exception IllegalArgumentException if <code>index0</code> or
1423     * <code>index1</code> lie outside
1424     * [0, <code>getColumnCount()</code>-1]
1425     * @param index0 one end of the interval
1426     * @param index1 the other end of the interval
1427     */

1428    public void setColumnSelectionInterval(int index0, int index1) {
1429        columnModel.getSelectionModel().setSelectionInterval(boundColumn(index0), boundColumn(index1));
1430    }
1431
1432    /**
1433     * Adds the rows from <code>index0</code> to <code>index1</code>, inclusive, to
1434     * the current selection.
1435     *
1436     * @exception IllegalArgumentException if <code>index0</code> or <code>index1</code>
1437     * lie outside [0, <code>getRowCount()</code>-1]
1438     * @param index0 one end of the interval
1439     * @param index1 the other end of the interval
1440     */

1441    public void addRowSelectionInterval(int index0, int index1) {
1442        selectionModel.addSelectionInterval(boundRow(index0), boundRow(index1));
1443    }
1444
1445    /**
1446     * Adds the columns from <code>index0</code> to <code>index1</code>,
1447     * inclusive, to the current selection.
1448     *
1449     * @exception IllegalArgumentException if <code>index0</code> or
1450     * <code>index1</code> lie outside
1451     * [0, <code>getColumnCount()</code>-1]
1452     * @param index0 one end of the interval
1453     * @param index1 the other end of the interval
1454     */

1455    public void addColumnSelectionInterval(int index0, int index1) {
1456        columnModel.getSelectionModel().addSelectionInterval(boundColumn(index0), boundColumn(index1));
1457    }
1458
1459    /**
1460     * Deselects the rows from <code>index0</code> to <code>index1</code>, inclusive.
1461     *
1462     * @exception IllegalArgumentException if <code>index0</code> or
1463     * <code>index1</code> lie outside
1464     * [0, <code>getRowCount()</code>-1]
1465     * @param index0 one end of the interval
1466     * @param index1 the other end of the interval
1467     */

1468    public void removeRowSelectionInterval(int index0, int index1) {
1469        selectionModel.removeSelectionInterval(boundRow(index0), boundRow(index1));
1470    }
1471
1472    /**
1473     * Deselects the columns from <code>index0</code> to <code>index1</code>, inclusive.
1474     *
1475     * @exception IllegalArgumentException if <code>index0</code> or
1476     * <code>index1</code> lie outside
1477     * [0, <code>getColumnCount()</code>-1]
1478     * @param index0 one end of the interval
1479     * @param index1 the other end of the interval
1480     */

1481    public void removeColumnSelectionInterval(int index0, int index1) {
1482        columnModel.getSelectionModel().removeSelectionInterval(boundColumn(index0), boundColumn(index1));
1483    }
1484
1485    /**
1486     * Returns the index of the first selected row, -1 if no row is selected.
1487     * @return the index of the first selected row
1488     */

1489    public int getSelectedRow() {
1490    return selectionModel.getMinSelectionIndex();
1491    }
1492
1493    /**
1494     * Returns the index of the first selected column,
1495     * -1 if no column is selected.
1496     * @return the index of the first selected column
1497     */

1498    public int getSelectedColumn() {
1499        return columnModel.getSelectionModel().getMinSelectionIndex();
1500    }
1501
1502    /**
1503     * Returns the indices of all selected rows.
1504     *
1505     * @return an array of integers containing the indices of all selected rows,
1506     * or an empty array if no row is selected
1507     * @see #getSelectedRow
1508     */

1509    public int[] getSelectedRows() {
1510    int iMin = selectionModel.getMinSelectionIndex();
1511    int iMax = selectionModel.getMaxSelectionIndex();
1512
1513    if ((iMin == -1) || (iMax == -1)) {
1514        return new int[0];
1515    }
1516
1517    int[] rvTmp = new int[1+ (iMax - iMin)];
1518    int n = 0;
1519    for(int i = iMin; i <= iMax; i++) {
1520        if (selectionModel.isSelectedIndex(i)) {
1521        rvTmp[n++] = i;
1522        }
1523    }
1524    int[] rv = new int[n];
1525    System.arraycopy(rvTmp, 0, rv, 0, n);
1526    return rv;
1527    }
1528
1529    /**
1530     * Returns the indices of all selected columns.
1531     *
1532     * @return an array of integers containing the indices of all selected columns,
1533     * or an empty array if no column is selected
1534     * @see #getSelectedColumn
1535     */

1536    public int[] getSelectedColumns() {
1537        return columnModel.getSelectedColumns();
1538    }
1539
1540    /**
1541     * Returns the number of selected rows.
1542     *
1543     * @return the number of selected rows, 0 if no rows are selected
1544     */

1545    public int getSelectedRowCount() {
1546    int iMin = selectionModel.getMinSelectionIndex();
1547    int iMax = selectionModel.getMaxSelectionIndex();
1548    int count = 0;
1549
1550    for(int i = iMin; i <= iMax; i++) {
1551        if (selectionModel.isSelectedIndex(i)) {
1552        count++;
1553        }
1554    }
1555    return count;
1556    }
1557
1558    /**
1559     * Returns the number of selected columns.
1560     *
1561     * @return the number of selected columns, 0 if no columns are selected
1562     */

1563    public int getSelectedColumnCount() {
1564        return columnModel.getSelectedColumnCount();
1565    }
1566
1567    /**
1568     * Returns true if the specified index is in the valid range of rows,
1569     * and the row at that index is selected.
1570     *
1571     * @return true if <code>row</code> is a valid index and the row at
1572     * that index is selected (where 0 is the first row)
1573     */

1574    public boolean isRowSelected(int row) {
1575    return selectionModel.isSelectedIndex(row);
1576    }
1577
1578    /**
1579     * Returns true if the specified index is in the valid range of columns,
1580     * and the column at that index is selected.
1581     *
1582     * @param column the column in the column model
1583     * @return true if <code>column</code> is a valid index and the column at
1584     * that index is selected (where 0 is the first column)
1585     */

1586    public boolean isColumnSelected(int column) {
1587        return columnModel.getSelectionModel().isSelectedIndex(column);
1588    }
1589
1590    /**
1591     * Returns true if the specified indices are in the valid range of rows
1592     * and columns and the cell at the specified position is selected.
1593     * @param row the row being queried
1594     * @param column the column being queried
1595     *
1596     * @return true if <code>row</code> and <code>column</code> are valid indices
1597     * and the cell at index <code>(row, column)</code> is selected,
1598     * where the first row and first column are at index 0
1599     */

1600    public boolean isCellSelected(int row, int column) {
1601    if (!getRowSelectionAllowed() && !getColumnSelectionAllowed()) {
1602        return false;
1603    }
1604    return (!getRowSelectionAllowed() || isRowSelected(row)) &&
1605               (!getColumnSelectionAllowed() || isColumnSelected(column));
1606    }
1607
1608    private void changeSelectionModel(ListSelectionModel JavaDoc sm, int index,
1609                      boolean toggle, boolean extend, boolean selected,
1610                                      boolean row) {
1611        if (extend) {
1612            if (toggle) {
1613        sm.setAnchorSelectionIndex(index);
1614        }
1615        else {
1616                int anchorIndex = getAdjustedIndex(sm.getAnchorSelectionIndex(), row);
1617                if (anchorIndex == -1) {
1618                    anchorIndex = 0;
1619                }
1620
1621                sm.setSelectionInterval(anchorIndex, index);
1622        }
1623        }
1624    else {
1625            if (toggle) {
1626                if (selected) {
1627                    sm.removeSelectionInterval(index, index);
1628                }
1629                else {
1630                    sm.addSelectionInterval(index, index);
1631                }
1632            }
1633        else {
1634                sm.setSelectionInterval(index, index);
1635            }
1636        }
1637    }
1638
1639    /**
1640     * Updates the selection models of the table, depending on the state of the
1641     * two flags: <code>toggle</code> and <code>extend</code>. Most changes
1642     * to the selection that are the result of keyboard or mouse events received
1643     * by the UI are channeled through this method so that the behavior may be
1644     * overridden by a subclass. Some UIs may need more functionality than
1645     * this method provides, such as when manipulating the lead for discontiguous
1646     * selection, and may not call into this method for some selection changes.
1647     * <p>
1648     * This implementation uses the following conventions:
1649     * <ul>
1650     * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>false</em>.
1651     * Clear the previous selection and ensure the new cell is selected.
1652     * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>true</em>.
1653     * Extend the previous selection from the anchor to the specified cell,
1654     * clearing all other selections.
1655     * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>false</em>.
1656     * If the specified cell is selected, deselect it. If it is not selected, select it.
1657     * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>true</em>.
1658     * Leave the selection state as it is, but move the anchor index to the specified location.
1659     * </ul>
1660     * @param rowIndex affects the selection at <code>row</code>
1661     * @param columnIndex affects the selection at <code>column</code>
1662     * @param toggle see description above
1663     * @param extend if true, extend the current selection
1664     *
1665     */

1666    public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
1667        ListSelectionModel JavaDoc rsm = getSelectionModel();
1668        ListSelectionModel JavaDoc csm = getColumnModel().getSelectionModel();
1669
1670    // Check the selection here rather than in each selection model.
1671
// This is significant in cell selection mode if we are supposed
1672
// to be toggling the selection. In this case it is better to
1673
// ensure that the cell's selection state will indeed be changed.
1674
// If this were done in the code for the selection model it
1675
// might leave a cell in selection state if the row was
1676
// selected but the column was not - as it would toggle them both.
1677
boolean selected = isCellSelected(rowIndex, columnIndex);
1678
1679        changeSelectionModel(csm, columnIndex, toggle, extend, selected, false);
1680        changeSelectionModel(rsm, rowIndex, toggle, extend, selected, true);
1681
1682        // Scroll after changing the selection as blit scrolling is immediate,
1683
// so that if we cause the repaint after the scroll we end up painting
1684
// everything!
1685
if (getAutoscrolls()) {
1686        Rectangle cellRect = getCellRect(rowIndex, columnIndex, false);
1687        if (cellRect != null) {
1688        scrollRectToVisible(cellRect);
1689        }
1690    }
1691    }
1692
1693    /**
1694     * Returns the foreground color for selected cells.
1695     *
1696     * @return the <code>Color</code> object for the foreground property
1697     * @see #setSelectionForeground
1698     * @see #setSelectionBackground
1699     */

1700    public Color getSelectionForeground() {
1701        return selectionForeground;
1702    }
1703
1704    /**
1705     * Sets the foreground color for selected cells. Cell renderers
1706     * can use this color to render text and graphics for selected
1707     * cells.
1708     * <p>
1709     * The default value of this property is defined by the look
1710     * and feel implementation.
1711     * <p>
1712     * This is a <a HREF="http://java.sun.com/docs/books/tutorial/javabeans/whatis/beanDefinition.html">JavaBeans</a> bound property.
1713     *
1714     * @param selectionForeground the <code>Color</code> to use in the foreground
1715     * for selected list items
1716     * @see #getSelectionForeground
1717     * @see #setSelectionBackground
1718     * @see #setForeground
1719     * @see #setBackground
1720     * @see #setFont
1721     * @beaninfo
1722     * bound: true
1723     * description: A default foreground color for selected cells.
1724     */

1725    public void setSelectionForeground(Color selectionForeground) {
1726        Color old = this.selectionForeground;
1727        this.selectionForeground = selectionForeground;
1728        firePropertyChange("selectionForeground", old, selectionForeground);
1729        if ( !selectionForeground.equals(old) )
1730        {
1731            repaint();
1732        }
1733    }
1734
1735    /**
1736     * Returns the background color for selected cells.
1737     *
1738     * @return the <code>Color</code> used for the background of selected list items
1739     * @see #setSelectionBackground
1740     * @see #setSelectionForeground
1741     */

1742    public Color getSelectionBackground() {
1743        return selectionBackground;
1744    }
1745
1746    /**
1747     * Sets the background color for selected cells. Cell renderers
1748     * can use this color to the fill selected cells.
1749     * <p>
1750     * The default value of this property is defined by the look
1751     * and feel implementation.
1752     * <p>
1753     * This is a <a HREF="http://java.sun.com/docs/books/tutorial/javabeans/whatis/beanDefinition.html">JavaBeans</a> bound property.
1754     *
1755     * @param selectionBackground the <code>Color</code> to use for the background
1756     * of selected cells
1757     * @see #getSelectionBackground
1758     * @see #setSelectionForeground
1759     * @see #setForeground
1760     * @see #setBackground
1761     * @see #setFont
1762     * @beaninfo
1763     * bound: true
1764     * description: A default background color for selected cells.
1765     */

1766    public void setSelectionBackground(Color selectionBackground) {
1767        Color old = this.selectionBackground;
1768        this.selectionBackground = selectionBackground;
1769        firePropertyChange("selectionBackground", old, selectionBackground);
1770        if ( !selectionBackground.equals(old) )
1771        {
1772            repaint();
1773        }
1774    }
1775
1776    /**
1777     * Returns the <code>TableColumn</code> object for the column in the table
1778     * whose identifier is equal to <code>identifier</code>, when compared using
1779     * <code>equals</code>.
1780     *
1781     * @return the <code>TableColumn</code> object that matches the identifier
1782     * @exception IllegalArgumentException if <code>identifier</code> is <code>null</code> or no <code>TableColumn</code> has this identifier
1783     *
1784     * @param identifier the identifier object
1785     */

1786    public TableColumn getColumn(Object JavaDoc identifier) {
1787        TableColumnModel cm = getColumnModel();
1788        int columnIndex = cm.getColumnIndex(identifier);
1789        return cm.getColumn(columnIndex);
1790    }
1791
1792//
1793
// Informally implement the TableModel interface.
1794
//
1795

1796    /**
1797     * Maps the index of the column in the view at
1798     * <code>viewColumnIndex</code> to the index of the column
1799     * in the table model. Returns the index of the corresponding
1800     * column in the model. If <code>viewColumnIndex</code>
1801     * is less than zero, returns <code>viewColumnIndex</code>.
1802     *
1803     * @param viewColumnIndex the index of the column in the view
1804     * @return the index of the corresponding column in the model
1805     *
1806     * @see #convertColumnIndexToView
1807     */

1808    public int convertColumnIndexToModel(int viewColumnIndex) {
1809        if (viewColumnIndex < 0) {
1810            return viewColumnIndex;
1811        }
1812        return getColumnModel().getColumn(viewColumnIndex).getModelIndex();
1813    }
1814
1815    /**
1816     * Maps the index of the column in the table model at
1817     * <code>modelColumnIndex</code> to the index of the column
1818     * in the view. Returns the index of the
1819     * corresponding column in the view; returns -1 if this column is not
1820     * being displayed. If <code>modelColumnIndex</code> is less than zero,
1821     * returns <code>modelColumnIndex</code>.
1822     *
1823     * @param modelColumnIndex the index of the column in the model
1824     * @return the index of the corresponding column in the view
1825     *
1826     * @see #convertColumnIndexToModel
1827     */

1828    public int convertColumnIndexToView(int modelColumnIndex) {
1829        if (modelColumnIndex < 0) {
1830            return modelColumnIndex;
1831        }
1832        TableColumnModel cm = getColumnModel();
1833        for (int column = 0; column < getColumnCount(); column++) {
1834            if (cm.getColumn(column).getModelIndex() == modelColumnIndex) {
1835                return column;
1836            }
1837        }
1838        return -1;
1839    }
1840
1841    /**
1842     * Returns the number of rows in this table's model.
1843     * @return the number of rows in this table's model
1844     *
1845     * @see #getColumnCount
1846     */

1847    public int getRowCount() {
1848        return getModel().getRowCount();
1849    }
1850
1851    /**
1852     * Returns the number of columns in the column model. Note that this may
1853     * be different from the number of columns in the table model.
1854     *
1855     * @return the number of columns in the table
1856     * @see #getRowCount
1857     * @see #removeColumn
1858     */

1859    public int getColumnCount() {
1860        return getColumnModel().getColumnCount();
1861    }
1862
1863    /**
1864     * Returns the name of the column appearing in the view at
1865     * column position <code>column</code>.
1866     *
1867     * @param column the column in the view being queried
1868     * @return the name of the column at position <code>column</code>
1869            in the view where the first column is column 0
1870     */

1871    public String JavaDoc getColumnName(int column) {
1872        return getModel().getColumnName(convertColumnIndexToModel(column));
1873    }
1874
1875    /**
1876     * Returns the type of the column appearing in the view at
1877     * column position <code>column</code>.
1878     *
1879     * @param column the column in the view being queried
1880     * @return the type of the column at position <code>column</code>
1881     * in the view where the first column is column 0
1882     */

1883    public Class JavaDoc<?> getColumnClass(int column) {
1884        return getModel().getColumnClass(convertColumnIndexToModel(column));
1885    }
1886
1887    /**
1888     * Returns the cell value at <code>row</code> and <code>column</code>.
1889     * <p>
1890     * <b>Note</b>: The column is specified in the table view's display
1891     * order, and not in the <code>TableModel</code>'s column
1892     * order. This is an important distinction because as the
1893     * user rearranges the columns in the table,
1894     * the column at a given index in the view will change.
1895     * Meanwhile the user's actions never affect the model's
1896     * column ordering.
1897     *
1898     * @param row the row whose value is to be queried
1899     * @param column the column whose value is to be queried
1900     * @return the Object at the specified cell
1901     */

1902    public Object JavaDoc getValueAt(int row, int column) {
1903        return getModel().getValueAt(row, convertColumnIndexToModel(column));
1904    }
1905
1906    /**
1907     * Sets the value for the cell in the table model at <code>row</code>
1908     * and <code>column</code>.
1909     * <p>
1910     * <b>Note</b>: The column is specified in the table view's display
1911     * order, and not in the <code>TableModel</code>'s column
1912     * order. This is an important distinction because as the
1913     * user rearranges the columns in the table,
1914     * the column at a given index in the view will change.
1915     * Meanwhile the user's actions never affect the model's
1916     * column ordering.
1917     *
1918     * <code>aValue</code> is the new value.
1919     *
1920     * @param aValue the new value
1921     * @param row the row of the cell to be changed
1922     * @param column the column of the cell to be changed
1923     * @see #getValueAt
1924     */

1925    public void setValueAt(Object JavaDoc aValue, int row, int column) {
1926        getModel().setValueAt(aValue, row, convertColumnIndexToModel(column));
1927    }
1928
1929    /**
1930     * Returns true if the cell at <code>row</code> and <code>column</code>
1931     * is editable. Otherwise, invoking <code>setValueAt</code> on the cell
1932     * will have no effect.
1933     * <p>
1934     * <b>Note</b>: The column is specified in the table view's display
1935     * order, and not in the <code>TableModel</code>'s column
1936     * order. This is an important distinction because as the
1937     * user rearranges the columns in the table,
1938     * the column at a given index in the view will change.
1939     * Meanwhile the user's actions never affect the model's
1940     * column ordering.
1941     *
1942     *
1943     * @param row the row whose value is to be queried
1944     * @param column the column whose value is to be queried
1945     * @return true if the cell is editable
1946     * @see #setValueAt
1947     */

1948    public boolean isCellEditable(int row, int column) {
1949        return getModel().isCellEditable(row, convertColumnIndexToModel(column));
1950    }
1951//
1952
// Adding and removing columns in the view
1953
//
1954

1955    /**
1956     * Appends <code>aColumn</code> to the end of the array of columns held by
1957     * this <code>JTable</code>'s column model.
1958     * If the column name of <code>aColumn</code> is <code>null</code>,
1959     * sets the column name of <code>aColumn</code> to the name
1960     * returned by <code>getModel().getColumnName()</code>.
1961     * <p>
1962     * To add a column to this <code>JTable</code> to display the
1963     * <code>modelColumn</code>'th column of data in the model with a
1964     * given <code>width</code>, <code>cellRenderer</code>,
1965     * and <code>cellEditor</code> you can use:
1966     * <pre>
1967     *
1968     * addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
1969     *
1970     * </pre>
1971     * [Any of the <code>TableColumn</code> constructors can be used
1972     * instead of this one.]
1973     * The model column number is stored inside the <code>TableColumn</code>
1974     * and is used during rendering and editing to locate the appropriates
1975     * data values in the model. The model column number does not change
1976     * when columns are reordered in the view.
1977     *
1978     * @param aColumn the <code>TableColumn</code> to be added
1979     * @see #removeColumn
1980     */

1981    public void addColumn(TableColumn aColumn) {
1982        if (aColumn.getHeaderValue() == null) {
1983        int modelColumn = aColumn.getModelIndex();
1984        String JavaDoc columnName = getModel().getColumnName(modelColumn);
1985            aColumn.setHeaderValue(columnName);
1986        }
1987        getColumnModel().addColumn(aColumn);
1988    }
1989
1990    /**
1991     * Removes <code>aColumn</code> from this <code>JTable</code>'s
1992     * array of columns. Note: this method does not remove the column
1993     * of data from the model; it just removes the <code>TableColumn</code>
1994     * that was responsible for displaying it.
1995     *
1996     * @param aColumn the <code>TableColumn</code> to be removed
1997     * @see #addColumn
1998     */

1999    public void removeColumn(TableColumn aColumn) {
2000        getColumnModel().removeColumn(aColumn);
2001    }
2002
2003    /**
2004     * Moves the column <code>column</code> to the position currently
2005     * occupied by the column <code>targetColumn</code> in the view.
2006     * The old column at <code>targetColumn</code> is
2007     * shifted left or right to make room.
2008     *
2009     * @param column the index of column to be moved
2010     * @param targetColumn the new index of the column
2011     */

2012    public void moveColumn(int column, int targetColumn) {
2013        getColumnModel().moveColumn(column, targetColumn);
2014    }
2015
2016//
2017
// Cover methods for various models and helper methods
2018
//
2019

2020    /**
2021     * Returns the index of the column that <code>point</code> lies in,
2022     * or -1 if the result is not in the range
2023     * [0, <code>getColumnCount()</code>-1].
2024     *
2025     * @param point the location of interest
2026     * @return the index of the column that <code>point</code> lies in,
2027     * or -1 if the result is not in the range
2028     * [0, <code>getColumnCount()</code>-1]
2029     * @see #rowAtPoint
2030     */

2031    public int columnAtPoint(Point point) {
2032        int x = point.x;
2033        if( !getComponentOrientation().isLeftToRight() ) {
2034            x = getWidth() - x;
2035        }
2036        return getColumnModel().getColumnIndexAtX(x);
2037    }
2038
2039    /**
2040     * Returns the index of the row that <code>point</code> lies in,
2041     * or -1 if the result is not in the range
2042     * [0, <code>getRowCount()</code>-1].
2043     *
2044     * @param point the location of interest
2045     * @return the index of the row that <code>point</code> lies in,
2046     * or -1 if the result is not in the range
2047     * [0, <code>getRowCount()</code>-1]
2048     * @see #columnAtPoint
2049     */

2050    public int rowAtPoint(Point point) {
2051        int y = point.y;
2052    int result = (rowModel == null) ? y/getRowHeight() : rowModel.getIndex(y);
2053        if (result < 0) {
2054            return -1;
2055        }
2056        else if (result >= getRowCount()) {
2057            return -1;
2058        }
2059        else {
2060            return result;
2061        }
2062    }
2063
2064    /**
2065     * Returns a rectangle for the cell that lies at the intersection of
2066     * <code>row</code> and <code>column</code>.
2067     * If <code>includeSpacing</code> is true then the value returned
2068     * has the full height and width of the row and column
2069     * specified. If it is false, the returned rectangle is inset by the
2070     * intercell spacing to return the true bounds of the rendering or
2071     * editing component as it will be set during rendering.
2072     * <p>
2073     * If the column index is valid but the row index is less
2074     * than zero the method returns a rectangle with the
2075     * <code>y</code> and <code>height</code> values set appropriately
2076     * and the <code>x</code> and <code>width</code> values both set
2077     * to zero. In general, when either the row or column indices indicate a
2078     * cell outside the appropriate range, the method returns a rectangle
2079     * depicting the closest edge of the closest cell that is within
2080     * the table's range. When both row and column indices are out
2081     * of range the returned rectangle covers the closest
2082     * point of the closest cell.
2083     * <p>
2084     * In all cases, calculations that use this method to calculate
2085     * results along one axis will not fail because of anomalies in
2086     * calculations along the other axis. When the cell is not valid
2087     * the <code>includeSpacing</code> parameter is ignored.
2088     *
2089     * @param row the row index where the desired cell
2090     * is located
2091     * @param column the column index where the desired cell
2092     * is located in the display; this is not
2093     * necessarily the same as the column index
2094     * in the data model for the table; the
2095     * {@link #convertColumnIndexToView(int)}
2096     * method may be used to convert a data
2097     * model column index to a display
2098     * column index
2099     * @param includeSpacing if false, return the true cell bounds -
2100     * computed by subtracting the intercell
2101     * spacing from the height and widths of
2102     * the column and row models
2103     *
2104     * @return the rectangle containing the cell at location
2105     * <code>row</code>,<code>column</code>
2106     */

2107    public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
2108        Rectangle r = new Rectangle();
2109    boolean valid = true;
2110    if (row < 0) {
2111        // y = height = 0;
2112
valid = false;
2113    }
2114    else if (row >= getRowCount()) {
2115        r.y = getHeight();
2116        valid = false;
2117    }
2118    else {
2119        r.height = getRowHeight(row);
2120        r.y = (rowModel == null) ? row * r.height : rowModel.getPosition(row);
2121    }
2122
2123    if (column < 0) {
2124        if( !getComponentOrientation().isLeftToRight() ) {
2125        r.x = getWidth();
2126        }
2127        // otherwise, x = width = 0;
2128
valid = false;
2129    }
2130    else if (column >= getColumnCount()) {
2131        if( getComponentOrientation().isLeftToRight() ) {
2132        r.x = getWidth();
2133        }
2134        // otherwise, x = width = 0;
2135
valid = false;
2136    }
2137    else {
2138            TableColumnModel cm = getColumnModel();
2139            if( getComponentOrientation().isLeftToRight() ) {
2140                for(int i = 0; i < column; i++) {
2141                    r.x += cm.getColumn(i).getWidth();
2142                }
2143            } else {
2144                for(int i = cm.getColumnCount()-1; i > column; i--) {
2145                    r.x += cm.getColumn(i).getWidth();
2146                }
2147            }
2148            r.width = cm.getColumn(column).getWidth();
2149    }
2150
2151        if (valid && !includeSpacing) {
2152            int rm = getRowMargin();
2153            int cm = getColumnModel().getColumnMargin();
2154            // This is not the same as grow(), it rounds differently.
2155
r.setBounds(r.x + cm/2, r.y + rm/2, r.width - cm, r.height - rm);
2156        }
2157        return r;
2158    }
2159
2160    private int viewIndexForColumn(TableColumn aColumn) {
2161    TableColumnModel cm = getColumnModel();
2162    for (int column = 0; column < cm.getColumnCount(); column++) {
2163        if (cm.getColumn(column) == aColumn) {
2164        return column;
2165        }
2166    }
2167    return -1;
2168    }
2169
2170    /**
2171     * Causes this table to lay out its rows and columns. Overridden so
2172     * that columns can be resized to accomodate a change in the size of
2173     * a containing parent.
2174     * Resizes one or more of the columns in the table
2175     * so that the total width of all of this <code>JTable</code>'s
2176     * columns is equal to the width of the table.
2177     * <p>
2178     * Before the layout begins the method gets the
2179     * <code>resizingColumn</code> of the <code>tableHeader</code>.
2180     * When the method is called as a result of the resizing of an enclosing window,
2181     * the <code>resizingColumn</code> is <code>null</code>. This means that resizing
2182     * has taken place "outside" the <code>JTable</code> and the change -
2183     * or "delta" - should be distributed to all of the columns regardless
2184     * of this <code>JTable</code>'s automatic resize mode.
2185     * <p>
2186     * If the <code>resizingColumn</code> is not <code>null</code>, it is one of
2187     * the columns in the table that has changed size rather than
2188     * the table itself. In this case the auto-resize modes govern
2189     * the way the extra (or deficit) space is distributed
2190     * amongst the available columns.
2191     * <p>
2192     * The modes are:
2193     * <ul>
2194     * <li> AUTO_RESIZE_OFF: Don't automatically adjust the column's
2195     * widths at all. Use a horizontal scrollbar to accomodate the
2196     * columns when their sum exceeds the width of the
2197     * <code>Viewport</code>. If the <code>JTable</code> is not
2198     * enclosed in a <code>JScrollPane</code> this may
2199     * leave parts of the table invisible.
2200     * <li> AUTO_RESIZE_NEXT_COLUMN: Use just the column after the
2201     * resizing column. This results in the "boundary" or divider
2202     * between adjacent cells being independently adjustable.
2203     * <li> AUTO_RESIZE_SUBSEQUENT_COLUMNS: Use all columns after the
2204     * one being adjusted to absorb the changes. This is the
2205     * default behavior.
2206     * <li> AUTO_RESIZE_LAST_COLUMN: Automatically adjust the
2207     * size of the last column only. If the bounds of the last column
2208     * prevent the desired size from being allocated, set the
2209     * width of the last column to the appropriate limit and make
2210     * no further adjustments.
2211     * <li> AUTO_RESIZE_ALL_COLUMNS: Spread the delta amongst all the columns
2212     * in the <code>JTable</code>, including the one that is being
2213     * adjusted.
2214     * </ul>
2215     * <p>
2216     * <bold>Note:</bold> When a <code>JTable</code> makes adjustments
2217     * to the widths of the columns it respects their minimum and
2218     * maximum values absolutely. It is therefore possible that,
2219     * even after this method is called, the total width of the columns
2220     * is still not equal to the width of the table. When this happens
2221     * the <code>JTable</code> does not put itself
2222     * in AUTO_RESIZE_OFF mode to bring up a scroll bar, or break other
2223     * commitments of its current auto-resize mode -- instead it
2224     * allows its bounds to be set larger (or smaller) than the total of the
2225     * column minimum or maximum, meaning, either that there
2226     * will not be enough room to display all of the columns, or that the
2227     * columns will not fill the <code>JTable</code>'s bounds.
2228     * These respectively, result in the clipping of some columns
2229     * or an area being painted in the <code>JTable</code>'s
2230     * background color during painting.
2231     * <p>
2232     * The mechanism for distributing the delta amongst the available
2233     * columns is provided in a private method in the <code>JTable</code>
2234     * class:
2235     * <pre>
2236     * adjustSizes(long targetSize, final Resizable3 r, boolean inverse)
2237     * </pre>
2238     * an explanation of which is provided in the following section.
2239     * <code>Resizable3</code> is a private
2240     * interface that allows any data structure containing a collection
2241     * of elements with a size, preferred size, maximum size and minimum size
2242     * to have its elements manipulated by the algorithm.
2243     * <p>
2244     * <H3> Distributing the delta </H3>
2245     * <p>
2246     * <H4> Overview </H4>
2247     * <P>
2248     * Call "DELTA" the difference between the target size and the
2249     * sum of the preferred sizes of the elements in r. The individual
2250     * sizes are calculated by taking the original preferred
2251     * sizes and adding a share of the DELTA - that share being based on
2252     * how far each preferred size is from its limiting bound (minimum or
2253     * maximum).
2254     * <p>
2255     * <H4>Definition</H4>
2256     * <P>
2257     * Call the individual constraints min[i], max[i], and pref[i].
2258     * <p>
2259     * Call their respective sums: MIN, MAX, and PREF.
2260     * <p>
2261     * Each new size will be calculated using:
2262     * <p>
2263     * <pre>
2264     * size[i] = pref[i] + delta[i]
2265     * </pre>
2266     * where each individual delta[i] is calculated according to:
2267     * <p>
2268     * If (DELTA < 0) we are in shrink mode where:
2269     * <p>
2270     * <PRE>
2271     * DELTA
2272     * delta[i] = ------------ * (pref[i] - min[i])
2273     * (PREF - MIN)
2274     * </PRE>
2275     * If (DELTA > 0) we are in expand mode where:
2276     * <p>
2277     * <PRE>
2278     * DELTA
2279     * delta[i] = ------------ * (max[i] - pref[i])
2280     * (MAX - PREF)
2281     * </PRE>
2282     * <P>
2283     * The overall effect is that the total size moves that same percentage,
2284     * k, towards the total minimum or maximum and that percentage guarantees
2285     * accomodation of the required space, DELTA.
2286     *
2287     * <H4>Details</H4>
2288     * <P>
2289     * Naive evaluation of the formulae presented here would be subject to
2290     * the aggregated rounding errors caused by doing this operation in finite
2291     * precision (using ints). To deal with this, the multiplying factor above,
2292     * is constantly recalculated and this takes account of the rounding
2293     * errors in the previous iterations. The result is an algorithm that
2294     * produces a set of integers whose values exactly sum to the supplied
2295     * <code>targetSize</code>, and does so by spreading the rounding
2296     * errors evenly over the given elements.
2297     *
2298     * <H4>When the MAX and MIN bounds are hit</H4>
2299     * <P>
2300     * When <code>targetSize</code> is outside the [MIN, MAX] range,
2301     * the algorithm sets all sizes to their appropriate limiting value
2302     * (maximum or minimum).
2303     *
2304     */

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

2315            // A column has been resized and JTable may need to distribute
2316
// any overall delta to other columns, according to the resize mode.
2317
int columnIndex = viewIndexForColumn(resizingColumn);
2318        int delta = getWidth() - getColumnModel().getTotalColumnWidth();
2319        accommodateDelta(columnIndex, delta);
2320        delta = getWidth() - getColumnModel().getTotalColumnWidth();
2321            
2322            // If the delta cannot be completely accomodated, then the
2323
// resizing column will have to take any remainder. This means
2324
// that the column is not being allowed to take the requested
2325
// width. This happens under many circumstances: For example,
2326
// AUTO_RESIZE_NEXT_COLUMN specifies that any delta be distributed
2327
// to the column after the resizing column. If one were to attempt
2328
// to resize the last column of the table, there would be no
2329
// columns after it, and hence nowhere to distribute the delta.
2330
// It would then be given entirely back to the resizing column,
2331
// preventing it from changing size.
2332
if (delta != 0) {
2333        resizingColumn.setWidth(resizingColumn.getWidth() + delta);
2334        }
2335
2336            // At this point the JTable has to work out what preferred sizes
2337
// would have resulted in the layout the user has chosen.
2338
// Thereafter, during window resizing etc. it has to work off
2339
// the preferred sizes as usual - the idea being that, whatever
2340
// the user does, everything stays in synch and things don't jump
2341
// around.
2342
setWidthsFromPreferredWidths(true);
2343    }
2344
2345    super.doLayout();
2346    }
2347
2348    private TableColumn getResizingColumn() {
2349    return (tableHeader == null) ? null
2350                                 : tableHeader.getResizingColumn();
2351    }
2352
2353    /**
2354     * Sizes the table columns to fit the available space.
2355     * @deprecated As of Swing version 1.0.3,
2356     * replaced by <code>doLayout()</code>.
2357     * @see #doLayout
2358     */

2359    @Deprecated JavaDoc
2360    public void sizeColumnsToFit(boolean lastColumnOnly) {
2361        int oldAutoResizeMode = autoResizeMode;
2362        setAutoResizeMode(lastColumnOnly ? AUTO_RESIZE_LAST_COLUMN
2363                                         : AUTO_RESIZE_ALL_COLUMNS);
2364        sizeColumnsToFit(-1);
2365        setAutoResizeMode(oldAutoResizeMode);
2366    }
2367
2368    /**
2369     * Obsolete as of Java 2 platform v1.4. Please use the
2370     * <code>doLayout()</code> method instead.
2371     * @param resizingColumn the column whose resizing made this adjustment
2372     * necessary or -1 if there is no such column
2373     * @see #doLayout
2374     */

2375    public void sizeColumnsToFit(int resizingColumn) {
2376        if (resizingColumn == -1) {
2377            setWidthsFromPreferredWidths(false);
2378    }
2379    else {
2380        if (autoResizeMode == AUTO_RESIZE_OFF) {
2381                TableColumn aColumn = getColumnModel().getColumn(resizingColumn);
2382                aColumn.setPreferredWidth(aColumn.getWidth());
2383        }
2384        else {
2385                int delta = getWidth() - getColumnModel().getTotalColumnWidth();
2386            accommodateDelta(resizingColumn, delta);
2387                setWidthsFromPreferredWidths(true);
2388        }
2389    }
2390    }
2391
2392    private void setWidthsFromPreferredWidths(final boolean inverse) {
2393        int totalWidth = getWidth();
2394    int totalPreferred = getPreferredSize().width;
2395    int target = !inverse ? totalWidth : totalPreferred;
2396
2397    final TableColumnModel cm = columnModel;
2398    Resizable3 r = new Resizable3() {
2399        public int getElementCount() { return cm.getColumnCount(); }
2400        public int getLowerBoundAt(int i) { return cm.getColumn(i).getMinWidth(); }
2401        public int getUpperBoundAt(int i) { return cm.getColumn(i).getMaxWidth(); }
2402        public int getMidPointAt(int i) {
2403            if (!inverse) {
2404            return cm.getColumn(i).getPreferredWidth();
2405            }
2406            else {
2407            return cm.getColumn(i).getWidth();
2408            }
2409        }
2410        public void setSizeAt(int s, int i) {
2411            if (!inverse) {
2412            cm.getColumn(i).setWidth(s);
2413            }
2414            else {
2415            cm.getColumn(i).setPreferredWidth(s);
2416            }
2417        }
2418    };
2419
2420    adjustSizes(target, r, inverse);
2421    }
2422
2423
2424    // Distribute delta over columns, as indicated by the autoresize mode.
2425
private void accommodateDelta(int resizingColumnIndex, int delta) {
2426        int columnCount = getColumnCount();
2427        int from = resizingColumnIndex;
2428        int to = columnCount;
2429
2430    // Use the mode to determine how to absorb the changes.
2431
switch(autoResizeMode) {
2432        case AUTO_RESIZE_NEXT_COLUMN:
2433        from = from + 1;
2434        to = Math.min(from + 1, columnCount); break;
2435        case AUTO_RESIZE_SUBSEQUENT_COLUMNS:
2436        from = from + 1;
2437        to = columnCount; break;
2438        case AUTO_RESIZE_LAST_COLUMN:
2439        from = columnCount - 1;
2440        to = from + 1; break;
2441        case AUTO_RESIZE_ALL_COLUMNS:
2442        from = 0;
2443        to = columnCount; break;
2444        default:
2445        return;
2446    }
2447
2448    final int start = from;
2449    final int end = to;
2450    final TableColumnModel cm = columnModel;
2451    Resizable3 r = new Resizable3() {
2452        public int getElementCount() { return end-start; }
2453        public int getLowerBoundAt(int i) { return cm.getColumn(i+start).getMinWidth(); }
2454        public int getUpperBoundAt(int i) { return cm.getColumn(i+start).getMaxWidth(); }
2455        public int getMidPointAt(int i) { return cm.getColumn(i+start).getWidth(); }
2456        public void setSizeAt(int s, int i) { cm.getColumn(i+start).setWidth(s); }
2457    };
2458
2459    int totalWidth = 0;
2460        for(int i = from; i < to; i++) {
2461            TableColumn aColumn = columnModel.getColumn(i);
2462            int input = aColumn.getWidth();
2463        totalWidth = totalWidth + input;
2464        }
2465
2466        adjustSizes(totalWidth + delta, r, false);
2467
2468    return;
2469    }
2470
2471    private interface Resizable2 {
2472        public int getElementCount();
2473        public int getLowerBoundAt(int i);
2474        public int getUpperBoundAt(int i);
2475        public void setSizeAt(int newSize, int i);
2476    }
2477
2478    private interface Resizable3 extends Resizable2 {
2479        public int getMidPointAt(int i);
2480    }
2481
2482
2483    private void adjustSizes(long target, final Resizable3 r, boolean inverse) {
2484    int N = r.getElementCount();
2485    long totalPreferred = 0;
2486    for(int i = 0; i < N; i++) {
2487        totalPreferred += r.getMidPointAt(i);
2488    }
2489    Resizable2 s;
2490        if ((target < totalPreferred) == !inverse) {
2491        s = new Resizable2() {
2492            public int getElementCount() { return r.getElementCount(); }
2493            public int getLowerBoundAt(int i) { return r.getLowerBoundAt(i); }
2494            public int getUpperBoundAt(int i) { return r.getMidPointAt(i); }
2495            public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
2496
2497        };
2498    }
2499    else {
2500        s = new Resizable2() {
2501            public int getElementCount() { return r.getElementCount(); }
2502            public int getLowerBoundAt(int i) { return r.getMidPointAt(i); }
2503            public int getUpperBoundAt(int i) { return r.getUpperBoundAt(i); }
2504            public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
2505
2506        };
2507    }
2508    adjustSizes(target, s, !inverse);
2509    }
2510
2511    private void adjustSizes(long target, Resizable2 r, boolean limitToRange) {
2512    long totalLowerBound = 0;
2513    long totalUpperBound = 0;
2514    for(int i = 0; i < r.getElementCount(); i++) {
2515        totalLowerBound += r.getLowerBoundAt(i);
2516        totalUpperBound += r.getUpperBoundAt(i);
2517    }
2518
2519    if (limitToRange) {
2520        target = Math.min(Math.max(totalLowerBound, target), totalUpperBound);
2521    }
2522
2523    for(int i = 0; i < r.getElementCount(); i++) {
2524        int lowerBound = r.getLowerBoundAt(i);
2525        int upperBound = r.getUpperBoundAt(i);
2526        // Check for zero. This happens when the distribution of the delta
2527
// finishes early due to a series of "fixed" entries at the end.
2528
// In this case, lowerBound == upperBound, for all subsequent terms.
2529
int newSize;
2530        if (totalLowerBound == totalUpperBound) {
2531            newSize = lowerBound;
2532        }
2533        else {
2534            double f = (double)(target - totalLowerBound)/(totalUpperBound - totalLowerBound);
2535        newSize = (int)Math.round(lowerBound+f*(upperBound - lowerBound));
2536        // We'd need to round manually in an all integer version.
2537
// size[i] = (int)(((totalUpperBound - target) * lowerBound +
2538
// (target - totalLowerBound) * upperBound)/(totalUpperBound-totalLowerBound));
2539
}
2540        r.setSizeAt(newSize, i);
2541        target -= newSize;
2542        totalLowerBound -= lowerBound;
2543        totalUpperBound -= upperBound;
2544    }
2545    }
2546
2547    /**
2548     * Overrides <code>JComponent</code>'s <code>getToolTipText</code>
2549     * method in order to allow the renderer's tips to be used
2550     * if it has text set.
2551     * <p>
2552     * <bold>Note:</bold> For <code>JTable</code> to properly display
2553     * tooltips of its renderers
2554     * <code>JTable</code> must be a registered component with the
2555     * <code>ToolTipManager</code>.
2556     * This is done automatically in <code>initializeLocalVars</code>,
2557     * but if at a later point <code>JTable</code> is told
2558     * <code>setToolTipText(null)</code> it will unregister the table
2559     * component, and no tips from renderers will display anymore.
2560     *
2561     * @see JComponent#getToolTipText
2562     */

2563    public String JavaDoc getToolTipText(MouseEvent event) {
2564        String JavaDoc tip = null;
2565        Point p = event.getPoint();
2566
2567        // Locate the renderer under the event location
2568
int hitColumnIndex = columnAtPoint(p);
2569        int hitRowIndex = rowAtPoint(p);
2570
2571        if ((hitColumnIndex != -1) && (hitRowIndex != -1)) {
2572            TableCellRenderer renderer = getCellRenderer(hitRowIndex, hitColumnIndex);
2573            Component component = prepareRenderer(renderer, hitRowIndex, hitColumnIndex);
2574
2575            // Now have to see if the component is a JComponent before
2576
// getting the tip
2577
if (component instanceof JComponent JavaDoc) {
2578                // Convert the event to the renderer's coordinate system
2579
Rectangle cellRect = getCellRect(hitRowIndex, hitColumnIndex, false);
2580                p.translate(-cellRect.x, -cellRect.y);
2581                MouseEvent newEvent = new MouseEvent(component, event.getID(),
2582                                          event.getWhen(), event.getModifiers(),
2583                                          p.x, p.y, event.getClickCount(),
2584                                          event.isPopupTrigger());
2585
2586                tip = ((JComponent JavaDoc)component).getToolTipText(newEvent);
2587            }
2588        }
2589
2590        // No tip from the renderer get our own tip
2591
if (tip == null)
2592            tip = getToolTipText();
2593
2594        return tip;
2595    }
2596
2597//
2598
// Editing Support
2599
//
2600

2601    /**
2602     * Sets whether editors in this JTable get the keyboard focus
2603     * when an editor is activated as a result of the JTable
2604     * forwarding keyboard events for a cell.
2605     * By default, this property is false, and the JTable
2606     * retains the focus unless the cell is clicked.
2607     *
2608     * @param surrendersFocusOnKeystroke true if the editor should get the focus
2609     * when keystrokes cause the editor to be
2610     * activated
2611     *
2612     *
2613     * @see #getSurrendersFocusOnKeystroke
2614     */

2615    public void setSurrendersFocusOnKeystroke(boolean surrendersFocusOnKeystroke) {
2616        this.surrendersFocusOnKeystroke = surrendersFocusOnKeystroke;
2617    }
2618
2619    /**
2620     * Returns true if the editor should get the focus
2621     * when keystrokes cause the editor to be activated
2622     *
2623     * @return true if the editor should get the focus
2624     * when keystrokes cause the editor to be
2625     * activated
2626     *
2627     * @see #setSurrendersFocusOnKeystroke
2628     */

2629    public boolean getSurrendersFocusOnKeystroke() {
2630        return surrendersFocusOnKeystroke;
2631    }
2632
2633    /**
2634     * Programmatically starts editing the cell at <code>row</code> and
2635     * <code>column</code>, if those indices are in the valid range, and
2636     * the cell at those indices is editable.
2637     * Note that this is a convenience method for
2638     * <code>editCellAt(int, int, null)</code>.
2639     *
2640     * @param row the row to be edited
2641     * @param column the column to be edited
2642     * @return false if for any reason the cell cannot be edited,
2643     * or if the indices are invalid
2644     */

2645    public boolean editCellAt(int row, int column) {
2646        return editCellAt(row, column, null);
2647    }
2648
2649    /**
2650     * Programmatically starts editing the cell at <code>row</code> and
2651     * <code>column</code>, if those indices are in the valid range, and
2652     * the cell at those indices is editable.
2653     * To prevent the <code>JTable</code> from
2654     * editing a particular table, column or cell value, return false from
2655     * the <code>isCellEditable</code> method in the <code>TableModel</code>
2656     * interface.
2657     *
2658     * @param row the row to be edited
2659     * @param column the column to be edited
2660     * @param e event to pass into <code>shouldSelectCell</code>;
2661     * note that as of Java 2 platform v1.2, the call to
2662     * <code>shouldSelectCell</code> is no longer made
2663     * @return false if for any reason the cell cannot be edited,
2664     * or if the indices are invalid
2665     */

2666    public boolean editCellAt(int row, int column, EventObject e){
2667        if (cellEditor != null && !cellEditor.stopCellEditing()) {
2668            return false;
2669        }
2670
2671    if (row < 0 || row >= getRowCount() ||
2672        column < 0 || column >= getColumnCount()) {
2673        return false;
2674    }
2675
2676        if (!isCellEditable(row, column))
2677            return false;
2678
2679        if (editorRemover == null) {
2680            KeyboardFocusManager fm =
2681                KeyboardFocusManager.getCurrentKeyboardFocusManager();
2682            editorRemover = new CellEditorRemover(fm);
2683            fm.addPropertyChangeListener("permanentFocusOwner", editorRemover);
2684        }
2685
2686        TableCellEditor editor = getCellEditor(row, column);
2687        if (editor != null && editor.isCellEditable(e)) {
2688        editorComp = prepareEditor(editor, row, column);
2689        if (editorComp == null) {
2690        removeEditor();
2691        return false;
2692        }
2693        editorComp.setBounds(getCellRect(row, column, false));
2694        add(editorComp);
2695        editorComp.validate();
2696
2697        setCellEditor(editor);
2698        setEditingRow(row);
2699        setEditingColumn(column);
2700        editor.addCellEditorListener(this);
2701
2702        return true;
2703        }
2704        return false;
2705    }
2706
2707    /**
2708     * Returns true if a cell is being edited.
2709     *
2710     * @return true if the table is editing a cell
2711     * @see #editingColumn
2712     * @see #editingRow
2713     */

2714    public boolean isEditing() {
2715        return (cellEditor == null)? false : true;
2716    }
2717
2718    /**
2719     * Returns the component that is handling the editing session.
2720     * If nothing is being edited, returns null.
2721     *
2722     * @return Component handling editing session
2723     */

2724    public Component getEditorComponent() {
2725        return editorComp;
2726    }
2727
2728    /**
2729     * Returns the index of the column that contains the cell currently
2730     * being edited. If nothing is being edited, returns -1.
2731     *
2732     * @return the index of the column that contains the cell currently
2733     * being edited; returns -1 if nothing being edited
2734     * @see #editingRow
2735     */

2736    public int getEditingColumn() {
2737        return editingColumn;
2738    }
2739
2740    /**
2741     * Returns the index of the row that contains the cell currently
2742     * being edited. If nothing is being edited, returns -1.
2743     *
2744     * @return the index of the row that contains the cell currently
2745     * being edited; returns -1 if nothing being edited
2746     * @see #editingColumn
2747     */

2748    public int getEditingRow() {
2749        return editingRow;
2750    }
2751
2752//
2753
// Managing TableUI
2754
//
2755

2756    /**
2757     * Returns the L&F object that renders this component.
2758     *
2759     * @return the <code>TableUI</code> object that renders this component
2760     */

2761    public TableUI getUI() {
2762        return (TableUI)ui;
2763    }
2764
2765    /**
2766     * Sets the L&F object that renders this component and repaints.
2767     *
2768     * @param ui the TableUI L&F object
2769     * @see UIDefaults#getUI
2770     * @beaninfo
2771     * bound: true
2772     * hidden: true
2773     * attribute: visualUpdate true
2774     * description: The UI object that implements the Component's LookAndFeel.
2775     */

2776    public void setUI(TableUI ui) {
2777        if (this.ui != ui) {
2778            super.setUI(ui);
2779            repaint();
2780        }
2781    }
2782
2783    private void updateSubComponentUI(Object JavaDoc componentShell) {
2784        if (componentShell == null) {
2785            return;
2786        }
2787        Component component = null;
2788        if (componentShell instanceof Component) {
2789            component = (Component)componentShell;
2790        }
2791        if (componentShell instanceof DefaultCellEditor JavaDoc) {
2792            component = ((DefaultCellEditor JavaDoc)componentShell).getComponent();
2793        }
2794
2795        if (component != null && component instanceof JComponent JavaDoc) {
2796            ((JComponent JavaDoc)component).updateUI();
2797        }
2798    }
2799
2800    /**
2801     * Notification from the <code>UIManager</code> that the L&F has changed.
2802     * Replaces the current UI object with the latest version from the
2803     * <code>UIManager</code>.
2804     *
2805     * @see JComponent#updateUI
2806     */

2807    public void updateUI() {
2808        // Update the UIs of the cell renderers, cell editors and header renderers.
2809
TableColumnModel cm = getColumnModel();
2810        for(int column = 0; column < cm.getColumnCount(); column++) {
2811            TableColumn aColumn = cm.getColumn(column);
2812        updateSubComponentUI(aColumn.getCellRenderer());
2813            updateSubComponentUI(aColumn.getCellEditor());
2814        updateSubComponentUI(aColumn.getHeaderRenderer());
2815        }
2816
2817        // Update the UIs of all the default renderers.
2818
Enumeration defaultRenderers = defaultRenderersByColumnClass.elements();
2819        while (defaultRenderers.hasMoreElements()) {
2820            updateSubComponentUI(defaultRenderers.nextElement());
2821        }
2822
2823        // Update the UIs of all the default editors.
2824
Enumeration defaultEditors = defaultEditorsByColumnClass.elements();
2825        while (defaultEditors.hasMoreElements()) {
2826            updateSubComponentUI(defaultEditors.nextElement());
2827        }
2828
2829        // Update the UI of the table header
2830
if (tableHeader != null && tableHeader.getParent() == null) {
2831            tableHeader.updateUI();
2832        }
2833        
2834        setUI((TableUI)UIManager.getUI(this));
2835        resizeAndRepaint();
2836    }
2837
2838    /**
2839     * Returns the suffix used to construct the name of the L&F class used to
2840     * render this component.
2841     *
2842     * @return the string "TableUI"
2843     * @see JComponent#getUIClassID
2844     * @see UIDefaults#getUI
2845     */

2846    public String JavaDoc getUIClassID() {
2847        return uiClassID;
2848    }
2849
2850
2851//
2852
// Managing models
2853
//
2854

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

2866    public void setModel(TableModel dataModel) {
2867        if (dataModel == null) {
2868            throw new IllegalArgumentException JavaDoc("Cannot set a null TableModel");
2869    }
2870        if (this.dataModel != dataModel) {
2871        TableModel old = this.dataModel;
2872            if (old != null) {
2873                old.removeTableModelListener(this);
2874        }
2875            this.dataModel = dataModel;
2876            dataModel.addTableModelListener(this);
2877
2878            tableChanged(new TableModelEvent(dataModel, TableModelEvent.HEADER_ROW));
2879
2880        firePropertyChange("model", old, dataModel);
2881        }
2882    }
2883
2884    /**
2885     * Returns the <code>TableModel</code> that provides the data displayed by this
2886     * <code>JTable</code>.
2887     *
2888     * @return the <code>TableModel</code> that provides the data displayed by this <code>JTable</code>
2889     * @see #setModel
2890     */

2891    public TableModel getModel() {
2892        return dataModel;
2893    }
2894
2895    /**
2896     * Sets the column model for this table to <code>newModel</code> and registers
2897     * for listener notifications from the new column model. Also sets
2898     * the column model of the <code>JTableHeader</code> to <code>columnModel</code>.
2899     *
2900     * @param columnModel the new data source for this table
2901     * @exception IllegalArgumentException if <code>columnModel</code> is <code>null</code>
2902     * @see #getColumnModel
2903     * @beaninfo
2904     * bound: true
2905     * description: The object governing the way columns appear in the view.
2906     */

2907    public void setColumnModel(TableColumnModel columnModel) {
2908        if (columnModel == null) {
2909            throw new IllegalArgumentException JavaDoc("Cannot set a null ColumnModel");
2910        }
2911        TableColumnModel old = this.columnModel;
2912        if (columnModel != old) {
2913            if (old != null) {
2914                old.removeColumnModelListener(this);
2915        }
2916            this.columnModel = columnModel;
2917            columnModel.addColumnModelListener(this);
2918
2919            // Set the column model of the header as well.
2920
if (tableHeader != null) {
2921                tableHeader.setColumnModel(columnModel);
2922            }
2923
2924        firePropertyChange("columnModel", old, columnModel);
2925            resizeAndRepaint();
2926        }
2927    }
2928
2929    /**
2930     * Returns the <code>TableColumnModel</code> that contains all column information
2931     * of this table.
2932     *
2933     * @return the object that provides the column state of the table
2934     * @see #setColumnModel
2935     */

2936    public TableColumnModel getColumnModel() {
2937        return columnModel;
2938    }
2939
2940    /**
2941     * Sets the row selection model for this table to <code>newModel</code>
2942     * and registers for listener notifications from the new selection model.
2943     *
2944     * @param newModel the new selection model
2945     * @exception IllegalArgumentException if <code>newModel</code> is <code>null</code>
2946     * @see #getSelectionModel
2947     * @beaninfo
2948     * bound: true
2949     * description: The selection model for rows.
2950     */

2951    public void setSelectionModel(ListSelectionModel JavaDoc newModel) {
2952        if (newModel == null) {
2953            throw new IllegalArgumentException JavaDoc("Cannot set a null SelectionModel");
2954        }
2955
2956        ListSelectionModel JavaDoc oldModel = selectionModel;
2957
2958        if (newModel != oldModel) {
2959            if (oldModel != null) {
2960                oldModel.removeListSelectionListener(this);
2961            }
2962
2963            selectionModel = newModel;
2964            newModel.addListSelectionListener(this);
2965
2966        firePropertyChange("selectionModel", oldModel, newModel);
2967            repaint();
2968        }
2969    }
2970
2971    /**
2972     * Returns the <code>ListSelectionModel</code> that is used to maintain row
2973     * selection state.
2974     *
2975     * @return the object that provides row selection state, <code>null</code>
2976     * if row selection is not allowed
2977     * @see #setSelectionModel
2978     */

2979    public ListSelectionModel JavaDoc getSelectionModel() {
2980        return selectionModel;
2981    }
2982
2983//
2984
// Implementing TableModelListener interface
2985
//
2986

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

3000    public void tableChanged(TableModelEvent e) {
3001        if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
3002            // The whole thing changed
3003
clearSelectionAndLeadAnchor();
3004
3005            rowModel = null;
3006
3007            if (getAutoCreateColumnsFromModel()) {
3008        // This will effect invalidation of the JTable and JTableHeader.
3009
createDefaultColumnsFromModel();
3010        return;
3011        }
3012
3013        resizeAndRepaint();
3014            return;
3015        }
3016
3017    // The totalRowHeight calculated below will be incorrect if
3018
// there are variable height rows. Repaint the visible region,
3019
// but don't return as a revalidate may be necessary as well.
3020
if (rowModel != null) {
3021        repaint();
3022    }
3023
3024        if (e.getType() == TableModelEvent.INSERT) {
3025            tableRowsInserted(e);
3026            return;
3027        }
3028
3029        if (e.getType() == TableModelEvent.DELETE) {
3030            tableRowsDeleted(e);
3031            return;
3032        }
3033
3034        int modelColumn = e.getColumn();
3035        int start = e.getFirstRow();
3036        int end = e.getLastRow();
3037
3038        Rectangle dirtyRegion;
3039        if (modelColumn == TableModelEvent.ALL_COLUMNS) {
3040            // 1 or more rows changed
3041
dirtyRegion = new Rectangle(0, start * getRowHeight(),
3042                                        getColumnModel().getTotalColumnWidth(), 0);
3043        }
3044        else {
3045            // A cell or column of cells has changed.
3046
// Unlike the rest of the methods in the JTable, the TableModelEvent
3047
// uses the coordinate system of the model instead of the view.
3048
// This is the only place in the JTable where this "reverse mapping"
3049
// is used.
3050
int column = convertColumnIndexToView(modelColumn);
3051            dirtyRegion = getCellRect(start, column, false);
3052        }
3053
3054        // Now adjust the height of the dirty region according to the value of "end".
3055
// Check for Integer.MAX_VALUE as this will cause an overflow.
3056
if (end != Integer.MAX_VALUE) {
3057        dirtyRegion.height = (end-start+1)*getRowHeight();
3058            repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
3059        }
3060        // In fact, if the end is Integer.MAX_VALUE we need to revalidate anyway
3061
// because the scrollbar may need repainting.
3062
else {
3063            clearSelectionAndLeadAnchor();
3064            resizeAndRepaint();
3065            rowModel = null;
3066        }
3067    }
3068
3069    /*
3070     * Invoked when rows have been inserted into the table.
3071     * <p>
3072     * Application code will not use these methods explicitly, they
3073     * are used internally by JTable.
3074     *
3075     * @param e the TableModelEvent encapsulating the insertion
3076     */

3077    private void tableRowsInserted(TableModelEvent e) {
3078        int start = e.getFirstRow();
3079        int end = e.getLastRow();
3080        if (start < 0) {
3081            start = 0;
3082    }
3083    if (end < 0) {
3084        end = getRowCount()-1;
3085    }
3086
3087        // Adjust the selection to account for the new rows.
3088
int length = end - start + 1;
3089    selectionModel.insertIndexInterval(start, length, true);
3090
3091    // If we have variable height rows, adjust the row model.
3092
if (rowModel != null) {
3093        rowModel.insertEntries(start, length, getRowHeight());
3094    }
3095        int rh = getRowHeight() ;
3096        Rectangle drawRect = new Rectangle(0, start * rh,
3097                                        getColumnModel().getTotalColumnWidth(),
3098                                           (getRowCount()-start) * rh);
3099
3100        revalidate();
3101        // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
3102
// repaint still required in the unusual case where there is no ScrollPane
3103
repaint(drawRect);
3104    }
3105
3106    /*
3107     * Invoked when rows have been removed from the table.
3108     * <p>
3109     * Application code will not use these methods explicitly, they
3110     * are used internally by JTable.
3111     *
3112     * @param e the TableModelEvent encapsulating the deletion
3113     */

3114    private void tableRowsDeleted(TableModelEvent e) {
3115        int start = e.getFirstRow();
3116        int end = e.getLastRow();
3117        if (start < 0) {
3118            start = 0;
3119    }
3120    if (end < 0) {
3121        end = getRowCount()-1;
3122    }
3123
3124        int deletedCount = end - start + 1;
3125        int previousRowCount = getRowCount() + deletedCount;
3126        // Adjust the selection to account for the new rows
3127
selectionModel.removeIndexInterval(start, end);
3128
3129    // If we have variable height rows, adjust the row model.
3130
if (rowModel != null) {
3131        rowModel.removeEntries(start, deletedCount);
3132    }
3133
3134        int rh = getRowHeight();
3135        Rectangle drawRect = new Rectangle(0, start * rh,
3136                                        getColumnModel().getTotalColumnWidth(),
3137                                        (previousRowCount - start) * rh);
3138
3139        revalidate();
3140        // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
3141
// repaint still required in the unusual case where there is no ScrollPane
3142
repaint(drawRect);
3143    }
3144
3145//
3146
// Implementing TableColumnModelListener interface
3147
//
3148

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

3157    public void columnAdded(TableColumnModelEvent e) {
3158        // If I'm currently editing, then I should stop editing
3159
if (isEditing()) {
3160            removeEditor();
3161        }
3162        resizeAndRepaint();
3163    }
3164
3165    /**
3166     * Invoked when a column is removed from the table column model.
3167     * <p>
3168     * Application code will not use these methods explicitly, they
3169     * are used internally by JTable.
3170     *
3171     * @see TableColumnModelListener
3172     */

3173    public void columnRemoved(TableColumnModelEvent e) {
3174        // If I'm currently editing, then I should stop editing
3175
if (isEditing()) {
3176            removeEditor();
3177        }
3178        resizeAndRepaint();
3179    }
3180
3181    /**
3182     * Invoked when a column is repositioned. If a cell is being
3183     * edited, then editing is stopped and the cell is redrawn.
3184     * <p>
3185     * Application code will not use these methods explicitly, they
3186     * are used internally by JTable.
3187     *
3188     * @param e the event received
3189     * @see TableColumnModelListener
3190     */

3191    public void columnMoved(TableColumnModelEvent e) {
3192        // If I'm currently editing, then I should stop editing
3193
if (isEditing()) {
3194            removeEditor();
3195        }
3196        repaint();
3197    }
3198
3199    /**
3200     * Invoked when a column is moved due to a margin change.
3201     * If a cell is being edited, then editing is stopped and the cell
3202     * is redrawn.
3203     * <p>
3204     * Application code will not use these methods explicitly, they
3205     * are used internally by JTable.
3206     *
3207     * @param e the event received
3208     * @see TableColumnModelListener
3209     */

3210    public void columnMarginChanged(ChangeEvent e) {
3211    if (isEditing()) {
3212            removeEditor();
3213        }
3214    TableColumn resizingColumn = getResizingColumn();
3215    // Need to do this here, before the parent's
3216
// layout manager calls getPreferredSize().
3217
if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF) {
3218        resizingColumn.setPreferredWidth(resizingColumn.getWidth());
3219    }
3220    resizeAndRepaint();
3221    }
3222
3223    private int limit(int i, int a, int b) {
3224    return Math.min(b, Math.max(i, a));
3225    }
3226
3227    /**
3228     * Invoked when the selection model of the <code>TableColumnModel</code>
3229     * is changed.
3230     * <p>
3231     * Application code will not use these methods explicitly, they
3232     * are used internally by JTable.
3233     *
3234     * @param e the event received
3235     * @see TableColumnModelListener
3236     */

3237    public void columnSelectionChanged(ListSelectionEvent e) {
3238        boolean isAdjusting = e.getValueIsAdjusting();
3239        if (columnSelectionAdjusting && !isAdjusting) {
3240            // The assumption is that when the model is no longer adjusting
3241
// we will have already gotten all the changes, and therefore
3242
// don't need to do an additional paint.
3243
columnSelectionAdjusting = false;
3244            return;
3245        }
3246        columnSelectionAdjusting = isAdjusting;
3247    // The getCellRect() call will fail unless there is at least one row.
3248
if (getRowCount() <= 0 || getColumnCount() <= 0) {
3249        return;
3250    }
3251        int firstIndex = limit(e.getFirstIndex(), 0, getColumnCount()-1);
3252        int lastIndex = limit(e.getLastIndex(), 0, getColumnCount()-1);
3253        int minRow = 0;
3254        int maxRow = getRowCount() - 1;
3255        if (getRowSelectionAllowed()) {
3256            minRow = selectionModel.getMinSelectionIndex();
3257            maxRow = selectionModel.getMaxSelectionIndex();
3258            int leadRow = getAdjustedIndex(selectionModel.getLeadSelectionIndex(), true);
3259
3260            if (minRow == -1 || maxRow == -1) {
3261                if (leadRow == -1) {
3262                    // nothing to repaint, return
3263
return;
3264                }
3265
3266                // only thing to repaint is the lead
3267
minRow = maxRow = leadRow;
3268            } else {
3269                // We need to consider more than just the range between
3270
// the min and max selected index. The lead row, which could
3271
// be outside this range, should be considered also.
3272
if (leadRow != -1) {
3273                    minRow = Math.min(minRow, leadRow);
3274                    maxRow = Math.max(maxRow, leadRow);
3275                }
3276            }
3277        }
3278        Rectangle firstColumnRect = getCellRect(minRow, firstIndex, false);
3279        Rectangle lastColumnRect = getCellRect(maxRow, lastIndex, false);
3280        Rectangle dirtyRegion = firstColumnRect.union(lastColumnRect);
3281        repaint(dirtyRegion);
3282    }
3283
3284//
3285
// Implementing ListSelectionListener interface
3286
//
3287

3288    /**
3289     * Invoked when the row selection changes -- repaints to show the new
3290     * selection.
3291     * <p>
3292     * Application code will not use these methods explicitly, they
3293     * are used internally by JTable.
3294     *
3295     * @param e the event received
3296     * @see ListSelectionListener
3297     */

3298    public void valueChanged(ListSelectionEvent e) {
3299        boolean isAdjusting = e.getValueIsAdjusting();
3300        if (rowSelectionAdjusting && !isAdjusting) {
3301            // The assumption is that when the model is no longer adjusting
3302
// we will have already gotten all the changes, and therefore
3303
// don't need to do an additional paint.
3304
rowSelectionAdjusting = false;
3305            return;
3306        }
3307        rowSelectionAdjusting = isAdjusting;
3308    // The getCellRect() calls will fail unless there is at least one column.
3309
if (getRowCount() <= 0 || getColumnCount() <= 0) {
3310        return;
3311    }
3312        int firstIndex = limit(e.getFirstIndex(), 0, getRowCount()-1);
3313        int lastIndex = limit(e.getLastIndex(), 0, getRowCount()-1);
3314        Rectangle firstRowRect = getCellRect(firstIndex, 0, false);
3315        Rectangle lastRowRect = getCellRect(lastIndex, getColumnCount()-1, false);
3316        Rectangle dirtyRegion = firstRowRect.union(lastRowRect);
3317        repaint(dirtyRegion);
3318    }
3319
3320//
3321
// Implementing the CellEditorListener interface
3322
//
3323

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

3334    public void editingStopped(ChangeEvent e) {
3335        // Take in the new value
3336
TableCellEditor editor = getCellEditor();
3337        if (editor != null) {
3338            Object JavaDoc value = editor.getCellEditorValue();
3339            setValueAt(value, editingRow, editingColumn);
3340            removeEditor();
3341        }
3342    }
3343
3344    /**
3345     * Invoked when editing is canceled. The editor object is discarded
3346     * and the cell is rendered once again.
3347     * <p>
3348     * Application code will not use these methods explicitly, they
3349     * are used internally by JTable.
3350     *
3351     * @param e the event received
3352     * @see CellEditorListener
3353     */

3354    public void editingCanceled(ChangeEvent e) {
3355        removeEditor();
3356    }
3357
3358//
3359
// Implementing the Scrollable interface
3360
//
3361

3362    /**
3363     * Sets the preferred size of the viewport for this table.
3364     *
3365     * @param size a <code>Dimension</code> object specifying the <code>preferredSize</code> of a
3366     * <code>JViewport</code> whose view is this table
3367     * @see Scrollable#getPreferredScrollableViewportSize
3368     * @beaninfo
3369     * description: The preferred size of the viewport.
3370     */

3371    public void setPreferredScrollableViewportSize(Dimension size) {
3372        preferredViewportSize = size;
3373    }
3374
3375    /**
3376     * Returns the preferred size of the viewport for this table.
3377     *
3378     * @return a <code>Dimension</code> object containing the <code>preferredSize</code> of the <code>JViewport</code>
3379     * which displays this table
3380     * @see Scrollable#getPreferredScrollableViewportSize
3381     */

3382    public Dimension getPreferredScrollableViewportSize() {
3383        return preferredViewportSize;
3384    }
3385
3386    /**
3387     * Returns the scroll increment (in pixels) that completely exposes one new
3388     * row or column (depending on the orientation).
3389     * <p>
3390     * This method is called each time the user requests a unit scroll.
3391     *
3392     * @param visibleRect the view area visible within the viewport
3393     * @param orientation either <code>SwingConstants.VERTICAL</code>
3394     * or <code>SwingConstants.HORIZONTAL</code>
3395     * @param direction less than zero to scroll up/left,
3396     * greater than zero for down/right
3397     * @return the "unit" increment for scrolling in the specified direction
3398     * @see Scrollable#getScrollableUnitIncrement
3399     */

3400    public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
3401                                          int direction) {
3402        // PENDING(alan): do something smarter
3403
if (orientation == SwingConstants.HORIZONTAL) {
3404            return 100;
3405        }
3406        return getRowHeight();
3407    }
3408
3409    /**
3410     * Returns <code>visibleRect.height</code> or
3411     * <code>visibleRect.width</code>,
3412     * depending on this table's orientation. Note that as of Swing 1.1.1
3413     * (Java 2 v 1.2.2) the value
3414     * returned will ensure that the viewport is cleanly aligned on
3415     * a row boundary.
3416     *
3417     * @return <code>visibleRect.height</code> or
3418     * <code>visibleRect.width</code>
3419     * per the orientation
3420     * @see Scrollable#getScrollableBlockIncrement
3421     */

3422    public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation,
3423                                           int direction) {
3424    if (orientation == SwingConstants.VERTICAL) {
3425        int rh = getRowHeight();
3426        return (rh > 0) ? Math.max(rh, (visibleRect.height / rh) * rh) : visibleRect.height;
3427    }
3428    else {
3429        return visibleRect.width;
3430    }
3431    }
3432
3433    /**
3434     * Returns false if <code>autoResizeMode</code> is set to
3435     * <code>AUTO_RESIZE_OFF</code>, which indicates that the
3436     * width of the viewport does not determine the width
3437     * of the table. Otherwise returns true.
3438     *
3439     * @return false if <code>autoResizeMode</code> is set
3440     * to <code>AUTO_RESIZE_OFF</code>, otherwise returns true
3441     * @see Scrollable#getScrollableTracksViewportWidth
3442     */

3443    public boolean getScrollableTracksViewportWidth() {
3444        return !(autoResizeMode == AUTO_RESIZE_OFF);
3445    }
3446
3447    /**
3448     * Returns false to indicate that the height of the viewport does not
3449     * determine the height of the table.
3450     *
3451     * @return false
3452     * @see Scrollable#getScrollableTracksViewportHeight
3453     */

3454    public boolean getScrollableTracksViewportHeight() {
3455        return false;
3456    }
3457
3458//
3459
// Protected Methods
3460
//
3461

3462    protected boolean processKeyBinding(KeyStroke JavaDoc ks, KeyEvent e,
3463                    int condition, boolean pressed) {
3464    boolean retValue = super.processKeyBinding(ks, e, condition, pressed);
3465
3466    // Start editing when a key is typed. UI classes can disable this behavior
3467
// by setting the client property JTable.autoStartsEdit to Boolean.FALSE.
3468
if (!retValue && condition == WHEN_ANCESTOR_OF_FOCUSED_COMPONENT &&
3469        isFocusOwner() &&
3470        !Boolean.FALSE.equals((Boolean JavaDoc)getClientProperty("JTable.autoStartsEdit"))) {
3471        // We do not have a binding for the event.
3472
Component editorComponent = getEditorComponent();
3473        if (editorComponent == null) {
3474        // Only attempt to install the editor on a KEY_PRESSED,
3475
if (e == null || e.getID() != KeyEvent.KEY_PRESSED) {
3476            return false;
3477        }
3478        // Don't start when just a modifier is pressed
3479
int code = e.getKeyCode();
3480        if (code == KeyEvent.VK_SHIFT || code == KeyEvent.VK_CONTROL ||
3481            code == KeyEvent.VK_ALT) {
3482            return false;
3483        }
3484        // Try to install the editor
3485
int leadRow = getSelectionModel().getLeadSelectionIndex();
3486        int leadColumn = getColumnModel().getSelectionModel().
3487                           getLeadSelectionIndex();
3488        if (leadRow != -1 && leadColumn != -1 && !isEditing()) {
3489            if (!editCellAt(leadRow, leadColumn)) {
3490            return false;
3491            }
3492        }
3493        editorComponent = getEditorComponent();
3494        if (editorComponent == null) {
3495            return false;
3496        }
3497        }
3498        // If the editorComponent is a JComponent, pass the event to it.
3499
if (editorComponent instanceof JComponent JavaDoc) {
3500        retValue = ((JComponent JavaDoc)editorComponent).processKeyBinding
3501                                (ks, e, WHEN_FOCUSED, pressed);
3502            // If we have started an editor as a result of the user
3503
// pressing a key and the surrendersFocusOnKeystroke property
3504
// is true, give the focus to the new editor.
3505
if (getSurrendersFocusOnKeystroke()) {
3506                    editorComponent.requestFocus();
3507                }
3508        }
3509    }
3510        return retValue;
3511    }
3512
3513    private void setLazyValue(Hashtable h, Class JavaDoc c, String JavaDoc s) {
3514    h.put(c, new UIDefaults.ProxyLazyValue JavaDoc(s));
3515    }
3516
3517    private void setLazyRenderer(Class JavaDoc c, String JavaDoc s) {
3518    setLazyValue(defaultRenderersByColumnClass, c, s);
3519    }
3520
3521    /**
3522     * Creates default cell renderers for objects, numbers, doubles, dates,
3523     * booleans, and icons.
3524     * @see javax.swing.table.DefaultTableCellRenderer
3525     *
3526     */

3527    protected void createDefaultRenderers() {
3528        defaultRenderersByColumnClass = new UIDefaults JavaDoc();
3529
3530        // Objects
3531
setLazyRenderer(Object JavaDoc.class, "javax.swing.table.DefaultTableCellRenderer$UIResource");
3532
3533    // Numbers
3534
setLazyRenderer(Number JavaDoc.class, "javax.swing.JTable$NumberRenderer");
3535
3536    // Doubles and Floats
3537
setLazyRenderer(Float JavaDoc.class, "javax.swing.JTable$DoubleRenderer");
3538        setLazyRenderer(Double JavaDoc.class, "javax.swing.JTable$DoubleRenderer");
3539
3540    // Dates
3541
setLazyRenderer(Date.class, "javax.swing.JTable$DateRenderer");
3542
3543        // Icons and ImageIcons
3544
setLazyRenderer(Icon JavaDoc.class, "javax.swing.JTable$IconRenderer");
3545        setLazyRenderer(ImageIcon JavaDoc.class, "javax.swing.JTable$IconRenderer");
3546
3547        // Booleans
3548
setLazyRenderer(Boolean JavaDoc.class, "javax.swing.JTable$BooleanRenderer");
3549    }
3550
3551    /**
3552     * Default Renderers
3553     **/

3554    static class NumberRenderer extends DefaultTableCellRenderer.UIResource {
3555    public NumberRenderer() {
3556        super();
3557        setHorizontalAlignment(JLabel.RIGHT);
3558    }
3559    }
3560
3561    static class DoubleRenderer extends NumberRenderer {
3562    NumberFormat JavaDoc formatter;
3563    public DoubleRenderer() { super(); }
3564
3565    public void setValue(Object JavaDoc value) {
3566        if (formatter == null) {
3567        formatter = NumberFormat.getInstance();
3568        }
3569        setText((value == null) ? "" : formatter.format(value));
3570    }
3571    }
3572
3573    static class DateRenderer extends DefaultTableCellRenderer.UIResource {
3574    DateFormat JavaDoc formatter;
3575    public DateRenderer() { super(); }
3576
3577    public void setValue(Object JavaDoc value) {
3578        if (formatter==null) {
3579        formatter = DateFormat.getDateInstance();
3580        }
3581        setText((value == null) ? "" : formatter.format(value));
3582    }
3583    }
3584
3585    static class IconRenderer extends DefaultTableCellRenderer.UIResource {
3586    public IconRenderer() {
3587        super();
3588        setHorizontalAlignment(JLabel.CENTER);
3589    }
3590    public void setValue(Object JavaDoc value) { setIcon((value instanceof Icon JavaDoc) ? (Icon JavaDoc)value : null); }
3591    }
3592
3593
3594    static class BooleanRenderer extends JCheckBox JavaDoc implements TableCellRenderer, UIResource
3595    {
3596        private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
3597
3598    public BooleanRenderer() {
3599        super();
3600        setHorizontalAlignment(JLabel.CENTER);
3601            setBorderPainted(true);
3602    }
3603
3604        public Component getTableCellRendererComponent(JTable JavaDoc table, Object JavaDoc value,
3605                               boolean isSelected, boolean hasFocus, int row, int column) {
3606        if (isSelected) {
3607            setForeground(table.getSelectionForeground());
3608            super.setBackground(table.getSelectionBackground());
3609        }
3610        else {
3611            setForeground(table.getForeground());
3612            setBackground(table.getBackground());
3613        }
3614            setSelected((value != null && ((Boolean JavaDoc)value).booleanValue()));
3615
3616            if (hasFocus) {
3617                setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
3618            } else {
3619                setBorder(noFocusBorder);
3620            }
3621
3622            return this;
3623        }
3624    }
3625
3626    private void setLazyEditor(Class JavaDoc c, String JavaDoc s) {
3627    setLazyValue(defaultEditorsByColumnClass, c, s);
3628    }
3629
3630    /**
3631     * Creates default cell editors for objects, numbers, and boolean values.
3632     * @see DefaultCellEditor
3633     */

3634    protected void createDefaultEditors() {
3635        defaultEditorsByColumnClass = new UIDefaults JavaDoc();
3636
3637        // Objects
3638
setLazyEditor(Object JavaDoc.class, "javax.swing.JTable$GenericEditor");
3639
3640        // Numbers
3641
setLazyEditor(Number JavaDoc.class, "javax.swing.JTable$NumberEditor");
3642
3643        // Booleans
3644
setLazyEditor(Boolean JavaDoc.class, "javax.swing.JTable$BooleanEditor");
3645    }
3646
3647    /**
3648     * Default Editors
3649     */

3650    static class GenericEditor extends DefaultCellEditor JavaDoc {
3651
3652    Class JavaDoc[] argTypes = new Class JavaDoc[]{String JavaDoc.class};
3653    java.lang.reflect.Constructor JavaDoc constructor;
3654    Object JavaDoc value;
3655
3656    public GenericEditor() {
3657            super(new JTextField JavaDoc());
3658            getComponent().setName("Table.editor");
3659        }
3660
3661    public boolean stopCellEditing() {
3662        String JavaDoc s = (String JavaDoc)super.getCellEditorValue();
3663        // Here we are dealing with the case where a user
3664
// has deleted the string value in a cell, possibly
3665
// after a failed validation. Return null, so that
3666
// they have the option to replace the value with
3667
// null or use escape to restore the original.
3668
// For Strings, return "" for backward compatibility.
3669
if ("".equals(s)) {
3670        if (constructor.getDeclaringClass() == String JavaDoc.class) {
3671            value = s;
3672        }
3673        super.stopCellEditing();
3674        }
3675
3676        try {
3677        value = constructor.newInstance(new Object JavaDoc[]{s});
3678        }
3679        catch (Exception JavaDoc e) {
3680        ((JComponent JavaDoc)getComponent()).setBorder(new LineBorder(Color.red));
3681        return false;
3682        }
3683        return super.stopCellEditing();
3684    }
3685
3686    public Component getTableCellEditorComponent(JTable JavaDoc table, Object JavaDoc value,
3687                         boolean isSelected,
3688                         int row, int column) {
3689        this.value = null;
3690            ((JComponent JavaDoc)getComponent()).setBorder(new LineBorder(Color.black));
3691        try {
3692        Class JavaDoc type = table.getColumnClass(column);
3693        // Since our obligation is to produce a value which is
3694
// assignable for the required type it is OK to use the
3695
// String constructor for columns which are declared
3696
// to contain Objects. A String is an Object.
3697
if (type == Object JavaDoc.class) {
3698            type = String JavaDoc.class;
3699        }
3700        constructor = type.getConstructor(argTypes);
3701        }
3702        catch (Exception JavaDoc e) {
3703        return null;
3704        }
3705        return super.getTableCellEditorComponent(table, value, isSelected, row, column);
3706    }
3707
3708    public Object JavaDoc getCellEditorValue() {
3709        return value;
3710    }
3711    }
3712
3713    static class NumberEditor extends GenericEditor {
3714
3715    public NumberEditor() {
3716        ((JTextField JavaDoc)getComponent()).setHorizontalAlignment(JTextField.RIGHT);
3717    }
3718    }
3719
3720    static class BooleanEditor extends DefaultCellEditor JavaDoc {
3721    public BooleanEditor() {
3722        super(new JCheckBox JavaDoc());
3723        JCheckBox JavaDoc checkBox = (JCheckBox JavaDoc)getComponent();
3724        checkBox.setHorizontalAlignment(JCheckBox.CENTER);
3725    }
3726    }
3727
3728    /**
3729     * Initializes table properties to their default values.
3730     */

3731    protected void initializeLocalVars() {
3732        setOpaque(true);
3733        createDefaultRenderers();
3734        createDefaultEditors();
3735
3736        setTableHeader(createDefaultTableHeader());
3737
3738        setShowGrid(true);
3739        setAutoResizeMode(AUTO_RESIZE_SUBSEQUENT_COLUMNS);
3740        setRowHeight(16);
3741        isRowHeightSet = false;
3742        setRowMargin(1);
3743        setRowSelectionAllowed(true);
3744        setCellEditor(null);
3745        setEditingColumn(-1);
3746    setEditingRow(-1);
3747        setSurrendersFocusOnKeystroke(false);
3748        setPreferredScrollableViewportSize(new Dimension(450, 400));
3749
3750        // I'm registered to do tool tips so we can draw tips for the renderers
3751
ToolTipManager JavaDoc toolTipManager = ToolTipManager.sharedInstance();
3752        toolTipManager.registerComponent(this);
3753
3754        setAutoscrolls(true);
3755    }
3756
3757    /**
3758     * Returns the default table model object, which is
3759     * a <code>DefaultTableModel</code>. A subclass can override this
3760     * method to return a different table model object.
3761     *
3762     * @return the default table model object
3763     * @see javax.swing.table.DefaultTableModel
3764     */

3765    protected TableModel createDefaultDataModel() {
3766        return new DefaultTableModel();
3767    }
3768
3769    /**
3770     * Returns the default column model object, which is
3771     * a <code>DefaultTableColumnModel</code>. A subclass can override this
3772     * method to return a different column model object.
3773     *
3774     * @return the default column model object
3775     * @see javax.swing.table.DefaultTableColumnModel
3776     */

3777    protected TableColumnModel createDefaultColumnModel() {
3778        return new DefaultTableColumnModel();
3779    }
3780
3781    /**
3782     * Returns the default selection model object, which is
3783     * a <code>DefaultListSelectionModel</code>. A subclass can override this
3784     * method to return a different selection model object.
3785     *
3786     * @return the default selection model object
3787     * @see javax.swing.DefaultListSelectionModel
3788     */

3789    protected ListSelectionModel JavaDoc createDefaultSelectionModel() {
3790        return new DefaultListSelectionModel JavaDoc();
3791    }
3792
3793    /**
3794     * Returns the default table header object, which is
3795     * a <code>JTableHeader</code>. A subclass can override this
3796     * method to return a different table header object.
3797     *
3798     * @return the default table header object
3799     * @see javax.swing.table.JTableHeader
3800     */

3801    protected JTableHeader createDefaultTableHeader() {
3802        return new JTableHeader(columnModel);
3803    }
3804
3805    /**
3806     * Equivalent to <code>revalidate</code> followed by <code>repaint</code>.
3807     */

3808    protected void resizeAndRepaint() {
3809        revalidate();
3810        repaint();
3811    }
3812
3813    /**
3814     * Returns the active cell editor, which is {@code null} if the table
3815     * is not currently editing.
3816     *
3817     * @return the {@code TableCellEditor} that does the editing,
3818     * or {@code null} if the table is not currently editing.
3819     * @see #cellEditor
3820     * @see #getCellEditor(int, int)
3821     */

3822    public TableCellEditor getCellEditor() {
3823        return cellEditor;
3824    }
3825
3826    /**
3827     * Sets the active cell editor.
3828     *
3829     * @param anEditor the active cell editor
3830     * @see #cellEditor
3831     * @beaninfo
3832     * bound: true
3833     * description: The table's active cell editor.
3834     */

3835    public void setCellEditor(TableCellEditor anEditor) {
3836    TableCellEditor oldEditor = cellEditor;
3837        cellEditor = anEditor;
3838    firePropertyChange("tableCellEditor", oldEditor, anEditor);
3839    }
3840
3841    /**
3842     * Sets the <code>editingColumn</code> variable.
3843     * @param aColumn the column of the cell to be edited
3844     *
3845     * @see #editingColumn
3846     */

3847    public void setEditingColumn(int aColumn) {
3848        editingColumn = aColumn;
3849    }
3850
3851    /**
3852     * Sets the <code>editingRow</code> variable.
3853     * @param aRow the row of the cell to be edited
3854     *
3855     * @see #editingRow
3856     */

3857    public void setEditingRow(int aRow) {
3858        editingRow = aRow;
3859    }
3860
3861    /**
3862     * Returns an appropriate renderer for the cell specified by this row and
3863     * column. If the <code>TableColumn</code> for this column has a non-null
3864     * renderer, returns that. If not, finds the class of the data in
3865     * this column (using <code>getColumnClass</code>)
3866     * and returns the default renderer for this type of data.
3867     * <p>
3868     * <b>Note:</b>
3869     * Throughout the table package, the internal implementations always
3870     * use this method to provide renderers so that this default behavior
3871     * can be safely overridden by a subclass.
3872     *
3873     * @param row the row of the cell to render, where 0 is the first row
3874     * @param column the column of the cell to render,
3875     * where 0 is the first column
3876     * @return the assigned renderer; if <code>null</code>
3877     * returns the default renderer
3878     * for this type of object
3879     * @see javax.swing.table.DefaultTableCellRenderer
3880     * @see javax.swing.table.TableColumn#setCellRenderer
3881     * @see #setDefaultRenderer
3882     */

3883    public TableCellRenderer getCellRenderer(int row, int column) {
3884        TableColumn tableColumn = getColumnModel().getColumn(column);
3885        TableCellRenderer renderer = tableColumn.getCellRenderer();
3886        if (renderer == null) {
3887            renderer = getDefaultRenderer(getColumnClass(column));
3888        }
3889        return renderer;
3890    }
3891
3892    /**
3893     * Prepares the renderer by querying the data model for the
3894     * value and selection state
3895     * of the cell at <code>row</code>, <code>column</code>.
3896     * Returns the component (may be a <code>Component</code>
3897     * or a <code>JComponent</code>) under the event location.
3898     * <p>
3899     * <b>Note:</b>
3900     * Throughout the table package, the internal implementations always
3901     * use this method to prepare renderers so that this default behavior
3902     * can be safely overridden by a subclass.
3903     *
3904     * @param renderer the <code>TableCellRenderer</code> to prepare
3905     * @param row the row of the cell to render, where 0 is the first row
3906     * @param column the column of the cell to render,
3907     * where 0 is the first column
3908     * @return the <code>Component</code> under the event location
3909     */

3910    public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
3911        Object JavaDoc value = getValueAt(row, column);
3912
3913        boolean isSelected = false;
3914        boolean hasFocus = false;
3915
3916        // Only indicate the selection and focused cell if not printing
3917
if (!isPrinting) {
3918            isSelected = isCellSelected(row, column);
3919
3920            boolean rowIsLead =
3921                (selectionModel.getLeadSelectionIndex() == row);
3922            boolean colIsLead =
3923                (columnModel.getSelectionModel().getLeadSelectionIndex() == column);
3924
3925            hasFocus = (rowIsLead && colIsLead) && isFocusOwner();
3926        }
3927
3928    return renderer.getTableCellRendererComponent(this, value,
3929                                                  isSelected, hasFocus,
3930                                                  row, column);
3931    }
3932
3933    /**
3934     * Returns an appropriate editor for the cell specified by
3935     * <code>row</code> and <code>column</code>. If the
3936     * <code>TableColumn</code> for this column has a non-null editor,
3937     * returns that. If not, finds the class of the data in this
3938     * column (using <code>getColumnClass</code>)
3939     * and returns the default editor for this type of data.
3940     * <p>
3941     * <b>Note:</b>
3942     * Throughout the table package, the internal implementations always
3943     * use this method to provide editors so that this default behavior
3944     * can be safely overridden by a subclass.
3945     *
3946     * @param row the row of the cell to edit, where 0 is the first row
3947     * @param column the column of the cell to edit,
3948     * where 0 is the first column
3949     * @return the editor for this cell;
3950     * if <code>null</code> return the default editor for
3951     * this type of cell
3952     * @see DefaultCellEditor
3953     */

3954    public TableCellEditor getCellEditor(int row, int column) {
3955        TableColumn tableColumn = getColumnModel().getColumn(column);
3956        TableCellEditor editor = tableColumn.getCellEditor();
3957        if (editor == null) {
3958            editor = getDefaultEditor(getColumnClass(column));
3959        }
3960        return editor;
3961    }
3962
3963
3964    /**
3965     * Prepares the editor by querying the data model for the value and
3966     * selection state of the cell at <code>row</code>, <code>column</code>.
3967     * <p>
3968     * <b>Note:</b>
3969     * Throughout the table package, the internal implementations always
3970     * use this method to prepare editors so that this default behavior
3971     * can be safely overridden by a subclass.
3972     *
3973     * @param editor the <code>TableCellEditor</code> to set up
3974     * @param row the row of the cell to edit,
3975     * where 0 is the first row
3976     * @param column the column of the cell to edit,
3977     * where 0 is the first column
3978     * @return the <code>Component</code> being edited
3979     */

3980    public Component prepareEditor(TableCellEditor editor, int row, int column) {
3981        Object JavaDoc value = getValueAt(row, column);
3982        boolean isSelected = isCellSelected(row, column);
3983        Component comp = editor.getTableCellEditorComponent(this, value, isSelected,
3984                                                  row, column);
3985        if (comp instanceof JComponent JavaDoc) {
3986        JComponent JavaDoc jComp = (JComponent JavaDoc)comp;
3987        if (jComp.getNextFocusableComponent() == null) {
3988        jComp.setNextFocusableComponent(this);
3989        }
3990    }
3991    return comp;
3992    }
3993
3994    /**
3995     * Discards the editor object and frees the real estate it used for
3996     * cell rendering.
3997     */

3998    public void removeEditor() {
3999        KeyboardFocusManager.getCurrentKeyboardFocusManager().
4000            removePropertyChangeListener("permanentFocusOwner", editorRemover);
4001    editorRemover = null;
4002
4003        TableCellEditor editor = getCellEditor();
4004        if(editor != null) {
4005            editor.removeCellEditorListener(this);
4006
4007            if (editorComp != null) {
4008        remove(editorComp);
4009        }
4010
4011            Rectangle cellRect = getCellRect(editingRow, editingColumn, false);
4012
4013            setCellEditor(null);
4014            setEditingColumn(-1);
4015            setEditingRow(-1);
4016            editorComp = null;
4017
4018            repaint(cellRect);
4019        }
4020    }
4021
4022//
4023
// Serialization
4024
//
4025

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

4030    private void writeObject(ObjectOutputStream JavaDoc s) throws IOException JavaDoc {
4031        s.defaultWriteObject();
4032        if (getUIClassID().equals(uiClassID)) {
4033            byte count = JComponent.getWriteObjCounter(this);
4034            JComponent.setWriteObjCounter(this, --count);
4035            if (count == 0 && ui != null) {
4036                ui.installUI(this);
4037            }
4038        }
4039    }
4040
4041    private void readObject(ObjectInputStream JavaDoc s)
4042        throws IOException JavaDoc, ClassNotFoundException JavaDoc
4043    {
4044        s.defaultReadObject();
4045    if ((ui != null) && (getUIClassID().equals(uiClassID))) {
4046        ui.installUI(this);
4047    }
4048        createDefaultRenderers();
4049        createDefaultEditors();
4050
4051        // If ToolTipText != null, then the tooltip has already been
4052
// registered by JComponent.readObject() and we don't want
4053
// to re-register here
4054
if (getToolTipText() == null) {
4055            ToolTipManager.sharedInstance().registerComponent(this);
4056         }
4057    }
4058
4059    /* Called from the JComponent's EnableSerializationFocusListener to
4060     * do any Swing-specific pre-serialization configuration.
4061     */

4062    void compWriteObjectNotify() {
4063        super.compWriteObjectNotify();
4064        // If ToolTipText != null, then the tooltip has already been
4065
// unregistered by JComponent.compWriteObjectNotify()
4066
if (getToolTipText() == null) {
4067            ToolTipManager.sharedInstance().unregisterComponent(this);
4068        }
4069    }
4070
4071    /**
4072     * Returns a string representation of this table. This method
4073     * is intended to be used only for debugging purposes, and the
4074     * content and format of the returned string may vary between
4075     * implementations. The returned string may be empty but may not
4076     * be <code>null</code>.
4077     *
4078     * @return a string representation of this table
4079     */

4080    protected String JavaDoc paramString() {
4081    String JavaDoc gridColorString = (gridColor != null ?
4082                  gridColor.toString() : "");
4083    String JavaDoc showHorizontalLinesString = (showHorizontalLines ?
4084                        "true" : "false");
4085    String JavaDoc showVerticalLinesString = (showVerticalLines ?
4086                      "true" : "false");
4087    String JavaDoc autoResizeModeString;
4088        if (autoResizeMode == AUTO_RESIZE_OFF) {
4089        autoResizeModeString = "AUTO_RESIZE_OFF";
4090    } else if (autoResizeMode == AUTO_RESIZE_NEXT_COLUMN) {
4091        autoResizeModeString = "AUTO_RESIZE_NEXT_COLUMN";
4092    } else if (autoResizeMode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) {
4093        autoResizeModeString = "AUTO_RESIZE_SUBSEQUENT_COLUMNS";
4094    } else if (autoResizeMode == AUTO_RESIZE_LAST_COLUMN) {
4095        autoResizeModeString = "AUTO_RESIZE_LAST_COLUMN";
4096    } else if (autoResizeMode == AUTO_RESIZE_ALL_COLUMNS) {
4097        autoResizeModeString = "AUTO_RESIZE_ALL_COLUMNS";
4098    } else autoResizeModeString = "";
4099    String JavaDoc autoCreateColumnsFromModelString = (autoCreateColumnsFromModel ?
4100                           "true" : "false");
4101    String JavaDoc preferredViewportSizeString = (preferredViewportSize != null ?
4102                          preferredViewportSize.toString()
4103                          : "");
4104    String JavaDoc rowSelectionAllowedString = (rowSelectionAllowed ?
4105                        "true" : "false");
4106    String JavaDoc cellSelectionEnabledString = (cellSelectionEnabled ?
4107                        "true" : "false");
4108    String JavaDoc selectionForegroundString = (selectionForeground != null ?
4109                        selectionForeground.toString() :
4110                        "");
4111    String JavaDoc selectionBackgroundString = (selectionBackground != null ?
4112                        selectionBackground.toString() :
4113                        "");
4114
4115    return super.paramString() +
4116    ",autoCreateColumnsFromModel=" + autoCreateColumnsFromModelString +
4117    ",autoResizeMode=" + autoResizeModeString +
4118    ",cellSelectionEnabled=" + cellSelectionEnabledString +
4119    ",editingColumn=" + editingColumn +
4120    ",editingRow=" + editingRow +
4121    ",gridColor=" + gridColorString +
4122    ",preferredViewportSize=" + preferredViewportSizeString +
4123    ",rowHeight=" + rowHeight +
4124    ",rowMargin=" + rowMargin +
4125    ",rowSelectionAllowed=" + rowSelectionAllowedString +
4126    ",selectionBackground=" + selectionBackgroundString +
4127    ",selectionForeground=" + selectionForegroundString +
4128    ",showHorizontalLines=" + showHorizontalLinesString +
4129    ",showVerticalLines=" + showVerticalLinesString;
4130    }
4131
4132    // This class tracks changes in the keyboard focus state. It is used
4133
// when the JTable is editing to determine when to cancel the edit.
4134
// If focus switches to a component outside of the jtable, but in the
4135
// same window, this will cancel editing.
4136
class CellEditorRemover implements PropertyChangeListener {
4137        KeyboardFocusManager focusManager;
4138
4139        public CellEditorRemover(KeyboardFocusManager fm) {
4140            this.focusManager = fm;
4141        }
4142
4143        public void propertyChange(PropertyChangeEvent ev) {
4144            if (!isEditing() || getClientProperty("terminateEditOnFocusLost") != Boolean.TRUE) {
4145                return;
4146            }
4147
4148            Component c = focusManager.getPermanentFocusOwner();
4149            while (c != null) {
4150                if (c == JTable.this) {
4151                    // focus remains inside the table
4152
return;
4153                } else if ((c instanceof Window) ||
4154                           (c instanceof Applet JavaDoc && c.getParent() == null)) {
4155                    if (c == SwingUtilities.getRoot(JTable.this)) {
4156                        if (!getCellEditor().stopCellEditing()) {
4157                            getCellEditor().cancelCellEditing();
4158                        }
4159                    }
4160                    break;
4161                }
4162                c = c.getParent();
4163            }
4164        }
4165    }
4166
4167/////////////////
4168
// Printing Support
4169
/////////////////
4170

4171    /**
4172     * A convenience method that displays a printing dialog, and then prints
4173     * this <code>JTable</code> in mode <code>PrintMode.FIT_WIDTH</code>,
4174     * with no header or footer text. A modal progress dialog, with an abort
4175     * option, will be shown for the duration of printing.
4176     * <p>
4177     * Note: In headless mode, no dialogs will be shown.
4178     *
4179     * @return true, unless printing is cancelled by the user
4180     * @throws PrinterException if an error in the print system causes the job
4181     * to be aborted
4182     * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
4183     * boolean, PrintRequestAttributeSet, boolean)
4184     * @see #getPrintable
4185     *
4186     * @since 1.5
4187     */

4188    public boolean print() throws PrinterException {
4189
4190        return print(PrintMode.FIT_WIDTH);
4191    }
4192
4193    /**
4194     * A convenience method that displays a printing dialog, and then prints
4195     * this <code>JTable</code> in the given printing mode,
4196     * with no header or footer text. A modal progress dialog, with an abort
4197     * option, will be shown for the duration of printing.
4198     * <p>
4199     * Note: In headless mode, no dialogs will be shown.
4200     *
4201     * @param printMode the printing mode that the printable should use
4202     * @return true, unless printing is cancelled by the user
4203     * @throws PrinterException if an error in the print system causes the job
4204     * to be aborted
4205     * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
4206     * boolean, PrintRequestAttributeSet, boolean)
4207     * @see #getPrintable
4208     *
4209     * @since 1.5
4210     */

4211    public boolean print(PrintMode printMode) throws PrinterException {
4212
4213        return print(printMode, null, null);
4214    }
4215
4216    /**
4217     * A convenience method that displays a printing dialog, and then prints
4218     * this <code>JTable</code> in the given printing mode,
4219     * with the specified header and footer text. A modal progress dialog,
4220     * with an abort option, will be shown for the duration of printing.
4221     * <p>
4222     * Note: In headless mode, no dialogs will be shown.
4223     *
4224     * @param printMode the printing mode that the printable should use
4225     * @param headerFormat a <code>MessageFormat</code> specifying the text
4226     * to be used in printing a header,
4227     * or null for none
4228     * @param footerFormat a <code>MessageFormat</code> specifying the text
4229     * to be used in printing a footer,
4230     * or null for none
4231     * @return true, unless printing is cancelled by the user
4232     * @throws PrinterException if an error in the print system causes the job
4233     * to be aborted
4234     * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
4235     * boolean, PrintRequestAttributeSet, boolean)
4236     * @see #getPrintable
4237     *
4238     * @since 1.5
4239     */

4240    public boolean print(PrintMode printMode,
4241                         MessageFormat JavaDoc headerFormat,
4242                         MessageFormat JavaDoc footerFormat) throws PrinterException {
4243
4244        boolean showDialogs = !GraphicsEnvironment.isHeadless();
4245        return print(printMode, headerFormat, footerFormat,
4246                     showDialogs, null, showDialogs);
4247    }
4248
4249    /**
4250     * Print this <code>JTable</code>. Takes steps that the majority of
4251     * developers would take in order to print a <code>JTable</code>.
4252     * In short, it prepares the table, calls <code>getPrintable</code> to
4253     * fetch an appropriate <code>Printable</code>, and then sends it to the
4254     * printer.
4255     * <p>
4256     * A <code>boolean</code> parameter allows you to specify whether or not
4257     * a printing dialog is displayed to the user. When it is, the user may
4258     * use the dialog to change printing attributes or even cancel the print.
4259     * Another parameter allows for printing attributes to be specified
4260     * directly. This can be used either to provide the initial values for the
4261     * print dialog, or to supply any needed attributes when the dialog is not
4262     * shown.
4263     * <p>
4264     * A second <code>boolean</code> parameter allows you to specify whether
4265     * or not to perform printing in an interactive mode. If <code>true</code>,
4266     * a modal progress dialog, with an abort option, is displayed for the
4267     * duration of printing . This dialog also prevents any user action which
4268     * may affect the table. However, it can not prevent the table from being
4269     * modified by code (for example, another thread that posts updates using
4270     * <code>SwingUtilities.invokeLater</code>). It is therefore the
4271     * responsibility of the developer to ensure that no other code modifies
4272     * the table in any way during printing (invalid modifications include
4273     * changes in: size, renderers, or underlying data). Printing behavior is
4274     * undefined when the table is changed during printing.
4275     * <p>
4276     * If <code>false</code> is specified for this parameter, no dialog will
4277     * be displayed and printing will begin immediately on the event-dispatch
4278     * thread. This blocks any other events, including repaints, from being
4279     * processed until printing is complete. Although this effectively prevents
4280     * the table from being changed, it doesn't provide a good user experience.
4281     * For this reason, specifying <code>false</code> is only recommended when
4282     * printing from an application with no visible GUI.
4283     * <p>
4284     * Note: Attempting to show the printing dialog or run interactively, while
4285     * in headless mode, will result in a <code>HeadlessException</code>.
4286     * <p>
4287     * Before fetching the printable, this method prepares the table in order
4288     * to get the most desirable printed result. If the table is currently
4289     * in an editing mode, it terminates the editing as gracefully as
4290     * possible. It also ensures that the the table's current selection and
4291     * focused cell are not indicated in the printed output. This is handled on
4292     * the view level, and only for the duration of the printing, thus no
4293     * notification needs to be sent to the selection models.
4294     * <p>
4295     * See {@link #getPrintable} for further description on how the
4296     * table is printed.
4297     *
4298     * @param printMode the printing mode that the printable should use
4299     * @param headerFormat a <code>MessageFormat</code> specifying the text
4300     * to be used in printing a header,
4301     * or null for none
4302     * @param footerFormat a <code>MessageFormat</code> specifying the text
4303     * to be used in printing a footer,
4304     * or null for none
4305     * @param showPrintDialog whether or not to display a print dialog
4306     * @param attr a <code>PrintRequestAttributeSet</code>
4307     * specifying any printing attributes,
4308     * or null for none
4309     * @param interactive whether or not to print in an interactive mode
4310     * @return true, unless printing is cancelled by the user
4311     * @throws PrinterException if an error in the print system causes the job
4312     * to be aborted
4313     * @throws HeadlessException if the method is asked to show a printing
4314     * dialog or run interactively, and
4315     * <code>GraphicsEnvironment.isHeadless</code>
4316     * returns true
4317     * @see #getPrintable
4318     * @see java.awt.GraphicsEnvironment#isHeadless
4319     *
4320     * @since 1.5
4321     */

4322    public boolean print(PrintMode printMode,
4323                         MessageFormat JavaDoc headerFormat,
4324                         MessageFormat JavaDoc footerFormat,
4325                         boolean showPrintDialog,
4326                         PrintRequestAttributeSet attr,
4327                         boolean interactive) throws PrinterException,
4328                                                     HeadlessException {
4329
4330        // complain early if an invalid parameter is specified for headless mode
4331
boolean isHeadless = GraphicsEnvironment.isHeadless();
4332        if (isHeadless) {
4333            if (showPrintDialog) {
4334                throw new HeadlessException("Can't show print dialog.");
4335            }
4336            
4337            if (interactive) {
4338                throw new HeadlessException("Can't run interactively.");
4339            }
4340        }
4341
4342        if (isEditing()) {
4343            // try to stop cell editing, and failing that, cancel it
4344
if (!getCellEditor().stopCellEditing()) {
4345                getCellEditor().cancelCellEditing();
4346            }
4347        }
4348
4349        if (attr == null) {
4350            attr = new HashPrintRequestAttributeSet();
4351        }
4352
4353        // get a PrinterJob
4354
final PrinterJob job = PrinterJob.getPrinterJob();
4355
4356        // fetch the Printable
4357
Printable printable =
4358            getPrintable(printMode, headerFormat, footerFormat);
4359
4360        if (interactive) {
4361            // wrap the Printable so that we can print on another thread
4362
printable = new ThreadSafePrintable(printable);
4363        }
4364
4365        // set the printable on the PrinterJob
4366
job.setPrintable(printable);
4367
4368        // if requested, show the print dialog
4369
if (showPrintDialog && !job.printDialog(attr)) {
4370            // the user cancelled the print dialog
4371
return false;
4372        }
4373
4374        // if not interactive, just print on this thread (no dialog)
4375
if (!interactive) {
4376            // set a flag to hide the selection and focused cell
4377
isPrinting = true;
4378
4379            try {
4380                // do the printing
4381
job.print(attr);
4382            } finally {
4383                // restore the flag
4384
isPrinting = false;
4385            }
4386
4387            // we're done
4388
return true;
4389        }
4390
4391        // interactive, drive printing from another thread
4392
// and show a modal status dialog for the duration
4393

4394        // prepare the status JOptionPane
4395
String JavaDoc progressTitle =
4396            UIManager.getString("PrintingDialog.titleProgressText");
4397
4398        String JavaDoc dialogInitialContent =
4399            UIManager.getString("PrintingDialog.contentInitialText");
4400
4401        // this one's a MessageFormat since it must include the page
4402
// number in its text
4403
MessageFormat JavaDoc statusFormat =
4404            new MessageFormat JavaDoc(
4405                UIManager.getString("PrintingDialog.contentProgressText"));
4406
4407        String JavaDoc abortText =
4408            UIManager.getString("PrintingDialog.abortButtonText");
4409        String JavaDoc abortTooltip =
4410            UIManager.getString("PrintingDialog.abortButtonToolTipText");
4411        int abortMnemonic =
4412            UIManager.getInt("PrintingDialog.abortButtonMnemonic", -1);
4413        int abortMnemonicIndex =
4414            UIManager.getInt("PrintingDialog.abortButtonDisplayedMnemonicIndex", -1);
4415
4416        final JButton JavaDoc abortButton = new JButton JavaDoc(abortText);
4417        abortButton.setToolTipText(abortTooltip);
4418        if (abortMnemonic != -1) {
4419            abortButton.setMnemonic(abortMnemonic);
4420        }
4421        if (abortMnemonicIndex != -1) {
4422            abortButton.setDisplayedMnemonicIndex(abortMnemonicIndex);
4423        }
4424
4425        final JLabel JavaDoc statusLabel = new JLabel JavaDoc(dialogInitialContent);
4426
4427        JOptionPane JavaDoc abortPane = new JOptionPane JavaDoc(statusLabel,
4428                                                JOptionPane.INFORMATION_MESSAGE,
4429                                                JOptionPane.DEFAULT_OPTION,
4430                                                null, new Object JavaDoc[] {abortButton},
4431                                                abortButton);
4432
4433        // need a final reference to the printable for later
4434
final ThreadSafePrintable wrappedPrintable =
4435            (ThreadSafePrintable)printable;
4436
4437        // set the label which the wrapped printable will update
4438
wrappedPrintable.startUpdatingStatus(statusFormat, statusLabel);
4439
4440        // The dialog should be centered over the viewport if the table is in one
4441
Container parentComp = getParent() instanceof JViewport JavaDoc ? getParent() : this;
4442
4443        // create the dialog to display the JOptionPane
4444
final JDialog JavaDoc abortDialog = abortPane.createDialog(parentComp, progressTitle);
4445        // clicking the X button should not hide the dialog
4446
abortDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
4447
4448        // the action that will abort printing
4449
final Action JavaDoc abortAction = new AbstractAction JavaDoc() {
4450            boolean isAborted = false;
4451            public void actionPerformed(ActionEvent ae) {
4452                if (!isAborted) {
4453                    isAborted = true;
4454
4455                    // update the status dialog to indicate aborting
4456
abortButton.setEnabled(false);
4457                    abortDialog.setTitle(
4458                        UIManager.getString("PrintingDialog.titleAbortingText"));
4459                    statusLabel.setText(
4460                        UIManager.getString("PrintingDialog.contentAbortingText"));
4461
4462                    // we don't want the aborting status message to be clobbered
4463
wrappedPrintable.stopUpdatingStatus();
4464
4465                    // cancel the PrinterJob
4466
job.cancel();
4467                }
4468            }
4469        };
4470
4471        // clicking the abort button should abort printing
4472
abortButton.addActionListener(abortAction);
4473
4474        // the look and feels set up a close action (typically bound
4475
// to ESCAPE) that also needs to be modified to simply abort
4476
// printing
4477
abortPane.getActionMap().put("close", abortAction);
4478
4479        // clicking the X button should also abort printing
4480
final WindowAdapter closeListener = new WindowAdapter() {
4481            public void windowClosing(WindowEvent we) {
4482                abortAction.actionPerformed(null);
4483            }
4484        };
4485        abortDialog.addWindowListener(closeListener);
4486
4487        // make sure this is clear since we'll check it after
4488
printError = null;
4489
4490        // to synchronize on
4491
final Object JavaDoc lock = new Object JavaDoc();
4492
4493        // copied so we can access from the inner class
4494
final PrintRequestAttributeSet copyAttr = attr;
4495
4496        // this runnable will be used to do the printing
4497
// (and save any throwables) on another thread
4498
Runnable JavaDoc runnable = new Runnable JavaDoc() {
4499            public void run() {
4500                try {
4501                    // do the printing
4502
job.print(copyAttr);
4503                } catch (Throwable JavaDoc t) {
4504                    // save any Throwable to be rethrown
4505
synchronized(lock) {
4506                        printError = t;
4507                    }
4508                } finally {
4509                    // we're finished - hide the dialog, allowing
4510
// processing in the original EDT to continue
4511
SwingUtilities.invokeLater(new Runnable JavaDoc() {
4512                        public void run() {
4513                            // don't want to notify the abort action
4514
abortDialog.removeWindowListener(closeListener);
4515                            abortDialog.dispose();
4516                        }
4517                    });
4518                }
4519            }
4520        };
4521
4522        // start printing on another thread
4523
Thread JavaDoc th = new Thread JavaDoc(runnable);
4524        th.start();
4525
4526        // show the modal status dialog (and wait for it to be hidden)
4527
abortDialog.setVisible(true);
4528
4529        // dialog has been hidden
4530

4531        // look for any error that the printing may have generated
4532
Throwable JavaDoc pe;
4533        synchronized(lock) {
4534            pe = printError;
4535            printError = null;
4536        }
4537
4538        // check the type of error and handle it
4539
if (pe != null) {
4540            // a subclass of PrinterException meaning the job was aborted,
4541
// in this case, by the user
4542
if (pe instanceof PrinterAbortException) {
4543                return false;
4544            } else if (pe instanceof PrinterException) {
4545                throw (PrinterException)pe;
4546            } else if (pe instanceof RuntimeException JavaDoc) {
4547                throw (RuntimeException JavaDoc)pe;
4548            } else if (pe instanceof Error JavaDoc) {
4549                throw (Error JavaDoc)pe;
4550            }
4551
4552            // can not happen
4553
throw new AssertionError JavaDoc(pe);
4554        }
4555
4556        return true;
4557    }
4558
4559    /**
4560     * Return a <code>Printable</code> for use in printing this JTable.
4561     * <p>
4562     * The <code>Printable</code> can be requested in one of two printing modes.
4563     * In both modes, it spreads table rows naturally in sequence across
4564     * multiple pages, fitting as many rows as possible per page.
4565     * <code>PrintMode.NORMAL</code> specifies that the table be
4566     * printed at its current size. In this mode, there may be a need to spread
4567     * columns across pages in a similar manner to that of the rows. When the
4568     * need arises, columns are distributed in an order consistent with the
4569     * table's <code>ComponentOrientation</code>.
4570     * <code>PrintMode.FIT_WIDTH</code> specifies that the output be
4571     * scaled smaller, if necessary, to fit the table's entire width
4572     * (and thereby all columns) on each page. Width and height are scaled
4573     * equally, maintaining the aspect ratio of the output.
4574     * <p>
4575     * The <code>Printable</code> heads the portion of table on each page
4576     * with the appropriate section from the table's <code>JTableHeader</code>,
4577     * if it has one.
4578     * <p>
4579     * Header and footer text can be added to the output by providing
4580     * <code>MessageFormat</code> arguments. The printing code requests
4581     * Strings from the formats, providing a single item which may be included
4582     * in the formatted string: an <code>Integer</code> representing the current
4583     * page number.
4584     * <p>
4585     * You are encouraged to read the documentation for
4586     * <code>MessageFormat</code> as some characters, such as single-quote,
4587     * are special and need to be escaped.
4588     * <p>
4589     * Here's an example of creating a <code>MessageFormat</code> that can be
4590     * used to print "Duke's Table: Page - " and the current page number:
4591     * <p>
4592     * <pre>
4593     * // notice the escaping of the single quote
4594     * // notice how the page number is included with "{0}"
4595     * MessageFormat format = new MessageFormat("Duke''s Table: Page - {0}");
4596     * </pre>
4597     * <p>
4598     * The <code>Printable</code> constrains what it draws to the printable
4599     * area of each page that it prints. Under certain circumstances, it may
4600     * find it impossible to fit all of a page's content into that area. In
4601     * these cases the output may be clipped, but the implementation
4602     * makes an effort to do something reasonable. Here are a few situations
4603     * where this is known to occur, and how they may be handled by this
4604     * particular implementation:
4605     * <ul>
4606     * <li>In any mode, when the header or footer text is too wide to fit
4607     * completely in the printable area -- print as much of the text as
4608     * possible starting from the beginning, as determined by the table's
4609     * <code>ComponentOrientation</code>.
4610     * <li>In any mode, when a row is too tall to fit in the
4611     * printable area -- print the upper-most portion of the row
4612     * and paint no lower border on the table.
4613     * <li>In <code>PrintMode.NORMAL</code> when a column
4614     * is too wide to fit in the printable area -- print the center
4615     * portion of the column and leave the left and right borders
4616     * off the table.
4617     * </ul>
4618     * <p>
4619     * It is entirely valid for this <code>Printable</code> to be wrapped
4620     * inside another in order to create complex reports and documents. You may
4621     * even request that different pages be rendered into different sized
4622     * printable areas. The implementation must be prepared to handle this
4623     * (possibly by doing its layout calculations on the fly). However,
4624     * providing different heights to each page will likely not work well
4625     * with <code>PrintMode.NORMAL</code> when it has to spread columns
4626     * across pages.
4627     * <p>
4628     * It is important to note that this <code>Printable</code> prints the
4629     * table at its current visual state, using the table's existing renderers.
4630     * <i>Before</i> calling this method, you may wish to <i>first</i> modify
4631     * the state of the table (such as to change the renderers, cancel editing,
4632     * or hide the selection).
4633     * <p>
4634     * You must not, however, modify the table in any way <i>after</i>
4635     * this <code>Printable</code> is fetched (invalid modifications include
4636     * changes in: size, renderers, or underlying data). The behavior of the
4637     * returned <code>Printable</code> is undefined once the table has been
4638     * changed.
4639     * <p>
4640     * Here's a simple example that calls this method to fetch a
4641     * <code>Printable</code>, shows a cross-platform print dialog, and then
4642     * prints the <code>Printable</code> unless the user cancels the dialog:
4643     * <p>
4644     * <pre>
4645     * // prepare the table for printing here first (for example, hide selection)
4646     *
4647     * // wrap in a try/finally so table can be restored even if something fails
4648     * try {
4649     * // fetch the printable
4650     * Printable printable = table.getPrintable(JTable.PrintMode.FIT_WIDTH,
4651     * new MessageFormat("My Table"),
4652     * new MessageFormat("Page - {0}"));
4653     *
4654     * // fetch a PrinterJob
4655     * PrinterJob job = PrinterJob.getPrinterJob();
4656     *
4657     * // set the Printable on the PrinterJob
4658     * job.setPrintable(printable);
4659     *
4660     * // create an attribute set to store attributes from the print dialog
4661     * PrintRequestAttributeSet attr = new HashPrintRequestAttributeSet();
4662     *
4663     * // display a print dialog and record whether or not the user cancels it
4664     * boolean printAccepted = job.printDialog(attr);
4665     *
4666     * // if the user didn't cancel the dialog
4667     * if (printAccepted) {
4668     * // do the printing (may need to handle PrinterException)
4669     * job.print(attr);
4670     * }
4671     * } finally {
4672     * // restore the original table state here (for example, restore selection)
4673     * }
4674     * </pre>
4675     *
4676     * @param printMode the printing mode that the printable should use
4677     * @param headerFormat a <code>MessageFormat</code> specifying the text to
4678     * be used in printing a header, or null for none
4679     * @param footerFormat a <code>MessageFormat</code> specifying the text to
4680     * be used in printing a footer, or null for none
4681     * @return a <code>Printable</code> for printing this JTable
4682     * @see Printable
4683     * @see PrinterJob
4684     *
4685     * @since 1.5
4686     */

4687    public Printable getPrintable(PrintMode printMode,
4688                                  MessageFormat JavaDoc headerFormat,
4689                                  MessageFormat JavaDoc footerFormat) {
4690
4691        return new TablePrintable JavaDoc(this, printMode, headerFormat, footerFormat);
4692    }
4693
4694
4695    /**
4696     * A <code>Printable</code> implementation that wraps another
4697     * <code>Printable</code>, making it safe for printing on another thread.
4698     * <p>
4699     * Also performs steps that are specific to this table printing
4700     * implementation, such as hiding the selection and focus in the table,
4701     * and updating the given <code>JLabel</code> with the page number
4702     * based on the specified message format.
4703     */

4704    private class ThreadSafePrintable implements Printable {
4705
4706        /** The delegate <code>Printable</code>. */
4707        private Printable printDelegate;
4708
4709        /** The formatter to prepare the status message. */
4710        private MessageFormat JavaDoc statusFormat;
4711
4712        /** The <code>JLabel</code> to update with the status. */
4713        private JLabel JavaDoc statusLabel;
4714
4715        /**
4716         * To communicate any return value when delegating.
4717         */

4718        private int retVal;
4719
4720        /**
4721         * To communicate any <code>Throwable</code> when delegating.
4722         */

4723        private Throwable JavaDoc retThrowable;
4724
4725        /**
4726         * Construct a <code>ThreadSafePrintable</code> around the given
4727         * delegate.
4728         *
4729         * @param printDelegate the <code>Printable</code> to delegate to
4730         */

4731        public ThreadSafePrintable(Printable printDelegate) {
4732            this.printDelegate = printDelegate;
4733        }
4734
4735        /**
4736         * Provide the <code>MessageFormat</code> and <code>JLabel</code>
4737         * to use in updating the status.
4738         *
4739         * @param statusFormat the format to prepare the status message
4740         * @param statusPane the JOptionPane to set the status message on
4741         */

4742        public void startUpdatingStatus(MessageFormat JavaDoc statusFormat,
4743                                        JLabel JavaDoc statusLabel) {
4744            this.statusFormat = statusFormat;
4745            this.statusLabel = statusLabel;
4746        }
4747
4748        /**
4749         * Indicate that the <code>JLabel</code> should not be updated
4750         * any more.
4751         */

4752        public void stopUpdatingStatus() {
4753            statusFormat = null;
4754            statusLabel = null;
4755        }
4756
4757        /**
4758         * Prints the specified page into the given {@link Graphics}
4759         * context, in the specified format.
4760         * <p>
4761         * Regardless of what thread this method is called on, all calls into
4762         * the delegate will be done on the event-dispatch thread.
4763         *
4764         * @param graphics the context into which the page is drawn
4765         * @param pageFormat the size and orientation of the page being drawn
4766         * @param pageIndex the zero based index of the page to be drawn
4767         * @return PAGE_EXISTS if the page is rendered successfully, or
4768         * NO_SUCH_PAGE if a non-existent page index is specified
4769         * @throws PrinterException if an error causes printing to be aborted
4770         */

4771        public int print(final Graphics graphics,
4772                         final PageFormat pageFormat,
4773                         final int pageIndex) throws PrinterException {
4774
4775            // We'll use this Runnable
4776
Runnable JavaDoc runnable = new Runnable JavaDoc() {
4777                public synchronized void run() {
4778                    // set a flag to hide the selection and focused cell
4779
isPrinting = true;
4780
4781                    try {
4782                        if (statusLabel != null) {
4783                            // set the status message on the JOptionPane with
4784
// the current page number
4785
Object JavaDoc[] pageNumber = new Object JavaDoc[]{
4786                                new Integer JavaDoc(pageIndex + 1)};
4787                            statusLabel.setText(statusFormat.format(pageNumber));
4788                        }
4789
4790                        // call into the delegate and save the return value
4791
retVal = printDelegate.print(graphics, pageFormat, pageIndex);
4792                    } catch (Throwable JavaDoc throwable) {
4793                        // save any Throwable to be rethrown
4794
retThrowable = throwable;
4795                    } finally {
4796                        // restore the flag
4797
isPrinting = false;
4798
4799                        // notify the caller that we're done
4800
notifyAll();
4801                    }
4802                }
4803            };
4804
4805            synchronized(runnable) {
4806                // make sure these are initialized
4807
retVal = -1;
4808                retThrowable = null;
4809
4810                // call into the EDT
4811
SwingUtilities.invokeLater(runnable);
4812
4813                // wait for the runnable to finish
4814
while (retVal == -1 && retThrowable == null) {
4815                    try {
4816                        runnable.wait();
4817                    } catch (InterruptedException JavaDoc ie) {
4818                        // short process, safe to ignore interrupts
4819
}
4820                }
4821
4822                // if the delegate threw a throwable, rethrow it here
4823
if (retThrowable != null) {
4824                    if (retThrowable instanceof PrinterException) {
4825                        throw (PrinterException)retThrowable;
4826                    } else if (retThrowable instanceof RuntimeException JavaDoc) {
4827                        throw (RuntimeException JavaDoc)retThrowable;
4828                    } else if (retThrowable instanceof Error JavaDoc) {
4829                        throw (Error JavaDoc)retThrowable;
4830                    }
4831
4832                    // can not happen
4833
throw new AssertionError JavaDoc(retThrowable);
4834                }
4835
4836                return retVal;
4837            }
4838        }
4839    }
4840
4841
4842/////////////////
4843
// Accessibility support
4844
////////////////
4845

4846    /**
4847     * Gets the AccessibleContext associated with this JTable.
4848     * For tables, the AccessibleContext takes the form of an
4849     * AccessibleJTable.
4850     * A new AccessibleJTable instance is created if necessary.
4851     *
4852     * @return an AccessibleJTable that serves as the
4853     * AccessibleContext of this JTable
4854     */

4855    public AccessibleContext getAccessibleContext() {
4856        if (accessibleContext == null) {
4857            accessibleContext = new AccessibleJTable();
4858        }
4859        return accessibleContext;
4860    }
4861
4862    //
4863
// *** should also implement AccessibleSelection?
4864
// *** and what's up with keyboard navigation/manipulation?
4865
//
4866
/**
4867     * This class implements accessibility support for the
4868     * <code>JTable</code> class. It provides an implementation of the
4869     * Java Accessibility API appropriate to table user-interface elements.
4870     * <p>
4871     * <strong>Warning:</strong>
4872     * Serialized objects of this class will not be compatible with
4873     * future Swing releases. The current serialization support is
4874     * appropriate for short term storage or RMI between applications running
4875     * the same version of Swing. As of 1.4, support for long term storage
4876     * of all JavaBeans<sup><font size="-2">TM</font></sup>
4877     * has been added to the <code>java.beans</code> package.
4878     * Please see {@link java.beans.XMLEncoder}.
4879     */

4880    protected class AccessibleJTable extends AccessibleJComponent
4881    implements AccessibleSelection, ListSelectionListener, TableModelListener,
4882    TableColumnModelListener, CellEditorListener, PropertyChangeListener,
4883    AccessibleExtendedTable {
4884
4885        int lastSelectedRow;
4886        int lastSelectedCol;
4887
4888        /**
4889         * AccessibleJTable constructor
4890         *
4891         * @since 1.5
4892         */

4893        protected AccessibleJTable() {
4894            super();
4895        JTable.this.addPropertyChangeListener(this);
4896            JTable.this.getSelectionModel().addListSelectionListener(this);
4897            TableColumnModel tcm = JTable.this.getColumnModel();
4898            tcm.addColumnModelListener(this);
4899        tcm.getSelectionModel().addListSelectionListener(this);
4900            JTable.this.getModel().addTableModelListener(this);
4901            lastSelectedRow = JTable.this.getSelectedRow();
4902            lastSelectedCol = JTable.this.getSelectedColumn();
4903        }
4904
4905    // Listeners to track model, etc. changes to as to re-place the other
4906
// listeners
4907

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

4913        public void propertyChange(PropertyChangeEvent e) {
4914        String JavaDoc name = e.getPropertyName();
4915        Object JavaDoc oldValue = e.getOldValue();
4916        Object JavaDoc newValue = e.getNewValue();
4917
4918            // re-set tableModel listeners
4919
if (name.compareTo("model") == 0) {
4920
4921        if (oldValue != null && oldValue instanceof TableModel) {
4922            ((TableModel) oldValue).removeTableModelListener(this);
4923        }
4924        if (newValue != null && newValue instanceof TableModel) {
4925            ((TableModel) newValue).addTableModelListener(this);
4926        }
4927
4928            // re-set selectionModel listeners
4929
} else if (name.compareTo("selectionModel") == 0) {
4930
4931        Object JavaDoc source = e.getSource();
4932        if (source == JTable.this) { // row selection model
4933

4934            if (oldValue != null &&
4935            oldValue instanceof ListSelectionModel JavaDoc) {
4936            ((ListSelectionModel JavaDoc) oldValue).removeListSelectionListener(this);
4937            }
4938            if (newValue != null &&
4939            newValue instanceof ListSelectionModel JavaDoc) {
4940            ((ListSelectionModel JavaDoc) newValue).addListSelectionListener(this);
4941            }
4942
4943        } else if (source == JTable.this.getColumnModel()) {
4944
4945            if (oldValue != null &&
4946            oldValue instanceof ListSelectionModel JavaDoc) {
4947            ((ListSelectionModel JavaDoc) oldValue).removeListSelectionListener(this);
4948            }
4949            if (newValue != null &&
4950            newValue instanceof ListSelectionModel JavaDoc) {
4951            ((ListSelectionModel JavaDoc) newValue).addListSelectionListener(this);
4952            }
4953
4954        } else {
4955          // System.out.println("!!! Bug in source of selectionModel propertyChangeEvent");
4956
}
4957
4958            // re-set columnModel listeners
4959
// and column's selection property listener as well
4960
} else if (name.compareTo("columnModel") == 0) {
4961
4962        if (oldValue != null && oldValue instanceof TableColumnModel) {
4963            TableColumnModel tcm = (TableColumnModel) oldValue;
4964            tcm.removeColumnModelListener(this);
4965            tcm.getSelectionModel().removeListSelectionListener(this);
4966        }
4967        if (newValue != null && newValue instanceof TableColumnModel) {
4968            TableColumnModel tcm = (TableColumnModel) newValue;
4969            tcm.addColumnModelListener(this);
4970            tcm.getSelectionModel().addListSelectionListener(this);
4971        }
4972
4973            // re-se cellEditor listeners
4974
} else if (name.compareTo("tableCellEditor") == 0) {
4975
4976        if (oldValue != null && oldValue instanceof TableCellEditor) {
4977            ((TableCellEditor) oldValue).removeCellEditorListener((CellEditorListener) this);
4978        }
4979        if (newValue != null && newValue instanceof TableCellEditor) {
4980            ((TableCellEditor) newValue).addCellEditorListener((CellEditorListener) this);
4981        }
4982        }
4983    }
4984
4985
4986    // Listeners to echo changes to the AccessiblePropertyChange mechanism
4987

4988        /*
4989     * Describes a change in the accessible table model.
4990     */

4991    protected class AccessibleJTableModelChange
4992            implements AccessibleTableModelChange {
4993
4994        protected int type;
4995        protected int firstRow;
4996        protected int lastRow;
4997        protected int firstColumn;
4998        protected int lastColumn;
4999
5000        protected AccessibleJTableModelChange(int type, int firstRow,
5001                          int lastRow, int firstColumn,
5002                          int lastColumn) {
5003        this.type = type;
5004        this.firstRow = firstRow;
5005        this.lastRow = lastRow;
5006        this.firstColumn = firstColumn;
5007        this.lastColumn = lastColumn;
5008        }
5009
5010        public int getType() {
5011        return type;
5012        }
5013
5014        public int getFirstRow() {
5015        return firstRow;
5016        }
5017
5018        public int getLastRow() {
5019        return lastRow;
5020        }
5021
5022        public int getFirstColumn() {
5023        return firstColumn;
5024        }
5025
5026        public int getLastColumn() {
5027        return lastColumn;
5028        }
5029    }
5030
5031        /**
5032         * Track changes to the table contents
5033         */

5034        public void tableChanged(TableModelEvent e) {
5035           firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
5036                              null, null);
5037           if (e != null) {
5038           int firstColumn = e.getColumn();
5039           int lastColumn = e.getColumn();
5040           if (firstColumn == TableModelEvent.ALL_COLUMNS) {
5041               firstColumn = 0;
5042               lastColumn = getColumnCount() - 1;
5043           }
5044
5045           // Fire a property change event indicating the table model
5046
// has changed.
5047
AccessibleJTableModelChange change =
5048               new AccessibleJTableModelChange(e.getType(),
5049                               e.getFirstRow(),
5050                               e.getLastRow(),
5051                               firstColumn,
5052                               lastColumn);
5053           firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
5054                      null, change);
5055            }
5056        }
5057
5058        /**
5059         * Track changes to the table contents (row insertions)
5060         */

5061        public void tableRowsInserted(TableModelEvent e) {
5062           firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
5063                              null, null);
5064
5065       // Fire a property change event indicating the table model
5066
// has changed.
5067
int firstColumn = e.getColumn();
5068       int lastColumn = e.getColumn();
5069       if (firstColumn == TableModelEvent.ALL_COLUMNS) {
5070           firstColumn = 0;
5071           lastColumn = getColumnCount() - 1;
5072       }
5073       AccessibleJTableModelChange change =
5074           new AccessibleJTableModelChange(e.getType(),
5075                           e.getFirstRow(),
5076                           e.getLastRow(),
5077                           firstColumn,
5078                           lastColumn);
5079       firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
5080                  null, change);
5081        }
5082
5083        /**
5084         * Track changes to the table contents (row deletions)
5085         */

5086        public void tableRowsDeleted(TableModelEvent e) {
5087           firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
5088                              null, null);
5089
5090       // Fire a property change event indicating the table model
5091
// has changed.
5092
int firstColumn = e.getColumn();
5093       int lastColumn = e.getColumn();
5094       if (firstColumn == TableModelEvent.ALL_COLUMNS) {
5095           firstColumn = 0;
5096           lastColumn = getColumnCount() - 1;
5097       }
5098       AccessibleJTableModelChange change =
5099           new AccessibleJTableModelChange(e.getType(),
5100                           e.getFirstRow(),
5101                           e.getLastRow(),
5102                           firstColumn,
5103                           lastColumn);
5104       firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
5105                  null, change);
5106        }
5107
5108        /**
5109         * Track changes to the table contents (column insertions)
5110         */

5111        public void columnAdded(TableColumnModelEvent e) {
5112           firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
5113                              null, null);
5114
5115       // Fire a property change event indicating the table model
5116
// has changed.
5117
int type = AccessibleTableModelChange.INSERT;
5118       AccessibleJTableModelChange change =
5119           new AccessibleJTableModelChange(type,
5120                           0,
5121                           0,
5122                           e.getFromIndex(),
5123                           e.getToIndex());
5124       firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
5125                  null, change);
5126        }
5127
5128        /**
5129         * Track changes to the table contents (column deletions)
5130         */

5131        public void columnRemoved(TableColumnModelEvent e) {
5132           firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
5133                              null, null);
5134       // Fire a property change event indicating the table model
5135
// has changed.
5136
int type = AccessibleTableModelChange.DELETE;
5137       AccessibleJTableModelChange change =
5138           new AccessibleJTableModelChange(type,
5139                           0,
5140                           0,
5141                           e.getFromIndex(),
5142                           e.getToIndex());
5143       firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
5144                  null, change);
5145        }
5146
5147        /**
5148         * Track changes of a column repositioning.
5149         *
5150         * @see TableColumnModelListener
5151         */

5152        public void columnMoved(TableColumnModelEvent e) {
5153           firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
5154                              null, null);
5155
5156       // Fire property change events indicating the table model
5157
// has changed.
5158
int type = AccessibleTableModelChange.DELETE;
5159       AccessibleJTableModelChange change =
5160           new AccessibleJTableModelChange(type,
5161                           0,
5162                           0,
5163                           e.getFromIndex(),
5164                           e.getFromIndex());
5165       firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
5166                  null, change);
5167
5168       int type2 = AccessibleTableModelChange.INSERT;
5169       AccessibleJTableModelChange change2 =
5170           new AccessibleJTableModelChange(type2,
5171                           0,
5172                           0,
5173                           e.getToIndex(),
5174                           e.getToIndex());
5175       firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
5176                  null, change2);
5177        }
5178
5179        /**
5180         * Track changes of a column moving due to margin changes.
5181         *
5182         * @see TableColumnModelListener
5183         */

5184        public void columnMarginChanged(ChangeEvent e) {
5185           firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
5186                              null, null);
5187        }
5188
5189        /**
5190         * Track that the selection model of the TableColumnModel changed.
5191         *
5192         * @see TableColumnModelListener
5193         */

5194        public void columnSelectionChanged(ListSelectionEvent e) {
5195            // we should now re-place our TableColumn listener
5196
}
5197
5198        /**
5199         * Track changes to a cell's contents.
5200         *
5201         * Invoked when editing is finished. The changes are saved, the
5202         * editor object is discarded, and the cell is rendered once again.
5203         *
5204         * @see CellEditorListener
5205         */

5206        public void editingStopped(ChangeEvent e) {
5207           // it'd be great if we could figure out which cell, and pass that
5208
// somehow as a parameter
5209
firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
5210                              null, null);
5211        }
5212
5213        /**
5214         * Invoked when editing is canceled. The editor object is discarded
5215         * and the cell is rendered once again.
5216         *
5217         * @see CellEditorListener
5218         */

5219        public void editingCanceled(ChangeEvent e) {
5220            // nothing to report, 'cause nothing changed
5221
}
5222
5223        /**
5224         * Track changes to table cell selections
5225         */

5226        public void valueChanged(ListSelectionEvent e) {
5227            firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
5228                               Boolean.valueOf(false), Boolean.valueOf(true));
5229
5230            int selectedRow = JTable.this.getSelectedRow();
5231            int selectedCol = JTable.this.getSelectedColumn();
5232            if (selectedRow != lastSelectedRow ||
5233                selectedCol != lastSelectedCol) {
5234                Accessible oldA = getAccessibleAt(lastSelectedRow,
5235                                                  lastSelectedCol);
5236                Accessible newA = getAccessibleAt(selectedRow, selectedCol);
5237                firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
5238                                   oldA, newA);
5239                 lastSelectedRow = selectedRow;
5240                 lastSelectedCol = selectedCol;
5241             }
5242        }
5243
5244
5245
5246
5247    // AccessibleContext support
5248

5249        /**
5250         * Get the AccessibleSelection associated with this object. In the
5251         * implementation of the Java Accessibility API for this class,
5252     * return this object, which is responsible for implementing the
5253         * AccessibleSelection interface on behalf of itself.
5254     *
5255     * @return this object
5256         */

5257        public AccessibleSelection getAccessibleSelection() {
5258            return this;
5259        }
5260
5261        /**
5262         * Gets the role of this object.
5263         *
5264         * @return an instance of AccessibleRole describing the role of the
5265         * object
5266         * @see AccessibleRole
5267         */

5268        public AccessibleRole getAccessibleRole() {
5269            return AccessibleRole.TABLE;
5270        }
5271
5272        /**
5273         * Returns the <code>Accessible</code> child, if one exists,
5274         * contained at the local coordinate <code>Point</code>.
5275         *
5276         * @param p the point defining the top-left corner of the
5277         * <code>Accessible</code>, given in the coordinate space
5278         * of the object's parent
5279         * @return the <code>Accessible</code>, if it exists,
5280         * at the specified location; else <code>null</code>
5281         */

5282        public Accessible getAccessibleAt(Point p) {
5283            int column = columnAtPoint(p);
5284            int row = rowAtPoint(p);
5285
5286            if ((column != -1) && (row != -1)) {
5287                TableColumn aColumn = getColumnModel().getColumn(column);
5288                TableCellRenderer renderer = aColumn.getCellRenderer();
5289                if (renderer == null) {
5290                    Class JavaDoc<?> columnClass = getColumnClass(column);
5291                    renderer = getDefaultRenderer(columnClass);
5292                }
5293                Component component = renderer.getTableCellRendererComponent(
5294                                  JTable.this, null, false, false,
5295                                  row, column);
5296                return new AccessibleJTableCell(JTable.this, row, column,
5297                      getAccessibleIndexAt(row, column));
5298            }
5299            return null;
5300        }
5301
5302        /**
5303         * Returns the number of accessible children in the object. If all
5304         * of the children of this object implement <code>Accessible</code>,
5305         * then this method should return the number of children of this object.
5306         *
5307         * @return the number of accessible children in the object
5308         */

5309        public int getAccessibleChildrenCount() {
5310            return (JTable.this.getColumnCount() * JTable.this.getRowCount());
5311        }
5312
5313        /**
5314         * Returns the nth <code>Accessible</code> child of the object.
5315         *
5316         * @param i zero-based index of child
5317         * @return the nth Accessible child of the object
5318         */

5319        public Accessible getAccessibleChild(int i) {
5320            if (i < 0 || i >= getAccessibleChildrenCount()) {
5321                return null;
5322            } else {
5323                // children increase across, and then down, for tables
5324
// (arbitrary decision)
5325
int column = getAccessibleColumnAtIndex(i);
5326                int row = getAccessibleRowAtIndex(i);
5327
5328                TableColumn aColumn = getColumnModel().getColumn(column);
5329                TableCellRenderer renderer = aColumn.getCellRenderer();
5330                if (renderer == null) {
5331                    Class JavaDoc<?> columnClass = getColumnClass(column);
5332                    renderer = getDefaultRenderer(columnClass);
5333                }
5334                Component component = renderer.getTableCellRendererComponent(
5335                                  JTable.this, null, false, false,
5336                                  row, column);
5337                return new AccessibleJTableCell(JTable.this, row, column,
5338                      getAccessibleIndexAt(row, column));
5339            }
5340        }
5341
5342    // AccessibleSelection support
5343

5344        /**
5345         * Returns the number of <code>Accessible</code> children
5346         * currently selected.
5347         * If no children are selected, the return value will be 0.
5348         *
5349         * @return the number of items currently selected
5350         */

5351        public int getAccessibleSelectionCount() {
5352            int rowsSel = JTable.this.getSelectedRowCount();
5353            int colsSel = JTable.this.getSelectedColumnCount();
5354
5355            if (JTable.this.cellSelectionEnabled) { // a contiguous block
5356
return rowsSel * colsSel;
5357
5358            } else {
5359                // a column swath and a row swath, with a shared block
5360
if (JTable.this.getRowSelectionAllowed() &&
5361                    JTable.this.getColumnSelectionAllowed()) {
5362                    return rowsSel * JTable.this.getColumnCount() +
5363                           colsSel * JTable.this.getRowCount() -
5364                           rowsSel * colsSel;
5365
5366                // just one or more rows in selection
5367
} else if (JTable.this.getRowSelectionAllowed()) {
5368                    return rowsSel * JTable.this.getColumnCount();
5369
5370                // just one or more rows in selection
5371
} else if (JTable.this.getColumnSelectionAllowed()) {
5372                    return colsSel * JTable.this.getRowCount();
5373
5374                } else {
5375                    return 0; // JTable doesn't allow selections
5376
}
5377            }
5378        }
5379
5380        /**
5381         * Returns an <code>Accessible</code> representing the
5382         * specified selected child in the object. If there
5383         * isn't a selection, or there are fewer children selected
5384         * than the integer passed in, the return
5385         * value will be <code>null</code>.
5386         * <p>Note that the index represents the i-th selected child, which
5387         * is different from the i-th child.
5388         *
5389         * @param i the zero-based index of selected children
5390         * @return the i-th selected child
5391         * @see #getAccessibleSelectionCount
5392         */

5393        public Accessible getAccessibleSelection(int i) {
5394            if (i < 0 || i > getAccessibleSelectionCount()) {
5395                return (Accessible) null;
5396            }
5397
5398            int rowsSel = JTable.this.getSelectedRowCount();
5399            int colsSel = JTable.this.getSelectedColumnCount();
5400            int rowIndicies[] = getSelectedRows();
5401            int colIndicies[] = getSelectedColumns();
5402            int ttlCols = JTable.this.getColumnCount();
5403            int ttlRows = JTable.this.getRowCount();
5404            int r;
5405            int c;
5406
5407            if (JTable.this.cellSelectionEnabled) { // a contiguous block
5408
r = rowIndicies[i / colsSel];
5409                c = colIndicies[i % colsSel];
5410                return getAccessibleChild((r * ttlCols) + c);
5411            } else {
5412
5413                // a column swath and a row swath, with a shared block
5414
if (JTable.this.getRowSelectionAllowed() &&
5415                    JTable.this.getColumnSelectionAllowed()) {
5416
5417                    // Situation:
5418
// We have a table, like the 6x3 table below,
5419
// wherein three colums and one row selected
5420
// (selected cells marked with "*", unselected "0"):
5421
//
5422
// 0 * 0 * * 0
5423
// * * * * * *
5424
// 0 * 0 * * 0
5425
//
5426

5427                    // State machine below walks through the array of
5428
// selected rows in two states: in a selected row,
5429
// and not in one; continuing until we are in a row
5430
// in which the ith selection exists. Then we return
5431
// the appropriate cell. In the state machine, we
5432
// always do rows above the "current" selected row first,
5433
// then the cells in the selected row. If we're done
5434
// with the state machine before finding the requested
5435
// selected child, we handle the rows below the last
5436
// selected row at the end.
5437
//
5438
int curIndex = i;
5439                    final int IN_ROW = 0;
5440                    final int NOT_IN_ROW = 1;
5441                    int state = (rowIndicies[0] == 0 ? IN_ROW : NOT_IN_ROW);
5442                    int j = 0;
5443                    int prevRow = -1;
5444                    while (j < rowIndicies.length) {
5445                        switch (state) {
5446
5447                        case IN_ROW: // on individual row full of selections
5448
if (curIndex < ttlCols) { // it's here!
5449
c = curIndex % ttlCols;
5450                                r = rowIndicies[j];
5451                                return getAccessibleChild((r * ttlCols) + c);
5452                            } else { // not here
5453
curIndex -= ttlCols;
5454                            }
5455                            // is the next row in table selected or not?
5456
if (j + 1 == rowIndicies.length ||
5457                                rowIndicies[j] != rowIndicies[j+1] - 1) {
5458                                state = NOT_IN_ROW;
5459                                prevRow = rowIndicies[j];
5460                            }
5461                            j++; // we didn't return earlier, so go to next row
5462
break;
5463
5464                        case NOT_IN_ROW: // sparse bunch of rows of selections
5465
if (curIndex <
5466                                (colsSel * (rowIndicies[j] -
5467                                (prevRow == -1 ? 0 : (prevRow + 1))))) {
5468
5469                                // it's here!
5470
c = colIndicies[curIndex % colsSel];
5471                                r = (j > 0 ? rowIndicies[j-1] + 1 : 0)
5472                                    + curIndex / colsSel;
5473                                return getAccessibleChild((r * ttlCols) + c);
5474                            } else { // not here
5475
curIndex -= colsSel * (rowIndicies[j] -
5476                                (prevRow == -1 ? 0 : (prevRow + 1)));
5477                            }
5478                            state = IN_ROW;
5479                            break;
5480                        }
5481                    }
5482                    // we got here, so we didn't find it yet; find it in
5483
// the last sparse bunch of rows
5484
if (curIndex <
5485                        (colsSel * (ttlRows -
5486                        (prevRow == -1 ? 0 : (prevRow + 1))))) { // it's here!
5487
c = colIndicies[curIndex % colsSel];
5488                        r = rowIndicies[j-1] + curIndex / colsSel + 1;
5489                        return getAccessibleChild((r * ttlCols) + c);
5490                    } else { // not here
5491
// we shouldn't get to this spot in the code!
5492
// System.out.println("Bug in AccessibleJTable.getAccessibleSelection()");
5493
}
5494
5495                // one or more rows selected
5496
} else if (JTable.this.getRowSelectionAllowed()) {
5497                    c = i % ttlCols;
5498                    r = rowIndicies[i / ttlCols];
5499                    return getAccessibleChild((r * ttlCols) + c);
5500
5501                // one or more columns selected
5502
} else if (JTable.this.getColumnSelectionAllowed()) {
5503                    c = colIndicies[i % colsSel];
5504                    r = i / colsSel;
5505                    return getAccessibleChild((r * ttlCols) + c);
5506                }
5507            }
5508            return (Accessible) null;
5509        }
5510
5511        /**
5512         * Determines if the current child of this object is selected.
5513         *
5514         * @param i the zero-based index of the child in this
5515         * <code>Accessible</code> object
5516         * @return true if the current child of this object is selected
5517         * @see AccessibleContext#getAccessibleChild
5518         */

5519        public boolean isAccessibleChildSelected(int i) {
5520            int column = getAccessibleColumnAtIndex(i);
5521            int row = getAccessibleRowAtIndex(i);
5522            return JTable.this.isCellSelected(row, column);
5523        }
5524
5525        /**
5526         * Adds the specified <code>Accessible</code> child of the
5527         * object to the object's selection. If the object supports
5528         * multiple selections, the specified child is added to
5529         * any existing selection, otherwise
5530         * it replaces any existing selection in the object. If the
5531         * specified child is already selected, this method has no effect.
5532         * <p>
5533         * This method only works on <code>JTable</code>s which have
5534         * individual cell selection enabled.
5535         *
5536         * @param i the zero-based index of the child
5537         * @see AccessibleContext#getAccessibleChild
5538         */

5539        public void addAccessibleSelection(int i) {
5540        // TIGER - 4495286
5541
int column = getAccessibleColumnAtIndex(i);
5542        int row = getAccessibleRowAtIndex(i);
5543        JTable.this.changeSelection(row, column, true, false);
5544        }
5545
5546        /**
5547         * Removes the specified child of the object from the object's
5548         * selection. If the specified item isn't currently selected, this
5549         * method has no effect.
5550         * <p>
5551         * This method only works on <code>JTables</code> which have
5552         * individual cell selection enabled.
5553         *
5554         * @param i the zero-based index of the child
5555         * @see AccessibleContext#getAccessibleChild
5556         */

5557        public void removeAccessibleSelection(int i) {
5558            if (JTable.this.cellSelectionEnabled) {
5559                int column = getAccessibleColumnAtIndex(i);
5560                int row = getAccessibleRowAtIndex(i);
5561                JTable.this.removeRowSelectionInterval(row, row);
5562                JTable.this.removeColumnSelectionInterval(column, column);
5563            }
5564        }
5565
5566        /**
5567         * Clears the selection in the object, so that no children in the
5568         * object are selected.
5569         */

5570        public void clearAccessibleSelection() {
5571            JTable.this.clearSelection();
5572        }
5573
5574        /**
5575         * Causes every child of the object to be selected, but only
5576         * if the <code>JTable</code> supports multiple selections,
5577         * and if individual cell selection is enabled.
5578         */

5579        public void selectAllAccessibleSelection() {
5580            if (JTable.this.cellSelectionEnabled) {
5581                JTable.this.selectAll();
5582            }
5583        }
5584
5585        // begin AccessibleExtendedTable implementation -------------
5586

5587        /**
5588         * Returns the row number of an index in the table.
5589         *
5590         * @param index the zero-based index in the table
5591         * @return the zero-based row of the table if one exists;
5592         * otherwise -1.
5593         */

5594        public int getAccessibleRow(int index) {
5595        return getAccessibleRowAtIndex(index);
5596        }
5597
5598        /**
5599         * Returns the column number of an index in the table.
5600         *
5601         * @param index the zero-based index in the table
5602         * @return the zero-based column of the table if one exists;
5603         * otherwise -1.
5604         */

5605        public int getAccessibleColumn(int index) {
5606        return getAccessibleColumnAtIndex(index);
5607        }
5608
5609        /**
5610         * Returns the index at a row and column in the table.
5611         *
5612         * @param r zero-based row of the table
5613         * @param c zero-based column of the table
5614         * @return the zero-based index in the table if one exists;
5615         * otherwise -1.
5616         */

5617        public int getAccessibleIndex(int r, int c) {
5618        return getAccessibleIndexAt(r, c);
5619        }
5620
5621        // end of AccessibleExtendedTable implementation ------------
5622

5623    // start of AccessibleTable implementation ------------------
5624

5625    private Accessible caption;
5626    private Accessible summary;
5627    private Accessible [] rowDescription;
5628    private Accessible [] columnDescription;
5629
5630        /**
5631         * Gets the <code>AccessibleTable</code> associated with this
5632         * object. In the implementation of the Java Accessibility
5633         * API for this class, return this object, which is responsible
5634         * for implementing the <code>AccessibleTables</code> interface
5635         * on behalf of itself.
5636     *
5637     * @return this object
5638         */

5639        public AccessibleTable getAccessibleTable() {
5640            return this;
5641        }
5642
5643    /**
5644     * Returns the caption for the table.
5645     *
5646     * @return the caption for the table
5647     */

5648    public Accessible getAccessibleCaption() {
5649        return this.caption;
5650    }
5651
5652    /**
5653     * Sets the caption for the table.
5654     *
5655     * @param a the caption for the table
5656     */

5657    public void setAccessibleCaption(Accessible a) {
5658        Accessible oldCaption = caption;
5659        this.caption = a;
5660        firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_CAPTION_CHANGED,
5661                   oldCaption, this.caption);
5662    }
5663
5664    /**
5665     * Returns the summary description of the table.
5666     *
5667     * @return the summary description of the table
5668     */

5669    public Accessible getAccessibleSummary() {
5670        return this.summary;
5671    }
5672
5673    /**
5674     * Sets the summary description of the table.
5675     *
5676     * @param a the summary description of the table
5677     */

5678    public void setAccessibleSummary(Accessible a) {
5679        Accessible oldSummary = summary;
5680        this.summary = a;
5681        firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_SUMMARY_CHANGED,
5682                   oldSummary, this.summary);
5683    }
5684
5685        /*
5686         * Returns the total number of rows in this table.
5687         *
5688         * @return the total number of rows in this table
5689         */

5690        public int getAccessibleRowCount() {
5691            return JTable.this.getRowCount();
5692        }
5693
5694        /*
5695         * Returns the total number of columns in the table.
5696         *
5697         * @return the total number of columns in the table
5698         */

5699        public int getAccessibleColumnCount() {
5700            return JTable.this.getColumnCount();
5701        }
5702
5703        /*
5704         * Returns the <code>Accessible</code> at a specified row
5705     * and column in the table.
5706         *
5707         * @param r zero-based row of the table
5708         * @param c zero-based column of the table
5709         * @return the <code>Accessible</code> at the specified row and column
5710     * in the table
5711         */

5712        public Accessible getAccessibleAt(int r, int c) {
5713            return getAccessibleChild((r * getAccessibleColumnCount()) + c);
5714        }
5715
5716    /**
5717     * Returns the number of rows occupied by the <code>Accessible</code>
5718     * at a specified row and column in the table.
5719     *
5720     * @return the number of rows occupied by the <code>Accessible</code>
5721     * at a specified row and column in the table
5722     */

5723    public int getAccessibleRowExtentAt(int r, int c) {
5724        return 1;
5725    }
5726
5727    /**
5728     * Returns the number of columns occupied by the
5729         * <code>Accessible</code> at a given (row, column).
5730     *
5731     * @return the number of columns occupied by the <code>Accessible</code>
5732     * at a specified row and column in the table
5733     */

5734    public int getAccessibleColumnExtentAt(int r, int c) {
5735        return 1;
5736    }
5737
5738    /**
5739     * Returns the row headers as an <code>AccessibleTable</code>.
5740     *
5741     * @return an <code>AccessibleTable</code> representing the row
5742     * headers
5743     */

5744        public AccessibleTable getAccessibleRowHeader() {
5745        // row headers are not supported
5746
return null;
5747        }
5748
5749    /**
5750     * Returns the row headers as an <code>AccessibleTable</code>.
5751     *
5752     * @return an <code>AccessibleTable</code> representing
5753     * the row headers
5754     */

5755    public void setAccessibleRowHeader(AccessibleTable a) {
5756        // row headers are not supported
5757
}
5758
5759        /**
5760         * Returns the column headers as an <code>AccessibleTable</code>.
5761         *
5762         * @return an <code>AccessibleTable</code> representing the column
5763         * headers, or <code>null</code> if the table header is
5764         * <code>null</code>
5765         */

5766        public AccessibleTable getAccessibleColumnHeader() {
5767            JTableHeader header = JTable.this.getTableHeader();
5768            return header == null ? null : new AccessibleTableHeader(header);
5769        }
5770    
5771        /*
5772         * Private class representing a table column header
5773         */

5774    private class AccessibleTableHeader implements AccessibleTable {
5775        private JTableHeader header;
5776        private TableColumnModel headerModel;
5777
5778        AccessibleTableHeader(JTableHeader header) {
5779        this.header = header;
5780        this.headerModel = header.getColumnModel();
5781        }
5782
5783        /**
5784         * Returns the caption for the table.
5785         *
5786         * @return the caption for the table
5787         */

5788        public Accessible getAccessibleCaption() { return null; }
5789        
5790        
5791        /**
5792         * Sets the caption for the table.
5793         *
5794         * @param a the caption for the table
5795         */

5796        public void setAccessibleCaption(Accessible a) {}
5797        
5798        /**
5799         * Returns the summary description of the table.
5800         *
5801         * @return the summary description of the table
5802         */

5803        public Accessible getAccessibleSummary() { return null; }
5804        
5805        /**
5806         * Sets the summary description of the table
5807         *
5808         * @param a the summary description of the table
5809         */

5810        public void setAccessibleSummary(Accessible a) {}
5811        
5812        /**
5813         * Returns the number of rows in the table.
5814         *
5815         * @return the number of rows in the table
5816         */

5817        public int getAccessibleRowCount() { return 1; }
5818        
5819        /**
5820         * Returns the number of columns in the table.
5821         *
5822         * @return the number of columns in the table
5823         */

5824        public int getAccessibleColumnCount() {
5825        return headerModel.getColumnCount();
5826        }
5827        
5828        /**
5829         * Returns the Accessible at a specified row and column
5830         * in the table.
5831         *
5832         * @param row zero-based row of the table
5833         * @param column zero-based column of the table
5834         * @return the Accessible at the specified row and column
5835         */

5836        public Accessible getAccessibleAt(int row, int column) {
5837
5838
5839        // TIGER - 4715503
5840
TableColumn aColumn = headerModel.getColumn(column);
5841                TableCellRenderer renderer = aColumn.getHeaderRenderer();
5842                if (renderer == null) {
5843                    renderer = header.getDefaultRenderer();
5844                }
5845                Component component = renderer.getTableCellRendererComponent(
5846                                  header.getTable(),
5847                                  aColumn.getHeaderValue(), false, false,
5848                                  -1, column);
5849
5850                return new AccessibleJTableHeaderCell(row, column,
5851                              JTable.this.getTableHeader(),
5852                              component);
5853            }
5854
5855        /**
5856         * Returns the number of rows occupied by the Accessible at
5857         * a specified row and column in the table.
5858         *
5859         * @return the number of rows occupied by the Accessible at a
5860         * given specified (row, column)
5861         */

5862        public int getAccessibleRowExtentAt(int r, int c) { return 1; }
5863        
5864        /**
5865         * Returns the number of columns occupied by the Accessible at
5866         * a specified row and column in the table.
5867         *
5868         * @return the number of columns occupied by the Accessible at a
5869         * given specified row and column
5870         */

5871        public int getAccessibleColumnExtentAt(int r, int c) { return 1; }
5872        
5873        /**
5874         * Returns the row headers as an AccessibleTable.
5875         *
5876         * @return an AccessibleTable representing the row
5877         * headers
5878         */

5879        public AccessibleTable getAccessibleRowHeader() { return null; }
5880        
5881        /**
5882         * Sets the row headers.
5883         *
5884         * @param table an AccessibleTable representing the
5885         * row headers
5886         */

5887        public void setAccessibleRowHeader(AccessibleTable table) {}
5888        
5889        /**
5890         * Returns the column headers as an AccessibleTable.
5891         *
5892         * @return an AccessibleTable representing the column
5893         * headers
5894         */

5895        public AccessibleTable getAccessibleColumnHeader() { return null; }
5896        
5897        /**
5898         * Sets the column headers.
5899         *
5900         * @param table an AccessibleTable representing the
5901         * column headers
5902         */

5903        public void setAccessibleColumnHeader(AccessibleTable table) {}
5904        
5905        /**
5906         * Returns the description of the specified row in the table.
5907         *
5908         * @param r zero-based row of the table
5909         * @return the description of the row
5910         */

5911        public Accessible getAccessibleRowDescription(int r) { return null; }
5912        
5913        /**
5914         * Sets the description text of the specified row of the table.
5915         *
5916         * @param r zero-based row of the table
5917         * @param a the description of the row
5918         */

5919        public void setAccessibleRowDescription(int r, Accessible a) {}
5920        
5921        /**
5922         * Returns the description text of the specified column in the table.
5923         *
5924         * @param c zero-based column of the table
5925         * @return the text description of the column
5926         */

5927        public Accessible getAccessibleColumnDescription(int c) { return null; }
5928        
5929        /**
5930         * Sets the description text of the specified column in the table.
5931         *
5932         * @param c zero-based column of the table
5933         * @param a the text description of the column
5934         */

5935        public void setAccessibleColumnDescription(int c, Accessible a) {}
5936        
5937        /**
5938         * Returns a boolean value indicating whether the accessible at
5939         * a specified row and column is selected.
5940         *
5941         * @param r zero-based row of the table
5942         * @param c zero-based column of the table
5943         * @return the boolean value true if the accessible at the
5944         * row and column is selected. Otherwise, the boolean value
5945         * false
5946         */

5947        public boolean isAccessibleSelected(int r, int c) { return false; }
5948        
5949        /**
5950         * Returns a boolean value indicating whether the specified row
5951         * is selected.
5952         *
5953         * @param r zero-based row of the table
5954         * @return the boolean value true if the specified row is selected.
5955         * Otherwise, false.
5956         */

5957        public boolean isAccessibleRowSelected(int r) { return false; }
5958        
5959        /**
5960         * Returns a boolean value indicating whether the specified column
5961         * is selected.
5962         *
5963         * @param r zero-based column of the table
5964         * @return the boolean value true if the specified column is selected.
5965         * Otherwise, false.
5966         */

5967        public boolean isAccessibleColumnSelected(int c) { return false; }
5968        
5969        /**
5970         * Returns the selected rows in a table.
5971         *
5972         * @return an array of selected rows where each element is a
5973         * zero-based row of the table
5974         */

5975        public int [] getSelectedAccessibleRows() { return new int[0]; }
5976        
5977        /**
5978         * Returns the selected columns in a table.
5979         *
5980         * @return an array of selected columns where each element is a
5981         * zero-based column of the table
5982         */

5983        public int [] getSelectedAccessibleColumns() { return new int[0]; }
5984    }
5985    
5986
5987    /**
5988     * Returns the column headers as an <code>AccessibleTable</code>.
5989     *
5990     * @return an <code>AccessibleTable</code> representing the column
5991     * headers
5992     */

5993    public void setAccessibleColumnHeader(AccessibleTable a) {
5994        // XXX not implemented
5995
}
5996
5997    /**
5998     * Returns the description of the specified row in the table.
5999     *
6000     * @param r zero-based row of the table
6001     * @return the description of the row
6002     */

6003    public Accessible getAccessibleRowDescription(int r) {
6004        if (r < 0 || r >= getAccessibleRowCount()) {
6005        throw new IllegalArgumentException JavaDoc(new Integer JavaDoc(r).toString());
6006        }
6007        if (rowDescription == null) {
6008        return null;
6009        } else {
6010        return rowDescription[r];
6011        }
6012    }
6013
6014    /**
6015     * Sets the description text of the specified row of the table.
6016     *
6017     * @param r zero-based row of the table
6018     * @param a the description of the row
6019     */

6020    public void setAccessibleRowDescription(int r, Accessible a) {
6021        if (r < 0 || r >= getAccessibleRowCount()) {
6022        throw new IllegalArgumentException JavaDoc(new Integer JavaDoc(r).toString());
6023        }
6024        if (rowDescription == null) {
6025        int numRows = getAccessibleRowCount();
6026        rowDescription = new Accessible[numRows];
6027        }
6028        rowDescription[r] = a;
6029    }
6030
6031    /**
6032     * Returns the description of the specified column in the table.
6033     *
6034     * @param c zero-based column of the table
6035     * @return the description of the column
6036     */

6037    public Accessible getAccessibleColumnDescription(int c) {
6038        if (c < 0 || c >= getAccessibleColumnCount()) {
6039        throw new IllegalArgumentException JavaDoc(new Integer JavaDoc(c).toString());
6040        }
6041        if (columnDescription == null) {
6042        return null;
6043        } else {
6044        return columnDescription[c];
6045        }
6046    }
6047
6048    /**
6049     * Sets the description text of the specified column of the table.
6050     *
6051     * @param c zero-based column of the table
6052     * @param a the description of the column
6053     */

6054    public void setAccessibleColumnDescription(int c, Accessible a) {
6055        if (c < 0 || c >= getAccessibleColumnCount()) {
6056        throw new IllegalArgumentException JavaDoc(new Integer JavaDoc(c).toString());
6057        }
6058        if (columnDescription == null) {
6059        int numColumns = getAccessibleColumnCount();
6060        columnDescription = new Accessible[numColumns];
6061        }
6062        columnDescription[c] = a;
6063    }
6064
6065    /**
6066     * Returns a boolean value indicating whether the accessible at a
6067     * given (row, column) is selected.
6068     *
6069     * @param r zero-based row of the table
6070     * @param c zero-based column of the table
6071     * @return the boolean value true if the accessible at (row, column)
6072     * is selected; otherwise, the boolean value false
6073     */

6074    public boolean isAccessibleSelected(int r, int c) {
6075        return JTable.this.isCellSelected(r, c);
6076    }
6077
6078    /**
6079     * Returns a boolean value indicating whether the specified row
6080     * is selected.
6081     *
6082     * @param r zero-based row of the table
6083     * @return the boolean value true if the specified row is selected;
6084     * otherwise, false
6085     */

6086    public boolean isAccessibleRowSelected(int r) {
6087        return JTable.this.isRowSelected(r);
6088    }
6089
6090    /**
6091     * Returns a boolean value indicating whether the specified column
6092     * is selected.
6093     *
6094     * @param c zero-based column of the table
6095     * @return the boolean value true if the specified column is selected;
6096     * otherwise, false
6097     */

6098    public boolean isAccessibleColumnSelected(int c) {
6099        return JTable.this.isColumnSelected(c);
6100    }
6101
6102    /**
6103     * Returns the selected rows in a table.
6104     *
6105     * @return an array of selected rows where each element is a
6106     * zero-based row of the table
6107     */

6108    public int [] getSelectedAccessibleRows() {
6109        return JTable.this.getSelectedRows();
6110    }
6111
6112    /**
6113     * Returns the selected columns in a table.
6114     *
6115     * @return an array of selected columns where each element is a
6116     * zero-based column of the table
6117     */

6118    public int [] getSelectedAccessibleColumns() {
6119        return JTable.this.getSelectedColumns();
6120    }
6121
6122        /**
6123         * Returns the row at a given index into the table.
6124         *
6125         * @param i zero-based index into the table
6126         * @return the row at a given index
6127         */

6128        public int getAccessibleRowAtIndex(int i) {
6129        int columnCount = getAccessibleColumnCount();
6130        if (columnCount == 0) {
6131        return -1;
6132        } else {
6133        return (i / columnCount);
6134        }
6135        }
6136
6137        /**
6138         * Returns the column at a given index into the table.
6139         *
6140         * @param i zero-based index into the table
6141         * @return the column at a given index
6142         */

6143        public int getAccessibleColumnAtIndex(int i) {
6144        int columnCount = getAccessibleColumnCount();
6145        if (columnCount == 0) {
6146        return -1;
6147        } else {
6148        return (i % columnCount);
6149        }
6150        }
6151
6152        /**
6153         * Returns the index at a given (row, column) in the table.
6154         *
6155         * @param r zero-based row of the table
6156         * @param c zero-based column of the table
6157         * @return the index into the table
6158         */

6159        public int getAccessibleIndexAt(int r, int c) {
6160            return ((r * getAccessibleColumnCount()) + c);
6161        }
6162
6163    // end of AccessibleTable implementation --------------------
6164

6165        /**
6166         * The class provides an implementation of the Java Accessibility
6167     * API appropriate to table cells.
6168         */

6169        protected class AccessibleJTableCell extends AccessibleContext
6170            implements Accessible, AccessibleComponent {
6171
6172            private JTable JavaDoc parent;
6173            private int row;
6174            private int column;
6175            private int index;
6176
6177            /**
6178             * Constructs an <code>AccessibleJTableHeaderEntry</code>.
6179             */

6180            public AccessibleJTableCell(JTable JavaDoc t, int r, int c, int i) {
6181                parent = t;
6182                row = r;
6183                column = c;
6184                index = i;
6185                this.setAccessibleParent(parent);
6186            }
6187
6188            /**
6189             * Gets the <code>AccessibleContext</code> associated with this
6190         * component. In the implementation of the Java Accessibility
6191         * API for this class, return this object, which is its own
6192         * <code>AccessibleContext</code>.
6193             *
6194             * @return this object
6195             */

6196            public AccessibleContext getAccessibleContext() {
6197                return this;
6198            }
6199
6200            private AccessibleContext getCurrentAccessibleContext() {
6201                TableColumn aColumn = getColumnModel().getColumn(column);
6202                TableCellRenderer renderer = aColumn.getCellRenderer();
6203                if (renderer == null) {
6204                    Class JavaDoc<?> columnClass = getColumnClass(column);
6205                    renderer = getDefaultRenderer(columnClass);
6206                }
6207                Component component = renderer.getTableCellRendererComponent(
6208                                  JTable.this, getValueAt(row, column),
6209                  false, false, row, column);
6210                if (component instanceof Accessible) {
6211                    return ((Accessible) component).getAccessibleContext();
6212                } else {
6213                    return null;
6214                }
6215            }
6216
6217            private Component getCurrentComponent() {
6218                TableColumn aColumn = getColumnModel().getColumn(column);
6219                TableCellRenderer renderer = aColumn.getCellRenderer();
6220                if (renderer == null) {
6221                    Class JavaDoc<?> columnClass = getColumnClass(column);
6222                    renderer = getDefaultRenderer(columnClass);
6223                }
6224                return renderer.getTableCellRendererComponent(
6225                                  JTable.this, null, false, false,
6226                                  row, column);
6227            }
6228
6229        // AccessibleContext methods
6230

6231            /**
6232             * Gets the accessible name of this object.
6233             *
6234             * @return the localized name of the object; <code>null</code>
6235             * if this object does not have a name
6236             */

6237            public String JavaDoc getAccessibleName() {
6238                AccessibleContext ac = getCurrentAccessibleContext();
6239                if (ac != null) {
6240                    String JavaDoc name = ac.getAccessibleName();
6241                    if ((name != null) && (name != "")) {
6242                        return ac.getAccessibleName();
6243                    }
6244                }
6245                if ((accessibleName != null) && (accessibleName != "")) {
6246                    return accessibleName;
6247                } else {
6248            return null;
6249                }
6250            }
6251
6252            /**
6253             * Sets the localized accessible name of this object.
6254             *
6255             * @param s the new localized name of the object
6256             */

6257            public void setAccessibleName(String JavaDoc s) {
6258                AccessibleContext ac = getCurrentAccessibleContext();
6259                if (ac != null) {
6260                    ac.setAccessibleName(s);
6261                } else {
6262                    super.setAccessibleName(s);
6263                }
6264            }
6265
6266            //
6267
// *** should check toolTip text for desc. (needs MouseEvent)
6268
//
6269
/**
6270             * Gets the accessible description of this object.
6271             *
6272             * @return the localized description of the object;
6273             * <code>null</code> if this object does not have
6274             * a description
6275             */

6276            public String JavaDoc getAccessibleDescription() {
6277                AccessibleContext ac = getCurrentAccessibleContext();
6278                if (ac != null) {
6279                    return ac.getAccessibleDescription();
6280                } else {
6281                    return super.getAccessibleDescription();
6282                }
6283            }
6284
6285            /**
6286             * Sets the accessible description of this object.
6287             *
6288             * @param s the new localized description of the object
6289             */

6290            public void setAccessibleDescription(String JavaDoc s) {
6291                AccessibleContext ac = getCurrentAccessibleContext();
6292                if (ac != null) {
6293                    ac.setAccessibleDescription(s);
6294                } else {
6295                    super.setAccessibleDescription(s);
6296                }
6297            }
6298
6299            /**
6300             * Gets the role of this object.
6301             *
6302             * @return an instance of <code>AccessibleRole</code>
6303             * describing the role of the object
6304             * @see AccessibleRole
6305             */

6306            public AccessibleRole getAccessibleRole() {
6307                AccessibleContext ac = getCurrentAccessibleContext();
6308                if (ac != null) {
6309                    return ac.getAccessibleRole();
6310                } else {
6311                    return AccessibleRole.UNKNOWN;
6312                }
6313            }
6314
6315            /**
6316             * Gets the state set of this object.
6317             *
6318             * @return an instance of <code>AccessibleStateSet</code>
6319             * containing the current state set of the object
6320             * @see AccessibleState
6321             */

6322            public AccessibleStateSet getAccessibleStateSet() {
6323                AccessibleContext ac = getCurrentAccessibleContext();
6324        AccessibleStateSet as = null;
6325
6326                if (ac != null) {
6327                    as = ac.getAccessibleStateSet();
6328                }
6329        if (as == null) {
6330                    as = new AccessibleStateSet();
6331                }
6332        Rectangle rjt = JTable.this.getVisibleRect();
6333                Rectangle rcell = JTable.this.getCellRect(row, column, false);
6334        if (rjt.intersects(rcell)) {
6335            as.add(AccessibleState.SHOWING);
6336                } else {
6337                    if (as.contains(AccessibleState.SHOWING)) {
6338             as.remove(AccessibleState.SHOWING);
6339            }
6340        }
6341                if (parent.isCellSelected(row, column)) {
6342                as.add(AccessibleState.SELECTED);
6343                } else if (as.contains(AccessibleState.SELECTED)) {
6344            as.remove(AccessibleState.SELECTED);
6345                }
6346        if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
6347            as.add(AccessibleState.ACTIVE);
6348        }
6349            as.add(AccessibleState.TRANSIENT);
6350                return as;
6351            }
6352
6353            /**
6354             * Gets the <code>Accessible</code> parent of this object.
6355             *
6356             * @return the Accessible parent of this object;
6357             * <code>null</code> if this object does not
6358             * have an <code>Accessible</code> parent
6359             */

6360            public Accessible getAccessibleParent() {
6361                return parent;
6362            }
6363
6364            /**
6365             * Gets the index of this object in its accessible parent.
6366             *
6367             * @return the index of this object in its parent; -1 if this
6368             * object does not have an accessible parent
6369             * @see #getAccessibleParent
6370             */

6371            public int getAccessibleIndexInParent() {
6372                return index;
6373            }
6374
6375            /**
6376             * Returns the number of accessible children in the object.
6377             *
6378             * @return the number of accessible children in the object
6379             */

6380            public int getAccessibleChildrenCount() {
6381                AccessibleContext ac = getCurrentAccessibleContext();
6382                if (ac != null) {
6383                    return ac.getAccessibleChildrenCount();
6384                } else {
6385                    return 0;
6386                }
6387            }
6388
6389            /**
6390             * Returns the specified <code>Accessible</code> child of the
6391             * object.
6392             *
6393             * @param i zero-based index of child
6394             * @return the <code>Accessible</code> child of the object
6395             */

6396            public Accessible getAccessibleChild(int i) {
6397                AccessibleContext ac = getCurrentAccessibleContext();
6398                if (ac != null) {
6399                    Accessible accessibleChild = ac.getAccessibleChild(i);
6400                    ac.setAccessibleParent(this);
6401                    return accessibleChild;
6402                } else {
6403                    return null;
6404                }
6405            }
6406
6407            /**
6408             * Gets the locale of the component. If the component
6409             * does not have a locale, then the locale of its parent
6410             * is returned.
6411             *
6412             * @return this component's locale; if this component does
6413             * not have a locale, the locale of its parent is returned
6414             * @exception IllegalComponentStateException if the
6415             * <code>Component</code> does not have its own locale
6416             * and has not yet been added to a containment hierarchy
6417             * such that the locale can be determined from the
6418             * containing parent
6419             * @see #setLocale
6420             */

6421            public Locale getLocale() {
6422                AccessibleContext ac = getCurrentAccessibleContext();
6423                if (ac != null) {
6424                    return ac.getLocale();
6425                } else {
6426                    return null;
6427                }
6428            }
6429
6430            /**
6431             * Adds a <code>PropertyChangeListener</code> to the listener list.
6432             * The listener is registered for all properties.
6433             *
6434             * @param l the <code>PropertyChangeListener</code>
6435             * to be added
6436             */

6437            public void addPropertyChangeListener(PropertyChangeListener l) {
6438                AccessibleContext ac = getCurrentAccessibleContext();
6439                if (ac != null) {
6440                    ac.addPropertyChangeListener(l);
6441                } else {
6442                    super.addPropertyChangeListener(l);
6443                }
6444            }
6445
6446            /**
6447             * Removes a <code>PropertyChangeListener</code> from the
6448             * listener list. This removes a <code>PropertyChangeListener</code>
6449             * that was registered for all properties.
6450             *
6451             * @param l the <code>PropertyChangeListener</code>
6452             * to be removed
6453             */

6454            public void removePropertyChangeListener(PropertyChangeListener l) {
6455                AccessibleContext ac = getCurrentAccessibleContext();
6456                if (ac != null) {
6457                    ac.removePropertyChangeListener(l);
6458                } else {
6459                    super.removePropertyChangeListener(l);
6460                }
6461            }
6462
6463            /**
6464             * Gets the <code>AccessibleAction</code> associated with this
6465             * object if one exists. Otherwise returns <code>null</code>.
6466             *
6467             * @return the <code>AccessibleAction</code>, or <code>null</code>
6468             */

6469            public AccessibleAction getAccessibleAction() {
6470                return getCurrentAccessibleContext().getAccessibleAction();
6471            }
6472
6473            /**
6474             * Gets the <code>AccessibleComponent</code> associated with
6475             * this object if one exists. Otherwise returns <code>null</code>.
6476             *
6477             * @return the <code>AccessibleComponent</code>, or
6478             * <code>null</code>
6479             */

6480            public AccessibleComponent getAccessibleComponent() {
6481                return this; // to override getBounds()
6482
}
6483
6484            /**
6485             * Gets the <code>AccessibleSelection</code> associated with
6486             * this object if one exists. Otherwise returns <code>null</code>.
6487             *
6488             * @return the <code>AccessibleSelection</code>, or
6489             * <code>null</code>
6490             */

6491            public AccessibleSelection getAccessibleSelection() {
6492                return getCurrentAccessibleContext().getAccessibleSelection();
6493            }
6494
6495            /**
6496             * Gets the <code>AccessibleText</code> associated with this
6497             * object if one exists. Otherwise returns <code>null</code>.
6498             *
6499             * @return the <code>AccessibleText</code>, or <code>null</code>
6500             */

6501            public AccessibleText getAccessibleText() {
6502                return getCurrentAccessibleContext().getAccessibleText();
6503            }
6504
6505            /**
6506             * Gets the <code>AccessibleValue</code> associated with
6507             * this object if one exists. Otherwise returns <code>null</code>.
6508             *
6509             * @return the <code>AccessibleValue</code>, or <code>null</code>
6510             */

6511            public AccessibleValue getAccessibleValue() {
6512                return getCurrentAccessibleContext().getAccessibleValue();
6513            }
6514
6515
6516        // AccessibleComponent methods
6517

6518            /**
6519             * Gets the background color of this object.
6520             *
6521             * @return the background color, if supported, of the object;
6522             * otherwise, <code>null</code>
6523             */

6524            public Color getBackground() {
6525                AccessibleContext ac = getCurrentAccessibleContext();
6526                if (ac instanceof AccessibleComponent) {
6527                    return ((AccessibleComponent) ac).getBackground();
6528                } else {
6529                    Component c = getCurrentComponent();
6530                    if (c != null) {
6531                        return c.getBackground();
6532                    } else {
6533                        return null;
6534                    }
6535                }
6536            }
6537
6538            /**
6539             * Sets the background color of this object.
6540             *
6541             * @param c the new <code>Color</code> for the background
6542             */

6543            public void setBackground(Color c) {
6544                AccessibleContext ac = getCurrentAccessibleContext();
6545                if (ac instanceof AccessibleComponent) {
6546                    ((AccessibleComponent) ac).setBackground(c);
6547                } else {
6548                    Component cp = getCurrentComponent();
6549                    if (cp != null) {
6550                        cp.setBackground(c);
6551                    }
6552                }
6553            }
6554
6555            /**
6556             * Gets the foreground color of this object.
6557             *
6558             * @return the foreground color, if supported, of the object;
6559             * otherwise, <code>null</code>
6560             */

6561            public Color getForeground() {
6562                AccessibleContext ac = getCurrentAccessibleContext();
6563                if (ac instanceof AccessibleComponent) {
6564                    return ((AccessibleComponent) ac).getForeground();
6565                } else {
6566                    Component c = getCurrentComponent();
6567                    if (c != null) {
6568                        return c.getForeground();
6569                    } else {
6570                        return null;
6571                    }
6572                }
6573            }
6574
6575            /**
6576             * Sets the foreground color of this object.
6577             *
6578             * @param c the new <code>Color</code> for the foreground
6579             */

6580            public void setForeground(Color c) {
6581                AccessibleContext ac = getCurrentAccessibleContext();
6582                if (ac instanceof AccessibleComponent) {
6583                    ((AccessibleComponent) ac).setForeground(c);
6584                } else {
6585                    Component cp = getCurrentComponent();
6586                    if (cp != null) {
6587                        cp.setForeground(c);
6588                    }
6589                }
6590            }
6591
6592            /**
6593             * Gets the <code>Cursor</code> of this object.
6594             *
6595             * @return the <code>Cursor</code>, if supported,
6596             * of the object; otherwise, <code>null</code>
6597             */

6598            public Cursor getCursor() {
6599                AccessibleContext ac = getCurrentAccessibleContext();
6600                if (ac instanceof AccessibleComponent) {
6601                    return ((AccessibleComponent) ac).getCursor();
6602                } else {
6603                    Component c = getCurrentComponent();
6604                    if (c != null) {
6605                        return c.getCursor();
6606                    } else {
6607                        Accessible ap = getAccessibleParent();
6608                        if (ap instanceof AccessibleComponent) {
6609                            return ((AccessibleComponent) ap).getCursor();
6610                        } else {
6611                            return null;
6612                        }
6613                    }
6614                }
6615            }
6616
6617            /**
6618             * Sets the <code>Cursor</code> of this object.
6619             *
6620             * @param c the new <code>Cursor</code> for the object
6621             */

6622            public void setCursor(Cursor c) {
6623                AccessibleContext ac = getCurrentAccessibleContext();
6624                if (ac instanceof AccessibleComponent) {
6625                    ((AccessibleComponent) ac).setCursor(c);
6626                } else {
6627                    Component cp = getCurrentComponent();
6628                    if (cp != null) {
6629                        cp.setCursor(c);
6630                    }
6631                }
6632            }
6633
6634            /**
6635             * Gets the <code>Font</code> of this object.
6636             *
6637             * @return the <code>Font</code>,if supported,
6638             * for the object; otherwise, <code>null</code>
6639             */

6640            public Font getFont() {
6641                AccessibleContext ac = getCurrentAccessibleContext();
6642                if (ac instanceof AccessibleComponent) {
6643                    return ((AccessibleComponent) ac).getFont();
6644                } else {
6645                    Component c = getCurrentComponent();
6646                    if (c != null) {
6647                        return c.getFont();
6648                    } else {
6649                        return null;
6650                    }
6651                }
6652            }
6653
6654            /**
6655             * Sets the <code>Font</code> of this object.
6656             *
6657             * @param f the new <code>Font</code> for the object
6658             */

6659            public void setFont(Font f) {
6660                AccessibleContext ac = getCurrentAccessibleContext();
6661                if (ac instanceof AccessibleComponent) {
6662                    ((AccessibleComponent) ac).setFont(f);
6663                } else {
6664                    Component c = getCurrentComponent();
6665                    if (c != null) {
6666                        c.setFont(f);
6667                    }
6668                }
6669            }
6670
6671            /**
6672             * Gets the <code>FontMetrics</code> of this object.
6673             *
6674             * @param f the <code>Font</code>
6675             * @return the <code>FontMetrics</code> object, if supported;
6676             * otherwise <code>null</code>
6677             * @see #getFont
6678             */

6679            public FontMetrics getFontMetrics(Font f) {
6680                AccessibleContext ac = getCurrentAccessibleContext();
6681                if (ac instanceof AccessibleComponent) {
6682                    return ((AccessibleComponent) ac).getFontMetrics(f);
6683                } else {
6684                    Component c = getCurrentComponent();
6685                    if (c != null) {
6686                        return c.getFontMetrics(f);
6687                    } else {
6688                        return null;
6689                    }
6690                }
6691            }
6692
6693            /**
6694             * Determines if the object is enabled.
6695             *
6696             * @return true if object is enabled; otherwise, false
6697             */

6698            public boolean isEnabled() {
6699                AccessibleContext ac = getCurrentAccessibleContext();
6700                if (ac instanceof AccessibleComponent) {
6701                    return ((AccessibleComponent) ac).isEnabled();
6702                } else {
6703                    Component c = getCurrentComponent();
6704                    if (c != null) {
6705                        return c.isEnabled();
6706                    } else {
6707                        return false;
6708                    }
6709                }
6710            }
6711
6712            /**
6713             * Sets the enabled state of the object.
6714             *
6715             * @param b if true, enables this object; otherwise, disables it
6716             */

6717            public void setEnabled(boolean b) {
6718                AccessibleContext ac = getCurrentAccessibleContext();
6719                if (ac instanceof AccessibleComponent) {
6720                    ((AccessibleComponent) ac).setEnabled(b);
6721                } else {
6722                    Component c = getCurrentComponent();
6723                    if (c != null) {
6724                        c.setEnabled(b);
6725                    }
6726                }
6727            }
6728
6729            /**
6730             * Determines if this object is visible. Note: this means that the
6731             * object intends to be visible; however, it may not in fact be
6732             * showing on the screen because one of the objects that this object
6733             * is contained by is not visible. To determine if an object is
6734             * showing on the screen, use <code>isShowing</code>.
6735             *
6736             * @return true if object is visible; otherwise, false
6737             */

6738            public boolean isVisible() {
6739                AccessibleContext ac = getCurrentAccessibleContext();
6740                if (ac instanceof AccessibleComponent) {
6741                    return ((AccessibleComponent) ac).isVisible();
6742                } else {
6743                    Component c = getCurrentComponent();
6744                    if (c != null) {
6745                        return c.isVisible();
6746                    } else {
6747                        return false;
6748                    }
6749                }
6750            }
6751
6752            /**
6753             * Sets the visible state of the object.
6754             *
6755             * @param b if true, shows this object; otherwise, hides it
6756             */

6757            public void setVisible(boolean b) {
6758                AccessibleContext ac = getCurrentAccessibleContext();
6759                if (ac instanceof AccessibleComponent) {
6760                    ((AccessibleComponent) ac).setVisible(b);
6761                } else {
6762                    Component c = getCurrentComponent();
6763                    if (c != null) {
6764                        c.setVisible(b);
6765                    }
6766                }
6767            }
6768
6769            /**
6770             * Determines if the object is showing. This is determined
6771             * by checking the visibility of the object and ancestors
6772             * of the object. Note: this will return true even if the
6773             * object is obscured by another (for example,
6774             * it happens to be underneath a menu that was pulled down).
6775             *
6776             * @return true if the object is showing; otherwise, false
6777             */

6778            public boolean isShowing() {
6779                AccessibleContext ac = getCurrentAccessibleContext();
6780                if (ac instanceof AccessibleComponent) {
6781                    if (ac.getAccessibleParent() != null) {
6782                        return ((AccessibleComponent) ac).isShowing();
6783                    } else {
6784                        // Fixes 4529616 - AccessibleJTableCell.isShowing()
6785
// returns false when the cell on the screen
6786
// if no parent
6787
return isVisible();
6788                    }
6789                } else {
6790                    Component c = getCurrentComponent();
6791                    if (c != null) {
6792                        return c.isShowing();
6793                    } else {
6794                        return false;
6795                    }
6796                }
6797            }
6798
6799            /**
6800             * Checks whether the specified point is within this
6801             * object's bounds, where the point's x and y coordinates
6802             * are defined to be relative to the coordinate system of
6803             * the object.
6804             *
6805             * @param p the <code>Point</code> relative to the
6806             * coordinate system of the object
6807             * @return true if object contains <code>Point</code>;
6808             * otherwise false
6809             */

6810            public boolean contains(Point p) {
6811                AccessibleContext ac = getCurrentAccessibleContext();
6812                if (ac instanceof AccessibleComponent) {
6813                    Rectangle r = ((AccessibleComponent) ac).getBounds();
6814                    return r.contains(p);
6815                } else {
6816                    Component c = getCurrentComponent();
6817                    if (c != null) {
6818                        Rectangle r = c.getBounds();
6819                        return r.contains(p);
6820                    } else {
6821                        return getBounds().contains(p);
6822                    }
6823                }
6824            }
6825
6826            /**
6827             * Returns the location of the object on the screen.
6828             *
6829             * @return location of object on screen -- can be
6830             * <code>null</code> if this object is not on the screen
6831             */

6832            public Point getLocationOnScreen() {
6833                if (parent != null) {
6834                    Point parentLocation = parent.getLocationOnScreen();
6835                    Point componentLocation = getLocation();
6836                    componentLocation.translate(parentLocation.x, parentLocation.y);
6837                    return componentLocation;
6838                } else {
6839                    return null;
6840                }
6841            }
6842
6843            /**
6844             * Gets the location of the object relative to the parent
6845             * in the form of a point specifying the object's
6846             * top-left corner in the screen's coordinate space.
6847             *
6848             * @return an instance of <code>Point</code> representing
6849             * the top-left corner of the object's bounds in the
6850             * coordinate space of the screen; <code>null</code> if
6851             * this object or its parent are not on the screen
6852             */

6853            public Point getLocation() {
6854                if (parent != null) {
6855                    Rectangle r = parent.getCellRect(row, column, false);
6856                    if (r != null) {
6857                        return r.getLocation();
6858                    }
6859                }
6860                return null;
6861            }
6862
6863            /**
6864             * Sets the location of the object relative to the parent.
6865             */

6866            public void setLocation(Point p) {
6867// if ((parent != null) && (parent.contains(p))) {
6868
// ensureIndexIsVisible(indexInParent);
6869
// }
6870
}
6871
6872            public Rectangle getBounds() {
6873                if (parent != null) {
6874                    return parent.getCellRect(row, column, false);
6875                } else {
6876                    return null;
6877                }
6878            }
6879
6880            public void setBounds(Rectangle r) {
6881                AccessibleContext ac = getCurrentAccessibleContext();
6882                if (ac instanceof AccessibleComponent) {
6883                    ((AccessibleComponent) ac).setBounds(r);
6884                } else {
6885                    Component c = getCurrentComponent();
6886                    if (c != null) {
6887                        c.setBounds(r);
6888                    }
6889                }
6890            }
6891
6892            public Dimension getSize() {
6893                if (parent != null) {
6894                    Rectangle r = parent.getCellRect(row, column, false);
6895                    if (r != null) {
6896                        return r.getSize();
6897                    }
6898                }
6899                return null;
6900            }
6901
6902            public void setSize (Dimension d) {
6903                AccessibleContext ac = getCurrentAccessibleContext();
6904                if (ac instanceof AccessibleComponent) {
6905                    ((AccessibleComponent) ac).setSize(d);
6906                } else {
6907                    Component c = getCurrentComponent();
6908                    if (c != null) {
6909                        c.setSize(d);
6910                    }
6911                }
6912            }
6913
6914            public Accessible getAccessibleAt(Point p) {
6915                AccessibleContext ac = getCurrentAccessibleContext();
6916                if (ac instanceof AccessibleComponent) {
6917                    return ((AccessibleComponent) ac).getAccessibleAt(p);
6918                } else {
6919                    return null;
6920                }
6921            }
6922
6923            public boolean isFocusTraversable() {
6924                AccessibleContext ac = getCurrentAccessibleContext();
6925                if (ac instanceof AccessibleComponent) {
6926                    return ((AccessibleComponent) ac).isFocusTraversable();
6927                } else {
6928                    Component c = getCurrentComponent();
6929                    if (c != null) {
6930                        return c.isFocusTraversable();
6931                    } else {
6932                        return false;
6933                    }
6934                }
6935            }
6936
6937            public void requestFocus() {
6938                AccessibleContext ac = getCurrentAccessibleContext();
6939                if (ac instanceof AccessibleComponent) {
6940                    ((AccessibleComponent) ac).requestFocus();
6941                } else {
6942                    Component c = getCurrentComponent();
6943                    if (c != null) {
6944                        c.requestFocus();
6945                    }
6946                }
6947            }
6948
6949            public void addFocusListener(FocusListener l) {
6950                AccessibleContext ac = getCurrentAccessibleContext();
6951                if (ac instanceof AccessibleComponent) {
6952                    ((AccessibleComponent) ac).addFocusListener(l);
6953                } else {
6954                    Component c = getCurrentComponent();
6955                    if (c != null) {
6956                        c.addFocusListener(l);
6957                    }
6958                }
6959            }
6960
6961            public void removeFocusListener(FocusListener l) {
6962                AccessibleContext ac = getCurrentAccessibleContext();
6963                if (ac instanceof AccessibleComponent) {
6964                    ((AccessibleComponent) ac).removeFocusListener(l);
6965                } else {
6966                    Component c = getCurrentComponent();
6967                    if (c != null) {
6968                        c.removeFocusListener(l);
6969                    }
6970                }
6971            }
6972
6973        } // inner class AccessibleJTableCell
6974

6975    // Begin AccessibleJTableHeader ========== // TIGER - 4715503
6976

6977        /**
6978         * This class implements accessibility for JTable header cells.
6979         */

6980        private class AccessibleJTableHeaderCell extends AccessibleContext
6981            implements Accessible, AccessibleComponent {
6982
6983            private int row;
6984            private int column;
6985        private JTableHeader parent;
6986            private Component rendererComponent;
6987
6988            /**
6989             * Constructs an <code>AccessibleJTableHeaderEntry</code> instance.
6990         *
6991         * @param row header cell row index
6992         * @param column header cell column index
6993         * @param parent header cell parent
6994         * @param rendererComponent component that renders the header cell
6995             */

6996            public AccessibleJTableHeaderCell(int row, int column,
6997                          JTableHeader parent,
6998                          Component rendererComponent) {
6999                this.row = row;
7000                this.column = column;
7001        this.parent = parent;
7002        this.rendererComponent = rendererComponent;
7003                this.setAccessibleParent(parent);
7004            }
7005
7006            /**
7007             * Gets the <code>AccessibleContext</code> associated with this
7008         * component. In the implementation of the Java Accessibility
7009         * API for this class, return this object, which is its own
7010         * <code>AccessibleContext</code>.
7011             *
7012             * @return this object
7013             */

7014            public AccessibleContext getAccessibleContext() {
7015                return this;
7016            }
7017
7018        /*
7019         * Returns the AccessibleContext for the header cell
7020         * renderer.
7021         */

7022            private AccessibleContext getCurrentAccessibleContext() {
7023        return rendererComponent.getAccessibleContext();
7024            }
7025
7026        /*
7027         * Returns the component that renders the header cell.
7028         */

7029            private Component getCurrentComponent() {
7030        return rendererComponent;
7031            }
7032
7033        // AccessibleContext methods ==========
7034

7035            /**
7036             * Gets the accessible name of this object.
7037             *
7038             * @return the localized name of the object; <code>null</code>
7039             * if this object does not have a name
7040             */

7041            public String JavaDoc getAccessibleName() {
7042                AccessibleContext ac = getCurrentAccessibleContext();
7043                if (ac != null) {
7044                    String JavaDoc name = ac.getAccessibleName();
7045                    if ((name != null) && (name != "")) {
7046                        return ac.getAccessibleName();
7047                    }
7048                }
7049                if ((accessibleName != null) && (accessibleName != "")) {
7050                    return accessibleName;
7051                } else {
7052            return null;
7053                }
7054            }
7055
7056            /**
7057             * Sets the localized accessible name of this object.
7058             *
7059             * @param s the new localized name of the object
7060             */

7061            public void setAccessibleName(String JavaDoc s) {
7062                AccessibleContext ac = getCurrentAccessibleContext();
7063                if (ac != null) {
7064                    ac.setAccessibleName(s);
7065                } else {
7066                    super.setAccessibleName(s);
7067                }
7068            }
7069
7070            /**
7071             * Gets the accessible description of this object.
7072             *
7073             * @return the localized description of the object;
7074             * <code>null</code> if this object does not have
7075             * a description
7076             */

7077            public String JavaDoc getAccessibleDescription() {
7078                AccessibleContext ac = getCurrentAccessibleContext();
7079                if (ac != null) {
7080                    return ac.getAccessibleDescription();
7081                } else {
7082                    return super.getAccessibleDescription();
7083                }
7084            }
7085
7086            /**
7087             * Sets the accessible description of this object.
7088             *
7089             * @param s the new localized description of the object
7090             */

7091            public void setAccessibleDescription(String JavaDoc s) {
7092                AccessibleContext ac = getCurrentAccessibleContext();
7093                if (ac != null) {
7094                    ac.setAccessibleDescription(s);
7095                } else {
7096                    super.setAccessibleDescription(s);
7097                }
7098            }
7099
7100            /**
7101             * Gets the role of this object.
7102             *
7103             * @return an instance of <code>AccessibleRole</code>
7104             * describing the role of the object
7105             * @see AccessibleRole
7106             */

7107            public AccessibleRole getAccessibleRole() {
7108                AccessibleContext ac = getCurrentAccessibleContext();
7109                if (ac != null) {
7110                    return ac.getAccessibleRole();
7111                } else {
7112                    return AccessibleRole.UNKNOWN;
7113                }
7114            }
7115
7116            /**
7117             * Gets the state set of this object.
7118             *
7119             * @return an instance of <code>AccessibleStateSet</code>
7120             * containing the current state set of the object
7121             * @see AccessibleState
7122             */

7123            public AccessibleStateSet getAccessibleStateSet() {
7124                AccessibleContext ac = getCurrentAccessibleContext();
7125        AccessibleStateSet as = null;
7126
7127                if (ac != null) {
7128                    as = ac.getAccessibleStateSet();
7129                }
7130        if (as == null) {
7131                    as = new AccessibleStateSet();
7132                }
7133        Rectangle rjt = JTable.this.getVisibleRect();
7134                Rectangle rcell = JTable.this.getCellRect(row, column, false);
7135        if (rjt.intersects(rcell)) {
7136            as.add(AccessibleState.SHOWING);
7137                } else {
7138                    if (as.contains(AccessibleState.SHOWING)) {
7139             as.remove(AccessibleState.SHOWING);
7140            }
7141        }
7142                if (JTable.this.isCellSelected(row, column)) {
7143                as.add(AccessibleState.SELECTED);
7144                } else if (as.contains(AccessibleState.SELECTED)) {
7145            as.remove(AccessibleState.SELECTED);
7146                }
7147        if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
7148            as.add(AccessibleState.ACTIVE);
7149        }
7150            as.add(AccessibleState.TRANSIENT);
7151                return as;
7152            }
7153
7154            /**
7155             * Gets the <code>Accessible</code> parent of this object.
7156             *
7157             * @return the Accessible parent of this object;
7158             * <code>null</code> if this object does not
7159             * have an <code>Accessible</code> parent
7160             */

7161            public Accessible getAccessibleParent() {
7162                return parent;
7163            }
7164
7165            /**
7166             * Gets the index of this object in its accessible parent.
7167             *
7168             * @return the index of this object in its parent; -1 if this
7169             * object does not have an accessible parent
7170             * @see #getAccessibleParent
7171             */

7172            public int getAccessibleIndexInParent() {
7173                return column;
7174            }
7175
7176            /**
7177             * Returns the number of accessible children in the object.
7178             *
7179             * @return the number of accessible children in the object
7180             */

7181            public int getAccessibleChildrenCount() {
7182                AccessibleContext ac = getCurrentAccessibleContext();
7183                if (ac != null) {
7184                    return ac.getAccessibleChildrenCount();
7185                } else {
7186                    return 0;
7187                }
7188            }
7189
7190            /**
7191             * Returns the specified <code>Accessible</code> child of the
7192             * object.
7193             *
7194             * @param i zero-based index of child
7195             * @return the <code>Accessible</code> child of the object
7196             */

7197            public Accessible getAccessibleChild(int i) {
7198                AccessibleContext ac = getCurrentAccessibleContext();
7199                if (ac != null) {
7200                    Accessible accessibleChild = ac.getAccessibleChild(i);
7201                    ac.setAccessibleParent(this);
7202                    return accessibleChild;
7203                } else {
7204                    return null;
7205                }
7206            }
7207
7208            /**
7209             * Gets the locale of the component. If the component
7210             * does not have a locale, then the locale of its parent
7211             * is returned.
7212             *
7213             * @return this component's locale; if this component does
7214             * not have a locale, the locale of its parent is returned
7215             * @exception IllegalComponentStateException if the
7216             * <code>Component</code> does not have its own locale
7217             * and has not yet been added to a containment hierarchy
7218             * such that the locale can be determined from the
7219             * containing parent
7220             * @see #setLocale
7221             */

7222            public Locale getLocale() {
7223                AccessibleContext ac = getCurrentAccessibleContext();
7224                if (ac != null) {
7225                    return ac.getLocale();
7226                } else {
7227                    return null;
7228                }
7229            }
7230
7231            /**
7232             * Adds a <code>PropertyChangeListener</code> to the listener list.
7233             * The listener is registered for all properties.
7234             *
7235             * @param l the <code>PropertyChangeListener</code>
7236             * to be added
7237             */

7238            public void addPropertyChangeListener(PropertyChangeListener l) {
7239                AccessibleContext ac = getCurrentAccessibleContext();
7240                if (ac != null) {
7241                    ac.addPropertyChangeListener(l);
7242                } else {
7243                    super.addPropertyChangeListener(l);
7244                }
7245            }
7246
7247            /**
7248             * Removes a <code>PropertyChangeListener</code> from the
7249             * listener list. This removes a <code>PropertyChangeListener</code>
7250             * that was registered for all properties.
7251             *
7252             * @param l the <code>PropertyChangeListener</code>
7253             * to be removed
7254             */

7255            public void removePropertyChangeListener(PropertyChangeListener l) {
7256                AccessibleContext ac = getCurrentAccessibleContext();
7257                if (ac != null) {
7258                    ac.removePropertyChangeListener(l);
7259                } else {
7260                    super.removePropertyChangeListener(l);
7261                }
7262            }
7263
7264            /**
7265             * Gets the <code>AccessibleAction</code> associated with this
7266             * object if one exists. Otherwise returns <code>null</code>.
7267             *
7268             * @return the <code>AccessibleAction</code>, or <code>null</code>
7269             */

7270            public AccessibleAction getAccessibleAction() {
7271                return getCurrentAccessibleContext().getAccessibleAction();
7272            }
7273
7274            /**
7275             * Gets the <code>AccessibleComponent</code> associated with
7276             * this object if one exists. Otherwise returns <code>null</code>.
7277             *
7278             * @return the <code>AccessibleComponent</code>, or
7279             * <code>null</code>
7280             */

7281            public AccessibleComponent getAccessibleComponent() {
7282                return this; // to override getBounds()
7283
}
7284
7285            /**
7286             * Gets the <code>AccessibleSelection</code> associated with
7287             * this object if one exists. Otherwise returns <code>null</code>.
7288             *
7289             * @return the <code>AccessibleSelection</code>, or
7290             * <code>null</code>
7291             */

7292            public AccessibleSelection getAccessibleSelection() {
7293                return getCurrentAccessibleContext().getAccessibleSelection();
7294            }
7295
7296            /**
7297             * Gets the <code>AccessibleText</code> associated with this
7298             * object if one exists. Otherwise returns <code>null</code>.
7299             *
7300             * @return the <code>AccessibleText</code>, or <code>null</code>
7301             */

7302            public AccessibleText getAccessibleText() {
7303                return getCurrentAccessibleContext().getAccessibleText();
7304            }
7305
7306            /**
7307             * Gets the <code>AccessibleValue</code> associated with
7308             * thi