OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / javax / swing / JTable.java
1 /* JTable.java -- 
2    Copyright (C) 2002, 2004, 2005, 2006  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package javax.swing;
40
41 import java.awt.Color;
42 import java.awt.Component;
43 import java.awt.Cursor;
44 import java.awt.Dimension;
45 import java.awt.Font;
46 import java.awt.FontMetrics;
47 import java.awt.Point;
48 import java.awt.Rectangle;
49 import java.awt.event.FocusListener;
50 import java.beans.PropertyChangeEvent;
51 import java.beans.PropertyChangeListener;
52 import java.text.DateFormat;
53 import java.text.NumberFormat;
54 import java.util.Date;
55 import java.util.EventObject;
56 import java.util.Hashtable;
57 import java.util.Locale;
58 import java.util.Vector;
59
60 import javax.accessibility.Accessible;
61 import javax.accessibility.AccessibleComponent;
62 import javax.accessibility.AccessibleContext;
63 import javax.accessibility.AccessibleExtendedTable;
64 import javax.accessibility.AccessibleRole;
65 import javax.accessibility.AccessibleSelection;
66 import javax.accessibility.AccessibleState;
67 import javax.accessibility.AccessibleStateSet;
68 import javax.accessibility.AccessibleTable;
69 import javax.accessibility.AccessibleTableModelChange;
70 import javax.swing.event.CellEditorListener;
71 import javax.swing.event.ChangeEvent;
72 import javax.swing.event.ListSelectionEvent;
73 import javax.swing.event.ListSelectionListener;
74 import javax.swing.event.TableColumnModelEvent;
75 import javax.swing.event.TableColumnModelListener;
76 import javax.swing.event.TableModelEvent;
77 import javax.swing.event.TableModelListener;
78 import javax.swing.plaf.TableUI;
79 import javax.swing.table.DefaultTableCellRenderer;
80 import javax.swing.table.DefaultTableColumnModel;
81 import javax.swing.table.DefaultTableModel;
82 import javax.swing.table.JTableHeader;
83 import javax.swing.table.TableCellEditor;
84 import javax.swing.table.TableCellRenderer;
85 import javax.swing.table.TableColumn;
86 import javax.swing.table.TableColumnModel;
87 import javax.swing.table.TableModel;
88
89 /**
90  * The table component, displaying information, organized in rows and columns.
91  * The table can be placed in the scroll bar and have the optional header
92  * that is always visible. Cell values may be editable after double clicking
93  * on the cell. Cell columns may have various data types, that are 
94  * displayed and edited by the different renderers and editors. It is possible
95  * to set different column width. The columns are also resizeable by 
96  * dragging the column boundary in the header.
97  */
98 public class JTable
99   extends JComponent
100   implements TableModelListener, Scrollable, TableColumnModelListener,
101              ListSelectionListener, CellEditorListener, Accessible
102 {
103   /**
104    * Provides accessibility support for <code>JTable</code>.
105    *
106    * @author Roman Kennke (kennke@aicas.com)
107    */
108   protected class AccessibleJTable
109     extends AccessibleJComponent
110     implements AccessibleSelection, ListSelectionListener, TableModelListener,
111     TableColumnModelListener, CellEditorListener, PropertyChangeListener,
112     AccessibleExtendedTable
113   {
114
115     /**
116      * Provides accessibility support for table cells.
117      *
118      * @author Roman Kennke (kennke@aicas.com)
119      */
120     protected class AccessibleJTableCell
121       extends AccessibleContext
122       implements Accessible, AccessibleComponent
123     {
124
125       /**
126        * The table of this cell.
127        */
128       private JTable table;
129
130       /**
131        * The row index of this cell.
132        */
133       private int row;
134
135       /**
136        * The column index of this cell.
137        */
138       private int column;
139
140       /**
141        * The index of this cell inside the AccessibleJTable parent.
142        */
143       private int index;
144
145       /**
146        * Creates a new <code>AccessibleJTableCell</code>.
147        *
148        * @param t the table
149        * @param r the row
150        * @param c the column
151        * @param i the index of this cell inside the accessible table parent
152        */
153       public AccessibleJTableCell(JTable t, int r, int c, int i)
154       {
155         table = t;
156         row = r;
157         column = c;
158         index = i;
159       }
160
161       /**
162        * Returns the accessible row for the table cell.
163        *
164        * @return the accessible row for the table cell
165        */
166       public AccessibleRole getAccessibleRole()
167       {
168         // TODO: What is the role of the table cell?
169         // Seems like the RI returns UNKNOWN here for 'normal' cells, might
170         // be different for special renderers though (not tested yet).
171         return AccessibleRole.UNKNOWN;
172       }
173
174       /**
175        * Returns the accessible state set of this accessible table cell.
176        *
177        * @return the accessible state set of this accessible table cell
178        */
179       public AccessibleStateSet getAccessibleStateSet()
180       {
181         AccessibleStateSet state = new AccessibleStateSet();
182
183         // Figure out the SHOWING state.
184         Rectangle visibleRect = getVisibleRect();
185         Rectangle cellRect = getCellRect(row, column, false);
186         if (visibleRect.intersects(cellRect))
187           state.add(AccessibleState.SHOWING);
188
189         // Figure out SELECTED state.
190         if (isCellSelected(row, column))
191           state.add(AccessibleState.SELECTED);
192
193         // Figure out ACTIVE state.
194         if (row == getSelectedRow() && column == getSelectedColumn())
195           state.add(AccessibleState.ACTIVE);
196
197         // TRANSIENT seems to be always set in the RI.
198         state.add(AccessibleState.TRANSIENT);
199
200         // TODO: Any other state to handle here?
201         return state;
202       }
203
204       /**
205        * Returns the index of this cell in the parent object.
206        *
207        * @return the index of this cell in the parent object
208        */
209       public int getAccessibleIndexInParent()
210       {
211         return index;
212       }
213
214       /**
215        * Returns the number of children of this object. Table cells cannot have
216        * children, so we return <code>0</code> here.
217        *
218        * @return <code>0</code>
219        */
220       public int getAccessibleChildrenCount()
221       {
222         return 0;
223       }
224
225       /**
226        * Returns the accessible child at index <code>i</code>. Table cells
227        * don't have children, so we return <code>null</code> here.
228        *
229        * @return <code>null</code>
230        */
231       public Accessible getAccessibleChild(int i)
232       {
233         return null;
234       }
235
236       /**
237        * Returns the locale setting for this accessible table cell.
238        *
239        * @return the locale setting for this accessible table cell
240        */
241       public Locale getLocale()
242       {
243         // TODO: For now, we return english here. This must be fixed as soon
244         // as we have a localized Swing.
245         return Locale.ENGLISH;
246       }
247
248       /**
249        * Returns the accessible context of this table cell. Since accessible
250        * table cells are their own accessible context, we return
251        * <code>this</code>.
252        *
253        * @return the accessible context of this table cell
254        */
255       public AccessibleContext getAccessibleContext()
256       {
257         return this;
258       }
259
260       /**
261        * Returns the background color of this cell.
262        *
263        * @return the background color of this cell
264        */
265       public Color getBackground()
266       {
267         return table.getBackground();
268       }
269
270       /**
271        * Sets the background of the cell. Since table cells cannot have
272        * individual background colors, this method does nothing. Set the
273        * background directly on the table instead.
274        * 
275        * @param color not used
276        */
277       public void setBackground(Color color)
278       {
279         // This method does nothing. See API comments.
280       }
281
282       /**
283        * Returns the foreground color of the table cell.
284        *
285        * @return the foreground color of the table cell
286        */
287       public Color getForeground()
288       {
289         return table.getForeground();
290       }
291
292       /**
293        * Sets the foreground of the cell. Since table cells cannot have
294        * individual foreground colors, this method does nothing. Set the
295        * foreground directly on the table instead.
296        * 
297        * @param color not used
298        */
299       public void setForeground(Color color)
300       {
301         // This method does nothing. See API comments.
302       }
303
304       /**
305        * Returns the cursor for this table cell.
306        *
307        * @return the cursor for this table cell
308        */
309       public Cursor getCursor()
310       {
311         return table.getCursor();
312       }
313
314       /**
315        * Sets the cursor of the cell. Since table cells cannot have
316        * individual cursors, this method does nothing. Set the
317        * cursor directly on the table instead.
318        * 
319        * @param cursor not used
320        */
321       public void setCursor(Cursor cursor)
322       {
323         // This method does nothing. See API comments.
324       }
325
326       /**
327        * Returns the font of the table cell.
328        *
329        * @return the font of the table cell
330        */
331       public Font getFont()
332       {
333         return table.getFont();
334       }
335
336       /**
337        * Sets the font of the cell. Since table cells cannot have
338        * individual fonts, this method does nothing. Set the
339        * font directly on the table instead.
340        * 
341        * @param font not used
342        */
343       public void setFont(Font font)
344       {
345         // This method does nothing. See API comments.
346       }
347
348       /**
349        * Returns the font metrics for a specified font.
350        *
351        * @param font the font for which we return the metrics
352        *
353        * @return the font metrics for a specified font
354        */
355       public FontMetrics getFontMetrics(Font font)
356       {
357         return table.getFontMetrics(font);
358       }
359
360       /**
361        * Returns <code>true</code> if this table cell is enabled,
362        * <code>false</code> otherwise.
363        *
364        * @return <code>true</code> if this table cell is enabled,
365        *         <code>false</code> otherwise
366        */
367       public boolean isEnabled()
368       {
369         return table.isEnabled();
370       }
371
372       /**
373        * Table cells cannot be disabled or enabled individually, so this method
374        * does nothing. Set the enabled flag on the table itself.
375        *
376        * @param b not used here
377        */
378       public void setEnabled(boolean b)
379       {
380         // This method does nothing. See API comments.
381       }
382
383       /**
384        * Returns <code>true</code> if this cell is visible, <code>false</code>
385        * otherwise.
386        *
387        * @return <code>true</code> if this cell is visible, <code>false</code>
388        *         otherwise
389        */
390       public boolean isVisible()
391       {
392         return table.isVisible();
393       }
394
395       /**
396        * The visibility cannot be set on individual table cells, so this method
397        * does nothing. Set the visibility on the table itself.
398        *
399        * @param b not used
400        */
401       public void setVisible(boolean b)
402       {
403         // This method does nothing. See API comments.
404       }
405
406       /**
407        * Returns <code>true</code> if this table cell is currently showing on
408        * screen.
409        *
410        * @return <code>true</code> if this table cell is currently showing on
411        *         screen
412        */
413       public boolean isShowing()
414       {
415         return table.isShowing();
416       }
417
418       /**
419        * Returns <code>true</code> if this table cell contains the location
420        * at <code>point</code>, <code>false</code> otherwise.
421        * <code>point</code> is interpreted as relative to the coordinate system
422        * of the table cell.
423        *
424        * @return <code>true</code> if this table cell contains the location
425        *         at <code>point</code>, <code>false</code> otherwise
426        */
427       public boolean contains(Point point)
428       {
429         Rectangle cellRect = table.getCellRect(row, column, true);
430         cellRect.x = 0;
431         cellRect.y = 0;
432         return cellRect.contains(point);
433       }
434
435       /**
436        * Returns the screen location of the table cell.
437        *
438        * @return the screen location of the table cell
439        */
440       public Point getLocationOnScreen()
441       {
442         Point tableLoc = table.getLocationOnScreen();
443         Rectangle cellRect = table.getCellRect(row, column, true);
444         tableLoc.x += cellRect.x;
445         tableLoc.y += cellRect.y;
446         return tableLoc;
447       }
448
449       /**
450        * Returns the location of this cell relative to the table's bounds.
451        *
452        * @return the location of this cell relative to the table's bounds
453        */
454       public Point getLocation()
455       {
456         Rectangle cellRect = table.getCellRect(row, column, true);
457         return new Point(cellRect.x, cellRect.y);
458       }
459
460       /**
461        * The location of the table cells cannot be manipulated directly, so
462        * this method does nothing.
463        *
464        * @param point not used
465        */
466       public void setLocation(Point point)
467       {
468         // This method does nothing. See API comments.
469       }
470
471       /**
472        * Returns the bounds of the cell relative to its table.
473        *
474        * @return the bounds of the cell relative to its table
475        */
476       public Rectangle getBounds()
477       {
478         return table.getCellRect(row, column, true);
479       }
480
481       /**
482        * The bounds of the table cells cannot be manipulated directly, so
483        * this method does nothing.
484        *
485        * @param rectangle not used
486        */
487       public void setBounds(Rectangle rectangle)
488       {
489         // This method does nothing. See API comments.
490       }
491
492       /**
493        * Returns the size of the table cell.
494        *
495        * @return the size of the table cell
496        */
497       public Dimension getSize()
498       {
499         Rectangle cellRect = table.getCellRect(row, column, true);
500         return new Dimension(cellRect.width, cellRect.height);
501       }
502
503       /**
504        * The size cannot be set on table cells directly, so this method does
505        * nothing.
506        *
507        * @param dimension not used
508        */
509       public void setSize(Dimension dimension)
510       {
511         // This method does nothing. See API comments.
512       }
513
514       /**
515        * Table cells have no children, so we return <code>null</code> here.
516        *
517        * @return <code>null</code>
518        */
519       public Accessible getAccessibleAt(Point point)
520       {
521         return null;
522       }
523
524       /**
525        * Returns <code>true</code> if this table cell is focus traversable,
526        * <code>false</code> otherwise.
527        *
528        * @return <code>true</code> if this table cell is focus traversable,
529        *         <code>false</code> otherwise
530        */
531       public boolean isFocusTraversable()
532       {
533         return table.isFocusable();
534       }
535
536       /**
537        * Requests that this table cell gets the keyboard focus.
538        */
539       public void requestFocus()
540       {
541         // We first set the selection models' lead selection to this cell.
542         table.getColumnModel().getSelectionModel()
543         .setLeadSelectionIndex(column);
544         table.getSelectionModel().setLeadSelectionIndex(row);
545         // Now we request that the table receives focus.
546         table.requestFocus();
547       }
548
549       /**
550        * Adds a focus listener to this cell. The focus listener is really
551        * added to the table, so there is no way to find out when an individual
552        * cell changes the focus.
553        *
554        * @param listener the focus listener to add
555        */
556       public void addFocusListener(FocusListener listener)
557       {
558         table.addFocusListener(listener);
559       }
560
561       /**
562        * Removes a focus listener from the cell. The focus listener is really
563        * removed from the table.
564        *
565        * @param listener the listener to remove
566        */
567       public void removeFocusListener(FocusListener listener)
568       {
569         table.removeFocusListener(listener);
570       }
571         
572     }
573
574     protected class AccessibleJTableModelChange
575       implements AccessibleTableModelChange
576     {
577       protected int type;
578       protected int firstRow;
579       protected int lastRow;
580       protected int firstColumn;
581       protected int lastColumn;
582
583       protected AccessibleJTableModelChange(int type, int firstRow,
584                                             int lastRow, int firstColumn,
585                                             int lastColumn)
586       {
587         this.type = type;
588         this.firstRow = firstRow;
589         this.lastRow = lastRow;
590         this.firstColumn = firstColumn;
591         this.lastColumn = lastColumn;
592       }
593
594       public int getType()
595       {
596         return type;
597       }
598
599       public int getFirstRow()
600       {
601         return firstRow;
602       }
603
604       public int getLastRow()
605       {
606         return lastRow;
607       }
608
609       public int getFirstColumn()
610       {
611         return firstColumn;
612       }
613
614       public int getLastColumn()
615       {
616         return lastColumn;
617       }
618     }
619
620     /**
621      * The RI returns an instance with this name in
622      * {@link #getAccessibleColumnHeader()}, this makes sense, so we do the
623      * same.
624      */
625     private class AccessibleTableHeader
626       implements AccessibleTable
627     {
628
629       /**
630        * The JTableHeader wrapped by this class.
631        */
632       private JTableHeader header;
633
634       /**
635        * Creates a new instance.
636        *
637        * @param h the JTableHeader to wrap
638        */
639       private AccessibleTableHeader(JTableHeader h)
640       {
641         header = h;
642       }
643
644       /**
645        * Returns the caption for the table header.
646        *
647        * @return the caption for the table header
648        */
649       public Accessible getAccessibleCaption()
650       {
651         // The RI seems to always return null here, so do we.
652         return null;
653       }
654
655       /**
656        * Sets the caption for the table header.
657        *
658        * @param caption the caption to set
659        */
660       public void setAccessibleCaption(Accessible caption)
661       {
662         // This seems to be a no-op in the RI, so we do the same.
663       }
664
665       /**
666        * Returns the caption for the table header.
667        *
668        * @return the caption for the table header
669        */
670       public Accessible getAccessibleSummary()
671       {
672         // The RI seems to always return null here, so do we.
673         return null;
674       }
675
676       /**
677        * Sets the summary for the table header.
678        *
679        * @param summary the caption to set
680        */
681       public void setAccessibleSummary(Accessible summary)
682       {
683         // This seems to be a no-op in the RI, so we do the same.
684       }
685
686       /**
687        * Returns the number of rows, which is always 1 for the table header.
688        *
689        * @return the number of rows
690        */
691       public int getAccessibleRowCount()
692       {
693         return 1;
694       }
695
696       /**
697        * Returns the number of columns in the table header.
698        *
699        * @return the number of columns in the table header
700        */
701       public int getAccessibleColumnCount()
702       {
703         return header.getColumnModel().getColumnCount();
704       }
705
706       /**
707        * Returns the accessible child at the specified row and column.
708        * The row number is ignored here, and we return an
709        * AccessibleJTableHeaderCell here with the renderer component as
710        * component.
711        *
712        * @param r the row number
713        * @param c the column number
714        *
715        * @return the accessible child at the specified row and column
716        */
717       public Accessible getAccessibleAt(int r, int c)
718       {
719         TableColumn column = header.getColumnModel().getColumn(c);
720         TableCellRenderer rend = column.getHeaderRenderer();
721         if (rend == null)
722           rend = header.getDefaultRenderer();
723         Component comp =
724           rend.getTableCellRendererComponent(header.getTable(),
725                                              column.getHeaderValue(), false,
726                                              false, -1, c);
727         return new AccessibleJTableHeaderCell(header, comp, r, c);
728       }
729
730       public int getAccessibleRowExtentAt(int r, int c)
731       {
732         // TODO Auto-generated method stub
733         return 0;
734       }
735
736       public int getAccessibleColumnExtentAt(int r, int c)
737       {
738         // TODO Auto-generated method stub
739         return 0;
740       }
741
742       public AccessibleTable getAccessibleRowHeader()
743       {
744         // TODO Auto-generated method stub
745         return null;
746       }
747
748       public void setAccessibleRowHeader(AccessibleTable header)
749       {
750         // TODO Auto-generated method stub
751         
752       }
753
754       public AccessibleTable getAccessibleColumnHeader()
755       {
756         // TODO Auto-generated method stub
757         return null;
758       }
759
760       public void setAccessibleColumnHeader(AccessibleTable header)
761       {
762         // TODO Auto-generated method stub
763         
764       }
765
766       public Accessible getAccessibleRowDescription(int r)
767       {
768         // TODO Auto-generated method stub
769         return null;
770       }
771
772       public void setAccessibleRowDescription(int r, Accessible description)
773       {
774         // TODO Auto-generated method stub
775         
776       }
777
778       public Accessible getAccessibleColumnDescription(int c)
779       {
780         // TODO Auto-generated method stub
781         return null;
782       }
783
784       public void setAccessibleColumnDescription(int c, Accessible description)
785       {
786         // TODO Auto-generated method stub
787         
788       }
789
790       public boolean isAccessibleSelected(int r, int c)
791       {
792         // TODO Auto-generated method stub
793         return false;
794       }
795
796       public boolean isAccessibleRowSelected(int r)
797       {
798         // TODO Auto-generated method stub
799         return false;
800       }
801
802       public boolean isAccessibleColumnSelected(int c)
803       {
804         // TODO Auto-generated method stub
805         return false;
806       }
807
808       public int[] getSelectedAccessibleRows()
809       {
810         // TODO Auto-generated method stub
811         return null;
812       }
813
814       public int[] getSelectedAccessibleColumns()
815       {
816         // TODO Auto-generated method stub
817         return null;
818       }
819         
820     }
821
822     /**
823      * The RI returns an instance of such class for table header cells. This
824      * makes sense so I added this class. This still needs to be fully
825      * implemented, I just don't feel motivated enough to do so just now.
826      */
827     private class AccessibleJTableHeaderCell
828       extends AccessibleContext
829       implements Accessible, AccessibleComponent
830     {
831
832       JTableHeader header;
833       
834       int columnIndex;
835       
836       /**
837        * 
838        * @param h  the table header.
839        * @param comp
840        * @param r
841        * @param c  the column index.
842        */
843       private AccessibleJTableHeaderCell(JTableHeader h, Component comp, int r,
844                                          int c)
845       {
846         header = h;
847         columnIndex = c;
848       }
849
850       /**
851        * Returns the header renderer.
852        * 
853        * @return The header renderer.
854        */
855       Component getColumnHeaderRenderer()
856       {
857         TableColumn tc = header.getColumnModel().getColumn(columnIndex);
858         TableCellRenderer r = tc.getHeaderRenderer();
859         if (r == null)
860           r = header.getDefaultRenderer();
861         return r.getTableCellRendererComponent(header.getTable(), 
862             tc.getHeaderValue(), false, false, -1, columnIndex);
863       }
864       
865       /**
866        * Returns the accessible role for the table header cell.
867        * 
868        * @return The accessible role.
869        */
870       public AccessibleRole getAccessibleRole()
871       {
872         Component renderer = getColumnHeaderRenderer();
873         if (renderer instanceof Accessible)
874           {
875             Accessible ac = (Accessible) renderer;
876             return ac.getAccessibleContext().getAccessibleRole();
877           }
878         return null;
879       }
880
881       public AccessibleStateSet getAccessibleStateSet()
882       {
883         // TODO Auto-generated method stub
884         return null;
885       }
886
887       public int getAccessibleIndexInParent()
888       {
889         // TODO Auto-generated method stub
890         return 0;
891       }
892
893       public int getAccessibleChildrenCount()
894       {
895         // TODO Auto-generated method stub
896         return 0;
897       }
898
899       public Accessible getAccessibleChild(int i)
900       {
901         // TODO Auto-generated method stub
902         return null;
903       }
904
905       public Locale getLocale()
906       {
907         // TODO Auto-generated method stub
908         return null;
909       }
910
911       /**
912        * Returns the accessible context.
913        * 
914        * @return <code>this</code>.
915        */
916       public AccessibleContext getAccessibleContext()
917       {
918         return this;
919       }
920
921       public Color getBackground()
922       {
923         // TODO Auto-generated method stub
924         return null;
925       }
926
927       public void setBackground(Color color)
928       {
929         // TODO Auto-generated method stub
930         
931       }
932
933       public Color getForeground()
934       {
935         // TODO Auto-generated method stub
936         return null;
937       }
938
939       public void setForeground(Color color)
940       {
941         // TODO Auto-generated method stub
942         
943       }
944
945       public Cursor getCursor()
946       {
947         // TODO Auto-generated method stub
948         return null;
949       }
950
951       public void setCursor(Cursor cursor)
952       {
953         // TODO Auto-generated method stub
954         
955       }
956
957       public Font getFont()
958       {
959         // TODO Auto-generated method stub
960         return null;
961       }
962
963       public void setFont(Font font)
964       {
965         // TODO Auto-generated method stub
966         
967       }
968
969       public FontMetrics getFontMetrics(Font font)
970       {
971         // TODO Auto-generated method stub
972         return null;
973       }
974
975       public boolean isEnabled()
976       {
977         // TODO Auto-generated method stub
978         return false;
979       }
980
981       public void setEnabled(boolean b)
982       {
983         // TODO Auto-generated method stub
984         
985       }
986
987       public boolean isVisible()
988       {
989         // TODO Auto-generated method stub
990         return false;
991       }
992
993       public void setVisible(boolean b)
994       {
995         // TODO Auto-generated method stub
996         
997       }
998
999       public boolean isShowing()
1000       {
1001         // TODO Auto-generated method stub
1002         return false;
1003       }
1004
1005       public boolean contains(Point point)
1006       {
1007         // TODO Auto-generated method stub
1008         return false;
1009       }
1010
1011       public Point getLocationOnScreen()
1012       {
1013         // TODO Auto-generated method stub
1014         return null;
1015       }
1016
1017       public Point getLocation()
1018       {
1019         // TODO Auto-generated method stub
1020         return null;
1021       }
1022
1023       public void setLocation(Point point)
1024       {
1025         // TODO Auto-generated method stub
1026         
1027       }
1028
1029       public Rectangle getBounds()
1030       {
1031         // TODO Auto-generated method stub
1032         return null;
1033       }
1034
1035       public void setBounds(Rectangle rectangle)
1036       {
1037         // TODO Auto-generated method stub
1038         
1039       }
1040
1041       public Dimension getSize()
1042       {
1043         // TODO Auto-generated method stub
1044         return null;
1045       }
1046
1047       public void setSize(Dimension dimension)
1048       {
1049         // TODO Auto-generated method stub
1050         
1051       }
1052
1053       public Accessible getAccessibleAt(Point point)
1054       {
1055         // TODO Auto-generated method stub
1056         return null;
1057       }
1058
1059       public boolean isFocusTraversable()
1060       {
1061         // TODO Auto-generated method stub
1062         return false;
1063       }
1064
1065       public void requestFocus()
1066       {
1067         // TODO Auto-generated method stub
1068         
1069       }
1070
1071       public void addFocusListener(FocusListener listener)
1072       {
1073         // TODO Auto-generated method stub
1074         
1075       }
1076
1077       public void removeFocusListener(FocusListener listener)
1078       {
1079         // TODO Auto-generated method stub
1080         
1081       }
1082       
1083     }
1084
1085     /**
1086      * The last selected row. This is needed to track the selection in
1087      * {@link #valueChanged(ListSelectionEvent)}.
1088      */
1089     private int lastSelectedRow;
1090
1091     /**
1092      * The last selected column. This is needed to track the selection in
1093      * {@link #valueChanged(ListSelectionEvent)}.
1094      */
1095     private int lastSelectedColumn;
1096
1097     /**
1098      * The caption of the table.
1099      */
1100     private Accessible caption;
1101
1102     /**
1103      * The summary of the table.
1104      */
1105     private Accessible summary;
1106
1107     /**
1108      * Accessible descriptions for rows.
1109      */
1110     private Accessible[] rowDescriptions;
1111
1112     /**
1113      * Accessible descriptions for columns.
1114      */
1115     private Accessible[] columnDescriptions;
1116
1117     /**
1118      * Creates a new <code>AccessibleJTable</code>.
1119      *
1120      * @since JDK1.5
1121      */
1122     protected AccessibleJTable()
1123     {
1124       getModel().addTableModelListener(this);
1125       getSelectionModel().addListSelectionListener(this);
1126       getColumnModel().addColumnModelListener(this);
1127       lastSelectedRow = getSelectedRow();
1128       lastSelectedColumn = getSelectedColumn();
1129       TableCellEditor editor = getCellEditor();
1130       if (editor != null)
1131         editor.addCellEditorListener(this);
1132     }
1133
1134     /**
1135      * Returns the accessible role for the <code>JTable</code> component.
1136      *
1137      * @return {@link AccessibleRole#TABLE}.
1138      */
1139     public AccessibleRole getAccessibleRole()
1140     {
1141       return AccessibleRole.TABLE;
1142     }
1143     
1144     /**
1145      * Returns the accessible table.
1146      * 
1147      * @return <code>this</code>.
1148      */
1149     public AccessibleTable getAccessibleTable()
1150     {
1151       return this;
1152     }
1153     
1154     /**
1155      * Returns the number of selected items in this table.
1156      */
1157     public int getAccessibleSelectionCount()
1158     {
1159       return getSelectedColumnCount();
1160     }
1161
1162     /**
1163      * Returns the selected accessible object with the specified index
1164      * <code>i</code>. This basically returns the i-th selected cell in the
1165      * table when going though it row-wise, and inside the rows, column-wise.
1166      *
1167      * @param i the index of the selected object to find
1168      *
1169      * @return the selected accessible object with the specified index
1170      *         <code>i</code>
1171      */
1172     public Accessible getAccessibleSelection(int i)
1173     {
1174       Accessible found = null;
1175
1176       int[] selectedRows = getSelectedRows();
1177       int[] selectedColumns = getSelectedColumns();
1178       int numCols = getColumnCount();
1179       int numRows = getRowCount();
1180
1181       // We have to go through every selected row and column and count until we
1182       // find the specified index. This is potentially inefficient, but I can't
1183       // think of anything better atm.
1184       if (getRowSelectionAllowed() && getColumnSelectionAllowed())
1185         {
1186           int current = -1;
1187           int newIndex = current;
1188           int lastSelectedRow = -1;
1189           // Go through the selected rows array, don't forget the selected
1190           // cells inside the not-selected rows' columns.
1191           for (int j = 0; i < selectedRows.length; i++)
1192             {
1193               // Handle unselected rows between this selected and the last
1194               // selected row, if any.
1195               int selectedRow = selectedRows[j];
1196               int r = -1;
1197               int ci = -1;
1198               for (r = lastSelectedRow + 1;
1199                    r < selectedRow && current < i; r++)
1200                 {
1201                   for (ci = 0; ci < selectedColumns.length && current < i;
1202                        ci++)
1203                     {
1204                       current++;
1205                     }
1206                 }
1207               if (current == i)
1208                 {
1209                   // We found the cell in the above loops, now get out of here.
1210                   found = getAccessibleChild(r * numCols
1211                                              + selectedColumns[ci]);
1212                   break;
1213                 }
1214
1215               // If we're still here, handle the current selected row.
1216               if (current < i && current + numCols >= i)
1217                 {
1218                   // The cell must be in that row, which one is it?
1219                   found = getAccessibleChild(r * numCols + (i - current));
1220                   break;
1221                 }
1222               current += numCols;
1223             }
1224           if (found == null)
1225             {
1226               // The cell can still be in the last couple of unselected rows.
1227               int r = 0;
1228               int ci = 0;
1229               for (r = lastSelectedRow + 1;
1230                    r < numRows && current < i; r++)
1231                 {
1232                   for (ci = 0; ci < selectedColumns.length && current < i;
1233                        ci++)
1234                     {
1235                       current++;
1236                     }
1237                 }
1238               if (current == i)
1239                 {
1240                   // We found the cell in the above loops, now get out of here.
1241                   found = getAccessibleChild(r * numCols
1242                                              + selectedColumns[ci]);
1243                 }
1244             }
1245         }
1246       // One or more rows can be completely selected.
1247       else if (getRowSelectionAllowed())
1248         {
1249           int c = i % numCols;
1250           int r = selectedRows[i / numCols];
1251           found = getAccessibleChild(r * numCols + c);
1252         }
1253       // One or more columns can be completely selected.
1254       else if (getRowSelectionAllowed())
1255         {
1256           int numSelectedColumns = selectedColumns.length;
1257           int c = selectedColumns[i % numSelectedColumns];
1258           int r = i / numSelectedColumns;
1259           found = getAccessibleChild(r * numCols + c);
1260         }
1261
1262       return found;
1263     }
1264
1265     /**
1266      * Returns <code>true</code> if the accessible child with the index
1267      * <code>i</code> is selected, <code>false</code> otherwise.
1268      *
1269      * @param i the index of the accessible to check
1270      *
1271      * @return <code>true</code> if the accessible child with the index
1272      *         <code>i</code> is selected, <code>false</code> otherwise
1273      */
1274     public boolean isAccessibleChildSelected(int i)
1275     {
1276       int r = getAccessibleRowAtIndex(i);
1277       int c = getAccessibleColumnAtIndex(i);
1278       return isCellSelected(r, c);
1279     }
1280
1281     /**
1282      * Adds the accessible child with the specified index <code>i</code> to the
1283      * selection.
1284      *
1285      * @param i the index of the accessible child to add to the selection
1286      */
1287     public void addAccessibleSelection(int i)
1288     {
1289       int r = getAccessibleRowAtIndex(i);
1290       int c = getAccessibleColumnAtIndex(i);
1291       changeSelection(r, c, true, false);
1292     }
1293
1294     /**
1295      * Removes the accessible child with the specified index <code>i</code>
1296      * from the current selection. This will only work on tables that have
1297      * cell selection enabled (<code>rowSelectionAllowed == false &&
1298      * columnSelectionAllowed == false</code>).
1299      *
1300      * @param i the index of the accessible to be removed from the selection
1301      */
1302     public void removeAccessibleSelection(int i)
1303     {
1304       if (! getRowSelectionAllowed() && ! getColumnSelectionAllowed())
1305         {
1306           int r = getAccessibleRowAtIndex(i);
1307           int c = getAccessibleColumnAtIndex(i);
1308           removeRowSelectionInterval(r, r);
1309           removeColumnSelectionInterval(c, c);
1310         }
1311     }
1312
1313     /**
1314      * Deselects all selected accessible children.
1315      */
1316     public void clearAccessibleSelection()
1317     {
1318       clearSelection();
1319     }
1320
1321     /**
1322      * Selects all accessible children that can be selected. This will only
1323      * work on tables that support multiple selections and that have individual
1324      * cell selection enabled.
1325      */
1326     public void selectAllAccessibleSelection()
1327     {
1328       selectAll();
1329     }
1330
1331     /**
1332      * Receives notification when the row selection changes and fires
1333      * appropriate property change events.
1334      *
1335      * @param event the list selection event
1336      */
1337     public void valueChanged(ListSelectionEvent event)
1338     {
1339       firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
1340                          Boolean.FALSE, Boolean.TRUE);
1341       int r = getSelectedRow();
1342       int c = getSelectedColumn();
1343       if (r != lastSelectedRow || c != lastSelectedColumn)
1344         {
1345           Accessible o = getAccessibleAt(lastSelectedRow,
1346                                          lastSelectedColumn);
1347           Accessible n = getAccessibleAt(r, c);
1348           firePropertyChange(AccessibleContext
1349                              .ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY, o, n);
1350           lastSelectedRow = r;
1351           lastSelectedColumn = c;
1352         }
1353     }
1354
1355     /**
1356      * Receives notification when the table model changes. Depending on the
1357      * type of change, this method calls {@link #tableRowsInserted} or
1358      * {@link #tableRowsDeleted}.
1359      *
1360      * @param event the table model event
1361      */
1362     public void tableChanged(TableModelEvent event)
1363     {
1364       switch (event.getType())
1365         {
1366         case TableModelEvent.INSERT:
1367           tableRowsInserted(event);
1368           break;
1369         case TableModelEvent.DELETE:
1370           tableRowsDeleted(event);
1371           break;
1372         }
1373     }
1374
1375     /**
1376      * Receives notification when one or more rows have been inserted into the
1377      * table and fires appropriate property change events.
1378      *
1379      * @param event the table model event
1380      */
1381     public void tableRowsInserted(TableModelEvent event)
1382     {
1383       handleRowChange(event);
1384     }
1385
1386     /**
1387      * Receives notification when one or more rows have been deleted from the
1388      * table.
1389      *
1390      * @param event the table model event
1391      */
1392     public void tableRowsDeleted(TableModelEvent event)
1393     {
1394       handleRowChange(event);
1395     }
1396
1397     /**
1398      * Fires a PropertyChangeEvent for inserted or deleted rows.
1399      *
1400      * @param event the table model event
1401      */
1402     private void handleRowChange(TableModelEvent event)
1403     {
1404       firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1405                          null, null);
1406       int firstColumn = event.getColumn();
1407       int lastColumn = event.getColumn();
1408       if (firstColumn == TableModelEvent.ALL_COLUMNS)
1409         {
1410           firstColumn = 0;
1411           lastColumn = getColumnCount() - 1;
1412         }
1413       AccessibleJTableModelChange change = new AccessibleJTableModelChange
1414          (event.getType(), event.getFirstRow(), event.getLastRow(),
1415           firstColumn, lastColumn);
1416       firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
1417                          null, change);
1418     }
1419
1420     public void columnAdded(TableColumnModelEvent event)
1421     {
1422       firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1423                          null, null);
1424       handleColumnChange(AccessibleTableModelChange.INSERT,
1425                          event.getFromIndex(), event.getToIndex());
1426     }
1427
1428     public void columnRemoved(TableColumnModelEvent event)
1429     {
1430       firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1431                          null, null);
1432       handleColumnChange(AccessibleTableModelChange.DELETE,
1433                          event.getFromIndex(), event.getToIndex());
1434     }
1435
1436     public void columnMoved(TableColumnModelEvent event)
1437     {
1438       firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1439                          null, null);
1440       handleColumnChange(AccessibleTableModelChange.DELETE,
1441                          event.getFromIndex(), event.getFromIndex());
1442       handleColumnChange(AccessibleTableModelChange.INSERT,
1443                          event.getFromIndex(), event.getToIndex());
1444     }
1445
1446     /**
1447      * Fires a PropertyChangeEvent for inserted or deleted columns.
1448      *
1449      * @param type the type of change
1450      * @param from the start of the change
1451      * @param to the target of the change
1452      */
1453     private void handleColumnChange(int type, int from, int to)
1454     {
1455       AccessibleJTableModelChange change =
1456         new AccessibleJTableModelChange(type, 0, 0, from, to);
1457       firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
1458                          null, change);
1459     }
1460
1461     public void columnMarginChanged(ChangeEvent event)
1462     {
1463       firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1464                          null, null);
1465     }
1466
1467     public void columnSelectionChanged(ListSelectionEvent event)
1468     {
1469       // AFAICS, nothing is done here.
1470     }
1471
1472     public void editingCanceled(ChangeEvent event)
1473     {
1474       // AFAICS, nothing is done here.
1475     }
1476
1477     public void editingStopped(ChangeEvent event)
1478     {
1479       firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1480                          null, null);
1481     }
1482
1483     /**
1484      * Receives notification when any of the JTable's properties changes. This
1485      * is used to replace the listeners on the table's model, selection model,
1486      * column model and cell editor.
1487      *
1488      * @param e the property change event
1489      */
1490     public void propertyChange(PropertyChangeEvent e)
1491     {
1492       String propName = e.getPropertyName(); 
1493       if (propName.equals("tableModel"))
1494         {
1495           TableModel oldModel = (TableModel) e.getOldValue();
1496           oldModel.removeTableModelListener(this);
1497           TableModel newModel = (TableModel) e.getNewValue();
1498           newModel.addTableModelListener(this);
1499         }
1500       else if (propName.equals("columnModel"))
1501         {
1502           TableColumnModel oldModel = (TableColumnModel) e.getOldValue();
1503           oldModel.removeColumnModelListener(this);
1504           TableColumnModel newModel = (TableColumnModel) e.getNewValue();
1505           newModel.addColumnModelListener(this);
1506         }
1507       else if (propName.equals("selectionModel"))
1508         {
1509           ListSelectionModel oldModel = (ListSelectionModel) e.getOldValue();
1510           oldModel.removeListSelectionListener(this);
1511           ListSelectionModel newModel = (ListSelectionModel) e.getNewValue();
1512           newModel.addListSelectionListener(this);
1513         }
1514       else if (propName.equals("cellEditor"))
1515         {
1516           CellEditor oldEd = (CellEditor) e.getOldValue();
1517           oldEd.removeCellEditorListener(this);
1518           CellEditor newEd = (CellEditor) e.getNewValue();
1519           newEd.addCellEditorListener(this);
1520         }
1521     }
1522
1523     /**
1524      * Returns the row number of an accessible child (cell) with the specified
1525      * index.
1526      *
1527      * @param index the index of the cell of which the row number is queried
1528      * 
1529      * @return the row number of an accessible child (cell) with the specified
1530      *         index 
1531      */
1532     public int getAccessibleRow(int index)
1533     {
1534       return getAccessibleRowAtIndex(index);
1535     }
1536
1537     /**
1538      * Returns the column number of an accessible child (cell) with the
1539      * specified index.
1540      *
1541      * @param index the index of the cell of which the column number is queried
1542      * 
1543      * @return the column number of an accessible child (cell) with the
1544      *         specified index 
1545      */
1546     public int getAccessibleColumn(int index)
1547     {
1548       return getAccessibleColumnAtIndex(index);
1549     }
1550
1551     /**
1552      * Returns the index of the accessible child at the specified row and
1553      * column.
1554      *
1555      * @param r the row number
1556      * @param c the column number
1557      *
1558      * @return the index of the accessible child at the specified row and
1559      *         column
1560      */
1561     public int getAccessibleIndex(int r, int c)
1562     {
1563       return getAccessibleIndexAt(r, c);
1564     }
1565
1566     /**
1567      * Returns the caption of the table.
1568      *
1569      * @return the caption of the table
1570      *
1571      * @see #setAccessibleCaption(Accessible)
1572      */
1573     public Accessible getAccessibleCaption()
1574     {
1575       return caption;
1576     }
1577
1578     /**
1579      * Sets the caption for the table.
1580      *
1581      * @param c the caption to set
1582      */
1583     public void setAccessibleCaption(Accessible c)
1584     {
1585       caption = c;
1586     }
1587
1588     /**
1589      * Returns the summary for the table.
1590      *
1591      * @return the summary for the table
1592      */
1593     public Accessible getAccessibleSummary()
1594     {
1595       return summary;
1596     }
1597
1598     /**
1599      * Sets the summary for the table.
1600      *
1601      * @param s the summary to set
1602      */
1603     public void setAccessibleSummary(Accessible s)
1604     {
1605       summary = s;
1606     }
1607
1608     /**
1609      * Returns the number of rows in the table.
1610      *
1611      * @return the number of rows in the table
1612      */
1613     public int getAccessibleRowCount()
1614     {
1615       return getRowCount();
1616     }
1617
1618     /**
1619      * Returns the number of columns in the table.
1620      *
1621      * @return the number of columns in the table
1622      */
1623     public int getAccessibleColumnCount()
1624     {
1625       return getColumnCount();
1626     }
1627
1628     /**
1629      * Returns the accessible child at the given index.
1630      *
1631      * @param index  the child index.
1632      * 
1633      * @return The accessible child.
1634      */
1635     public Accessible getAccessibleChild(int index)
1636     {
1637       int r = getAccessibleRow(index);
1638       int c = getAccessibleColumn(index);
1639       return getAccessibleAt(r, c);  
1640     }
1641     
1642     /**
1643      * Returns the accessible child (table cell) at the specified row and
1644      * column.
1645      *
1646      * @param r the row number
1647      * @param c the column number
1648      *
1649      * @return the accessible child (table cell) at the specified row and
1650      *         column
1651      */
1652     public Accessible getAccessibleAt(int r, int c)
1653     {
1654       TableCellRenderer cellRenderer = getCellRenderer(r, c);
1655       Component renderer = cellRenderer.getTableCellRendererComponent(
1656           JTable.this, getValueAt(r, c), isCellSelected(r, c), false, r, c);
1657       if (renderer instanceof Accessible)
1658         return (Accessible) renderer;
1659       return null;
1660     }
1661
1662     /**
1663      * Returns the number of rows that the specified cell occupies. The
1664      * standard table cells only occupy one row, so we return <code>1</code>
1665      * here.
1666      *
1667      * @param r the row number
1668      * @param c the column number
1669      *
1670      * @return the number of rows that the specified cell occupies
1671      */
1672     public int getAccessibleRowExtentAt(int r, int c)
1673     {
1674       return 1;
1675     }
1676
1677     /**
1678      * Returns the number of columns that the specified cell occupies. The
1679      * standard table cells only occupy one column, so we return <code>1</code>
1680      * here.
1681      *
1682      * @param r the row number
1683      * @param c the column number
1684      *
1685      * @return the number of rows that the specified cell occupies
1686      */
1687     public int getAccessibleColumnExtentAt(int r, int c)
1688     {
1689       return 1;
1690     }
1691
1692     /**
1693      * Returns the accessible row header.
1694      *
1695      * @return the accessible row header
1696      */
1697     public AccessibleTable getAccessibleRowHeader()
1698     {
1699       // The RI seems to always return null here, so do we.
1700       return null;
1701     }
1702
1703     /**
1704      * Sets the accessible row header.
1705      *
1706      * @param header the header to set
1707      */
1708     public void setAccessibleRowHeader(AccessibleTable header)
1709     {
1710       // In the RI this seems to be a no-op.    
1711     }
1712
1713     /**
1714      * Returns the column header.
1715      *
1716      * @return the column header, or <code>null</code> if there is no column
1717      *         header
1718      */
1719     public AccessibleTable getAccessibleColumnHeader()
1720     {
1721       JTableHeader h = getTableHeader();
1722       AccessibleTable header = null;
1723       if (h != null)
1724         header = new AccessibleTableHeader(h);
1725       return header;
1726     }
1727
1728     /**
1729      * Sets the accessible column header. The default implementation doesn't
1730      * allow changing the header this way, so this is a no-op.
1731      *
1732      * @param header the accessible column header to set
1733      */
1734     public void setAccessibleColumnHeader(AccessibleTable header)
1735     {
1736       // The RI doesn't seem to do anything, so we also do nothing.
1737     }
1738
1739     /**
1740      * Returns the accessible description for the row with the specified index,
1741      * or <code>null</code> if no description has been set.
1742      *
1743      * @param r the row for which the description is queried
1744      *
1745      * @return the accessible description for the row with the specified index,
1746      *         or <code>null</code> if no description has been set
1747      */
1748     public Accessible getAccessibleRowDescription(int r)
1749     {
1750       Accessible descr = null;
1751       if (rowDescriptions != null)
1752         descr = rowDescriptions[r];
1753       return descr;
1754     }
1755
1756     /**
1757      * Sets the accessible description for the row with the specified index.
1758      *
1759      * @param r the row number for which to set the description
1760      * @param description the description to set
1761      */
1762     public void setAccessibleRowDescription(int r, Accessible description)
1763     {
1764       if (rowDescriptions == null)
1765         rowDescriptions = new Accessible[getAccessibleRowCount()];
1766       rowDescriptions[r] = description;
1767     }
1768
1769     /**
1770      * Returns the accessible description for the column with the specified
1771      * index, or <code>null</code> if no description has been set.
1772      *
1773      * @param c the column for which the description is queried
1774      *
1775      * @return the accessible description for the column with the specified
1776      *         index, or <code>null</code> if no description has been set
1777      */
1778     public Accessible getAccessibleColumnDescription(int c)
1779     {
1780       Accessible descr = null;
1781       if (columnDescriptions != null)
1782         descr = columnDescriptions[c];
1783       return descr;
1784     }
1785
1786     /**
1787      * Sets the accessible description for the column with the specified index.
1788      *
1789      * @param c the column number for which to set the description
1790      * @param description the description to set
1791      */
1792     public void setAccessibleColumnDescription(int c, Accessible description)
1793     {
1794       if (columnDescriptions == null)
1795         columnDescriptions = new Accessible[getAccessibleRowCount()];
1796       columnDescriptions[c] = description;
1797     }
1798
1799     /**
1800      * Returns <code>true</code> if the accessible child at the specified
1801      * row and column is selected, <code>false</code> otherwise.
1802      *
1803      * @param r the row number of the child
1804      * @param c the column number of the child
1805      *
1806      * @return <code>true</code> if the accessible child at the specified
1807      *         row and column is selected, <code>false</code> otherwise
1808      */
1809     public boolean isAccessibleSelected(int r, int c)
1810     {
1811       return isCellSelected(r, c);
1812     }
1813
1814     /**
1815      * Returns <code>true</code> if the row with the specified index is
1816      * selected, <code>false</code> otherwise.
1817      *
1818      * @param r the row number
1819      *
1820      * @return <code>true</code> if the row with the specified index is
1821      *        selected, <code>false</code> otherwise
1822      */
1823     public boolean isAccessibleRowSelected(int r)
1824     {
1825       return isRowSelected(r);
1826     }
1827
1828     /**
1829      * Returns <code>true</code> if the column with the specified index is
1830      * selected, <code>false</code> otherwise.
1831      *
1832      * @param c the column number
1833      *
1834      * @return <code>true</code> if the column with the specified index is
1835      *        selected, <code>false</code> otherwise
1836      */
1837     public boolean isAccessibleColumnSelected(int c)
1838     {
1839       return isColumnSelected(c);
1840     }
1841
1842     /**
1843      * Returns the indices of all selected rows.
1844      *
1845      * @return the indices of all selected rows
1846      */
1847     public int[] getSelectedAccessibleRows()
1848     {
1849       return getSelectedRows();
1850     }
1851
1852     /**
1853      * Returns the indices of all selected columns.
1854      *
1855      * @return the indices of all selected columns
1856      */
1857     public int[] getSelectedAccessibleColumns()
1858     {
1859       return getSelectedColumns();
1860     }
1861
1862     /**
1863      * Returns the accessible row at the specified index.
1864      *
1865      * @param index the index for which to query the row
1866      *
1867      * @return the row number at the specified table index
1868      */
1869     public int getAccessibleRowAtIndex(int index)
1870     {
1871       // TODO: Back this up by a Mauve test and update API docs accordingly.
1872       return index / getColumnCount();
1873     }
1874
1875     /**
1876      * Returns the accessible column at the specified index.
1877      *
1878      * @param index the index for which to query the column
1879      *
1880      * @return the column number at the specified table index
1881      */
1882     public int getAccessibleColumnAtIndex(int index)
1883     {
1884       // TODO: Back this up by a Mauve test and update API docs accordingly.
1885       return index % getColumnCount();
1886     }
1887
1888     /**
1889      * Returns the accessible child index at the specified column and row.
1890      *
1891      * @param row the row
1892      * @param column the column
1893      *
1894      * @return the index of the accessible child at the specified row and
1895      *         column
1896      */
1897     public int getAccessibleIndexAt(int row, int column)
1898     {
1899       // TODO: Back this up by a Mauve test and update API docs accordingly.
1900       return row * getColumnCount() + column;
1901     }
1902   }
1903   /**
1904    * Handles property changes from the <code>TableColumn</code>s of this
1905    * <code>JTable</code>.
1906    *
1907    * More specifically, this triggers a {@link #revalidate()} call if the
1908    * preferredWidth of one of the observed columns changes.
1909    */
1910   class TableColumnPropertyChangeHandler implements PropertyChangeListener
1911   {
1912     /**
1913      * Receives notification that a property of the observed TableColumns has
1914      * changed.
1915      * 
1916      * @param ev the property change event
1917      */
1918     public void propertyChange(PropertyChangeEvent ev)
1919     {
1920       if (ev.getPropertyName().equals("preferredWidth"))
1921         {
1922           JTableHeader header = getTableHeader();
1923           if (header != null)
1924             // Do nothing if the table is in the resizing mode.
1925             if (header.getResizingColumn() == null)
1926               {
1927                 TableColumn col = (TableColumn) ev.getSource();
1928                 header.setResizingColumn(col);
1929                 doLayout();
1930                 header.setResizingColumn(null);
1931               }
1932         }
1933     }
1934   }
1935
1936   /**
1937    * A cell renderer for boolean values.
1938    */
1939   private class BooleanCellRenderer
1940     extends DefaultTableCellRenderer
1941   {
1942     /**
1943      * The CheckBox that is used for rendering.
1944      */
1945     private final JCheckBox checkBox;
1946     
1947     /**
1948      * Creates a new checkbox based boolean cell renderer. The checkbox is
1949      * centered by default.
1950      */
1951     BooleanCellRenderer()
1952     {
1953        checkBox = new JCheckBox();
1954        checkBox.setHorizontalAlignment(SwingConstants.CENTER);
1955     }
1956    
1957     /**
1958      * Get the check box.
1959      */
1960     JCheckBox getCheckBox()
1961     {
1962       return checkBox;
1963     }
1964
1965     /**
1966      * Returns the component that is used for rendering the value.
1967      * 
1968      * @param table the JTable
1969      * @param value the value of the object
1970      * @param isSelected is the cell selected?
1971      * @param hasFocus has the cell the focus?
1972      * @param row the row to render
1973      * @param column the cell to render
1974      * @return this component (the default table cell renderer)
1975      */
1976     public Component getTableCellRendererComponent(JTable table, Object value,
1977                                                    boolean isSelected,
1978                                                    boolean hasFocus, int row,
1979                                                    int column)
1980     {
1981       if (isSelected)
1982         {
1983           checkBox.setBackground(table.getSelectionBackground());
1984           checkBox.setForeground(table.getSelectionForeground());
1985         }
1986       else
1987         {
1988           checkBox.setBackground(table.getBackground());
1989           checkBox.setForeground(table.getForeground());
1990         }
1991
1992       if (hasFocus)
1993         {
1994           checkBox.setBorder(
1995             UIManager.getBorder("Table.focusCellHighlightBorder"));
1996           if (table.isCellEditable(row, column))
1997             {
1998               checkBox.setBackground(
1999                 UIManager.getColor("Table.focusCellBackground"));
2000               checkBox.setForeground(
2001                 UIManager.getColor("Table.focusCellForeground"));
2002             }
2003         }
2004       else
2005         checkBox.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
2006
2007       // Null is rendered as false.
2008       if (value == null)
2009         checkBox.setSelected(false);
2010       else
2011         {
2012           Boolean boolValue = (Boolean) value;
2013           checkBox.setSelected(boolValue.booleanValue());
2014         }
2015       return checkBox;
2016     }
2017   }
2018
2019   /**
2020    * A cell renderer for Date values.
2021    */
2022   private class DateCellRenderer
2023     extends DefaultTableCellRenderer
2024   {
2025     /**
2026      * Returns the component that is used for rendering the value.
2027      *
2028      * @param table the JTable
2029      * @param value the value of the object
2030      * @param isSelected is the cell selected?
2031      * @param hasFocus has the cell the focus?
2032      * @param row the row to render
2033      * @param column the cell to render
2034      * 
2035      * @return this component (the default table cell renderer)
2036      */
2037     public Component getTableCellRendererComponent(JTable table, Object value,
2038                                                    boolean isSelected,
2039                                                    boolean hasFocus, int row,
2040                                                    int column)
2041     {
2042       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
2043                                           row, column);
2044       if (value instanceof Date)
2045         {
2046           Date dateValue = (Date) value;
2047           DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
2048           setText(df.format(dateValue));
2049         }
2050       return this;
2051     }
2052   }
2053
2054   /**
2055    * A cell renderer for Double values.
2056    */
2057   private class DoubleCellRenderer
2058     extends DefaultTableCellRenderer
2059   {
2060     /**
2061      * Creates a new instance of NumberCellRenderer.
2062      */
2063     public DoubleCellRenderer()
2064     {
2065       setHorizontalAlignment(JLabel.RIGHT);
2066     }
2067
2068     /**
2069      * Returns the component that is used for rendering the value.
2070      *
2071      * @param table the JTable
2072      * @param value the value of the object
2073      * @param isSelected is the cell selected?
2074      * @param hasFocus has the cell the focus?
2075      * @param row the row to render
2076      * @param column the cell to render
2077      * 
2078      * @return this component (the default table cell renderer)
2079      */
2080     public Component getTableCellRendererComponent(JTable table, Object value,
2081                                                    boolean isSelected,
2082                                                    boolean hasFocus, int row,
2083                                                    int column)
2084     {
2085       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
2086                                           row, column);
2087       if (value instanceof Double)
2088         {
2089           Double doubleValue = (Double) value;
2090           NumberFormat nf = NumberFormat.getInstance();
2091           setText(nf.format(doubleValue.doubleValue()));
2092         }
2093       return this;
2094     }
2095   }
2096
2097   /**
2098    * A cell renderer for Float values.
2099    */
2100   private class FloatCellRenderer
2101     extends DefaultTableCellRenderer
2102   {
2103     /**
2104      * Creates a new instance of NumberCellRenderer.
2105      */
2106     public FloatCellRenderer()
2107     {
2108       setHorizontalAlignment(JLabel.RIGHT);
2109     }
2110
2111     /**
2112      * Returns the component that is used for rendering the value.
2113      *
2114      * @param table the JTable
2115      * @param value the value of the object
2116      * @param isSelected is the cell selected?
2117      * @param hasFocus has the cell the focus?
2118      * @param row the row to render
2119      * @param column the cell to render
2120      * 
2121      * @return this component (the default table cell renderer)
2122      */
2123     public Component getTableCellRendererComponent(JTable table, Object value,
2124                                                    boolean isSelected,
2125                                                    boolean hasFocus, int row,
2126                                                    int column)
2127     {
2128       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
2129                                           row, column);
2130       if (value instanceof Float)
2131         {
2132           Float floatValue = (Float) value;
2133           NumberFormat nf = NumberFormat.getInstance();
2134           setText(nf.format(floatValue.floatValue()));
2135         }
2136       return this;
2137     }
2138   }
2139
2140   /**
2141    * A cell renderer for Number values.
2142    */
2143   private class NumberCellRenderer
2144     extends DefaultTableCellRenderer
2145   {
2146     /**
2147      * Creates a new instance of NumberCellRenderer.
2148      */
2149     public NumberCellRenderer()
2150     {
2151       setHorizontalAlignment(JLabel.RIGHT);
2152     }
2153   }
2154
2155   /**
2156    * A cell renderer for Icon values.
2157    */
2158   private class IconCellRenderer
2159     extends DefaultTableCellRenderer
2160   {
2161     IconCellRenderer()
2162     {
2163       setHorizontalAlignment(SwingConstants.CENTER);
2164     }
2165     
2166     
2167     /**
2168      * Returns the component that is used for rendering the value.
2169      *
2170      * @param table the JTable
2171      * @param value the value of the object
2172      * @param isSelected is the cell selected?
2173      * @param hasFocus has the cell the focus?
2174      * @param row the row to render
2175      * @param column the cell to render
2176      * 
2177      * @return this component (the default table cell renderer)
2178      */
2179     public Component getTableCellRendererComponent(JTable table, Object value,
2180                                                    boolean isSelected,
2181                                                    boolean hasFocus, int row,
2182                                                    int column)
2183     {
2184       super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
2185                                           row, column);
2186       if (value instanceof Icon)
2187         {
2188           Icon iconValue = (Icon) value;
2189           setIcon(iconValue);
2190         }
2191       else
2192         {
2193           setIcon(null);
2194         }
2195       setText("");
2196       return this;
2197     }
2198   }
2199   
2200     /**
2201      * The JTable text component (used in editing) always has the table
2202      * as its parent. The scrollRectToVisible must be adjusted taking the
2203      * relative component position.
2204      *
2205      * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
2206      */
2207     private class TableTextField extends JTextField
2208     {
2209       /**
2210        * Create the text field without the border.
2211        */
2212       TableTextField()
2213       {
2214         setBorder(BorderFactory.createLineBorder(getGridColor(), 2));
2215       }
2216     }    
2217   
2218
2219   private static final long serialVersionUID = 3876025080382781659L;
2220   
2221   /**
2222    * This table, for referring identically name methods from inner classes.
2223    */
2224   final JTable this_table = this;
2225
2226
2227   /**
2228    * When resizing columns, do not automatically change any columns. In this
2229    * case the table should be enclosed in a {@link JScrollPane} in order to
2230    * accomodate cases in which the table size exceeds its visible area.
2231    */
2232   public static final int AUTO_RESIZE_OFF = 0;
2233
2234   /**
2235    * When resizing column <code>i</code>, automatically change only the
2236    * single column <code>i+1</code> to provide or absorb excess space
2237    * requirements.
2238    */
2239   public static final int AUTO_RESIZE_NEXT_COLUMN = 1;
2240
2241   /**
2242    * When resizing column <code>i</code> in a table of <code>n</code>
2243    * columns, automatically change all columns in the range <code>[i+1,
2244    * n)</code>, uniformly, to provide or absorb excess space requirements.
2245    */
2246   public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
2247   
2248   /**
2249    * When resizing column <code>i</code> in a table of <code>n</code>
2250    * columns, automatically change all columns in the range <code>[0,
2251    * n)</code> (with the exception of column i) uniformly, to provide or
2252    * absorb excess space requirements.
2253    */
2254   public static final int AUTO_RESIZE_ALL_COLUMNS = 4;
2255
2256   /**
2257    * When resizing column <code>i</code> in a table of <code>n</code>
2258    * columns, automatically change column <code>n-1</code> (the last column
2259    * in the table) to provide or absorb excess space requirements.
2260    */
2261   public static final int AUTO_RESIZE_LAST_COLUMN = 3;
2262
2263   /**
2264    * A table mapping {@link java.lang.Class} objects to 
2265    * {@link TableCellEditor} objects. This table is consulted by the 
2266    * FIXME
2267    */
2268   protected Hashtable defaultEditorsByColumnClass = new Hashtable();
2269
2270   /**
2271    * A table mapping {@link java.lang.Class} objects to 
2272    * {@link TableCellEditor} objects. This table is consulted by the 
2273    * FIXME
2274    */
2275   protected Hashtable defaultRenderersByColumnClass = new Hashtable();
2276
2277   /**
2278    * The column that is edited, -1 if the table is not edited currently.
2279    */
2280   protected int editingColumn;
2281
2282   /**
2283    * The row that is edited, -1 if the table is not edited currently.
2284    */
2285   protected int editingRow;
2286
2287   /**
2288    * The component that is used for editing.
2289    * <code>null</code> if the table is not editing currently.
2290    *
2291    */
2292   protected transient Component editorComp;
2293
2294
2295   /**
2296    * Whether or not the table should automatically compute a matching
2297    * {@link TableColumnModel} and assign it to the {@link #columnModel}
2298    * property when the {@link #dataModel} property is changed. 
2299    *
2300    * @see #setModel(TableModel)
2301    * @see #createDefaultColumnsFromModel()
2302    * @see #setColumnModel(TableColumnModel)
2303    * @see #setAutoCreateColumnsFromModel(boolean)
2304    * @see #getAutoCreateColumnsFromModel()
2305    */
2306   protected boolean autoCreateColumnsFromModel;
2307
2308   /**
2309    * A numeric code specifying the resizing behavior of the table. Must be
2310    * one of {@link #AUTO_RESIZE_ALL_COLUMNS} (the default), {@link
2311    * #AUTO_RESIZE_LAST_COLUMN}, {@link #AUTO_RESIZE_NEXT_COLUMN}, {@link
2312    * #AUTO_RESIZE_SUBSEQUENT_COLUMNS}, or {@link #AUTO_RESIZE_OFF}.
2313    * 
2314    * @see #doLayout()
2315    * @see #setAutoResizeMode(int)
2316    * @see #getAutoResizeMode()
2317    */
2318   protected int autoResizeMode;
2319
2320   /**
2321    * The height in pixels of any row of the table. All rows in a table are
2322    * of uniform height. This differs from column width, which varies on a
2323    * per-column basis, and is stored in the individual columns of the
2324    * {@link #columnModel}.
2325    * 
2326    * @see #getRowHeight()
2327    * @see #setRowHeight(int)
2328    * @see TableColumn#getWidth()
2329    * @see TableColumn#setWidth(int)
2330    */
2331   protected int rowHeight;
2332
2333   /**
2334    * The height in pixels of the gap left between any two rows of the table. 
2335    * 
2336    * @see #setRowMargin(int)
2337    * @see #getRowHeight()
2338    * @see #getIntercellSpacing()
2339    * @see #setIntercellSpacing(Dimension)
2340    * @see TableColumnModel#getColumnMargin()
2341    * @see TableColumnModel#setColumnMargin(int)
2342    */
2343   protected int rowMargin;
2344
2345   /**
2346    * Whether or not the table should allow row selection. If the table
2347    * allows both row <em>and</em> column selection, it is said to allow
2348    * "cell selection". Previous versions of the JDK supported cell
2349    * selection as an independent concept, but it is now represented solely
2350    * in terms of simultaneous row and column selection.
2351    *
2352    * @see TableColumnModel#getColumnSelectionAllowed()
2353    * @see #setRowSelectionAllowed(boolean)
2354    * @see #getRowSelectionAllowed()
2355    * @see #getCellSelectionEnabled()
2356    * @see #setCellSelectionEnabled(boolean)
2357    */
2358   protected boolean rowSelectionAllowed;
2359
2360   /**
2361    * Obsolete. Use {@link #rowSelectionAllowed}, {@link 
2362    * #getColumnSelectionAllowed}, or the combined methods {@link
2363    * #getCellSelectionEnabled} and {@link #setCellSelectionEnabled(boolean)}.
2364    */
2365   protected boolean cellSelectionEnabled;
2366   
2367   /**
2368    * The model for data stored in the table. Confusingly, the published API
2369    * requires that this field be called <code>dataModel</code>, despite its
2370    * property name. The table listens to its model as a {@link
2371    * TableModelListener}.
2372    *
2373    * @see #tableChanged(TableModelEvent)
2374    * @see TableModel#addTableModelListener(TableModelListener)
2375    */
2376   protected TableModel dataModel;
2377
2378   /**
2379    * <p>A model of various aspects of the columns of the table, <em>not
2380    * including</em> the data stored in them. The {@link TableColumnModel}
2381    * is principally concerned with holding a set of {@link TableColumn}
2382    * objects, each of which describes the display parameters of a column
2383    * and the numeric index of the column from the data model which the
2384    * column is presenting.</p>
2385    *
2386    * <p>The TableColumnModel also contains a {@link ListSelectionModel} which
2387    * indicates which columns are currently selected. This selection model
2388    * works in combination with the {@link #selectionModel} of the table
2389    * itself to specify a <em>table selection</em>: a combination of row and
2390    * column selections.</p>
2391    *
2392    * <p>Most application programmers do not need to work with this property
2393    * at all: setting {@link #autoCreateColumnsFromModel} will construct the
2394    * columnModel automatically, and the table acts as a facade for most of
2395    * the interesting properties of the columnModel anyways.</p>
2396    * 
2397    * @see #setColumnModel(TableColumnModel)
2398    * @see #getColumnModel()
2399    */
2400   protected TableColumnModel columnModel;
2401
2402   /**
2403    * A model of the rows of this table which are currently selected. This
2404    * model is used in combination with the column selection model held as a
2405    * member of the {@link #columnModel} property, to represent the rows and
2406    * columns (or both: cells) of the table which are currently selected.
2407    *
2408    * @see #rowSelectionAllowed
2409    * @see #setSelectionModel(ListSelectionModel)
2410    * @see #getSelectionModel()
2411    * @see TableColumnModel#getSelectionModel()
2412    * @see ListSelectionModel#addListSelectionListener(ListSelectionListener)   
2413    */
2414   protected ListSelectionModel selectionModel;
2415
2416   /**
2417    * The current cell editor. 
2418    */
2419   protected TableCellEditor cellEditor;
2420
2421   /**
2422    * Whether or not drag-and-drop is enabled on this table.
2423    *
2424    * @see #setDragEnabled(boolean)
2425    * @see #getDragEnabled()
2426    */
2427   private boolean dragEnabled;
2428
2429   /**
2430    * The color to paint the grid lines of the table, when either {@link
2431    * #showHorizontalLines} or {@link #showVerticalLines} is set.
2432    *
2433    * @see #setGridColor(Color)
2434    * @see #getGridColor()
2435    */
2436   protected Color gridColor;
2437
2438   /**
2439    * The size this table would prefer its viewport assume, if it is
2440    * contained in a {@link JScrollPane}.
2441    *
2442    * @see #setPreferredScrollableViewportSize(Dimension)
2443    * @see #getPreferredScrollableViewportSize()
2444    */
2445   protected Dimension preferredViewportSize;
2446
2447   /**
2448    * The color to paint the background of selected cells. Fires a property
2449    * change event with name {@link #SELECTION_BACKGROUND_CHANGED_PROPERTY}
2450    * when its value changes.
2451    *
2452    * @see #setSelectionBackground(Color)
2453    * @see #getSelectionBackground()
2454    */
2455   protected Color selectionBackground;
2456
2457   /**
2458    * The name carried in property change events when the {@link
2459    * #selectionBackground} property changes.
2460    */
2461   private static final String SELECTION_BACKGROUND_CHANGED_PROPERTY = "selectionBackground";
2462
2463   /**
2464    * The color to paint the foreground of selected cells. Fires a property
2465    * change event with name {@link #SELECTION_FOREGROUND_CHANGED_PROPERTY}
2466    * when its value changes.
2467    *
2468    * @see #setSelectionForeground(Color)
2469    * @see #getSelectionForeground()
2470    */
2471   protected Color selectionForeground;
2472
2473   /**
2474    * The name carried in property change events when the
2475    * {@link #selectionForeground} property changes.
2476    */
2477   private static final String SELECTION_FOREGROUND_CHANGED_PROPERTY = "selectionForeground";
2478
2479   /**
2480    * The showHorizontalLines property.
2481    */
2482   protected boolean showHorizontalLines;
2483
2484   /**
2485    * The showVerticalLines property.
2486    */
2487   protected boolean showVerticalLines;
2488
2489   /**
2490    * The tableHeader property.
2491    */
2492   protected JTableHeader tableHeader;
2493
2494   /**
2495    * The property handler for this table's columns.
2496    */
2497   TableColumnPropertyChangeHandler tableColumnPropertyChangeHandler =
2498     new TableColumnPropertyChangeHandler();
2499
2500   /**
2501    * Whether cell editors should receive keyboard focus when the table is
2502    * activated.
2503    */
2504   private boolean surrendersFocusOnKeystroke = false;
2505
2506   /**
2507    * A Rectangle object to be reused in {@link #getCellRect}. 
2508    */
2509   private Rectangle rectCache = new Rectangle();
2510
2511   /**
2512    * Indicates if the rowHeight property has been set by a client program or by
2513    * the UI.
2514    *
2515    * @see #setUIProperty(String, Object)
2516    * @see LookAndFeel#installProperty(JComponent, String, Object)
2517    */
2518   private boolean clientRowHeightSet = false;
2519
2520   /**
2521    * Stores the sizes and positions of each row, when using non-uniform row
2522    * heights. Initially the height of all rows is equal and stored in
2523    * {link #rowHeight}. However, when an application calls
2524    * {@link #setRowHeight(int,int)}, the table switches to non-uniform
2525    * row height mode which stores the row heights in the SizeSequence
2526    * object instead.
2527    *
2528    * @see #setRowHeight(int)
2529    * @see #getRowHeight()
2530    * @see #getRowHeight(int)
2531    * @see #setRowHeight(int, int)
2532    */
2533   private SizeSequence rowHeights;
2534   
2535   /**
2536    * This editor serves just a marker that the value must be simply changed to
2537    * the opposite one instead of starting the editing session.
2538    */
2539   private transient TableCellEditor booleanInvertingEditor; 
2540   
2541   /**
2542    * Creates a new <code>JTable</code> instance.
2543    */
2544   public JTable ()
2545   {
2546     this(null, null, null);
2547   }
2548
2549   /**
2550    * Creates a new <code>JTable</code> instance with the given number
2551    * of rows and columns.
2552    *
2553    * @param numRows an <code>int</code> value
2554    * @param numColumns an <code>int</code> value
2555    */
2556   public JTable (int numRows, int numColumns)
2557   {
2558     this(new DefaultTableModel(numRows, numColumns));
2559   }
2560
2561   /**
2562    * Creates a new <code>JTable</code> instance, storing the given data 
2563    * array and heaving the given column names. To see the column names,
2564    * you must place the JTable into the {@link JScrollPane}.
2565    *
2566    * @param data an <code>Object[][]</code> the table data
2567    * @param columnNames an <code>Object[]</code> the column headers
2568    */
2569   public JTable(Object[][] data, Object[] columnNames)
2570   {
2571     this(new DefaultTableModel(data, columnNames));
2572   }
2573
2574   /**
2575    * Creates a new <code>JTable</code> instance, using the given data model
2576    * object that provides information about the table content. The table model
2577    * object is asked for the table size, other features and also receives
2578    * notifications in the case when the table has been edited by the user.
2579    * 
2580    * @param model
2581    *          the table model.
2582    */
2583   public JTable (TableModel model)
2584   {
2585     this(model, null, null);
2586   }
2587
2588   /**
2589    * Creates a new <code>JTable</code> instance, using the given model object
2590    * that provides information about the table content. The table data model
2591    * object is asked for the table size, other features and also receives
2592    * notifications in the case when the table has been edited by the user. The
2593    * table column model provides more detailed control on the table column
2594    * related features.
2595    * 
2596    * @param dm
2597    *          the table data mode
2598    * @param cm
2599    *          the table column model
2600    */
2601   public JTable (TableModel dm, TableColumnModel cm)
2602   {
2603     this(dm, cm, null);
2604   }
2605
2606   /**
2607    * Creates a new <code>JTable</code> instance, providing data model,
2608    * column model and list selection model. The list selection model
2609    * manages the selections.
2610    *
2611    * @param dm data model (manages table data)
2612    * @param cm column model (manages table columns)
2613    * @param sm list selection model (manages table selections)
2614    */
2615   public JTable (TableModel dm, TableColumnModel cm, ListSelectionModel sm)
2616   {
2617     boolean autoCreate = false;
2618     TableColumnModel columnModel;
2619     if (cm != null)
2620         columnModel = cm;
2621     else 
2622       {
2623         columnModel = createDefaultColumnModel();
2624         autoCreate = true;
2625       }
2626     
2627     // Initialise the intercelar spacing before setting the column model to
2628     // avoid firing unnecessary events.
2629     // The initial incellar spacing is new Dimenstion(1,1). 
2630     rowMargin = 1;
2631     columnModel.setColumnMargin(1);
2632     setColumnModel(columnModel);
2633     
2634     setSelectionModel(sm == null ? createDefaultSelectionModel() : sm);
2635     setModel(dm == null ? createDefaultDataModel() : dm);
2636     setAutoCreateColumnsFromModel(autoCreate);
2637     initializeLocalVars();
2638     
2639     // The following four lines properly set the lead selection indices.
2640     // After this, the UI will handle the lead selection indices.
2641     // FIXME: this should probably not be necessary, if the UI is installed
2642     // before the TableModel is set then the UI will handle things on its
2643     // own, but certain variables need to be set before the UI can be installed
2644     // so we must get the correct order for all the method calls in this
2645     // constructor.
2646     // These four lines are not needed.  A Mauve test that shows this is
2647     // gnu.testlet.javax.swing.JTable.constructors(linesNotNeeded).
2648     // selectionModel.setAnchorSelectionIndex(-1);
2649     // selectionModel.setLeadSelectionIndex(-1);
2650     // columnModel.getSelectionModel().setAnchorSelectionIndex(-1);
2651     // columnModel.getSelectionModel().setLeadSelectionIndex(-1);
2652     updateUI(); 
2653   }
2654   
2655   /**
2656    * Creates a new <code>JTable</code> instance that uses data and column
2657    * names, stored in {@link Vector}s.
2658    *
2659    * @param data the table data
2660    * @param columnNames the table column names.
2661    */
2662   public JTable(Vector data, Vector columnNames)
2663   {
2664     this(new DefaultTableModel(data, columnNames));
2665   }  
2666   
2667   /**
2668    * Initialize local variables to default values.
2669    */
2670   protected void initializeLocalVars()
2671   {
2672     setTableHeader(createDefaultTableHeader());
2673     if (autoCreateColumnsFromModel)
2674       createDefaultColumnsFromModel();
2675     this.columnModel.addColumnModelListener(this);
2676
2677     this.autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
2678     setRowHeight(16);
2679     this.rowMargin = 1;
2680     this.rowSelectionAllowed = true;
2681     
2682     // this.accessibleContext = new AccessibleJTable();
2683     this.cellEditor = null;
2684     
2685     // COMPAT: Both Sun and IBM have drag enabled
2686     this.dragEnabled = false;
2687     this.preferredViewportSize = new Dimension(450,400);
2688     this.showHorizontalLines = true;
2689     this.showVerticalLines = true;
2690     this.editingColumn = -1;
2691     this.editingRow = -1;
2692   }
2693   
2694   /**
2695    * Add the new table column. The table column class allows to specify column
2696    * features more precisely, setting the preferred width, column data type
2697    * (column class) and table headers.
2698    * 
2699    * There is no need the add columns to the table if the default column 
2700    * handling is sufficient.
2701    * 
2702    * @param column
2703    *          the new column to add.
2704    */
2705   public void addColumn(TableColumn column)
2706   {
2707     if (column.getHeaderValue() == null)
2708       {
2709         String name = dataModel.getColumnName(column.getModelIndex());
2710         column.setHeaderValue(name);
2711       }
2712     
2713     columnModel.addColumn(column);
2714     column.addPropertyChangeListener(tableColumnPropertyChangeHandler);
2715   }
2716   
2717   /**
2718    * Create the default editors for this table. The default method creates
2719    * the editor for Booleans.
2720    * 
2721    * Other fields are edited as strings at the moment.
2722    */
2723   protected void createDefaultEditors()
2724   {
2725     JCheckBox box = new BooleanCellRenderer().getCheckBox();
2726     box.setBorder(BorderFactory.createLineBorder(getGridColor(), 2));
2727     box.setBorderPainted(true);
2728     booleanInvertingEditor = new DefaultCellEditor(box);    
2729     setDefaultEditor(Boolean.class, booleanInvertingEditor);
2730   }
2731   
2732   /**
2733    * Create the default renderers for this table. The default method creates
2734    * renderers for Boolean, Number, Double, Date, Icon and ImageIcon.
2735    *
2736    */
2737   protected void createDefaultRenderers()
2738   {
2739     setDefaultRenderer(Boolean.class, new BooleanCellRenderer());
2740     setDefaultRenderer(Number.class, new NumberCellRenderer());
2741     setDefaultRenderer(Double.class, new DoubleCellRenderer());
2742     setDefaultRenderer(Double.class, new FloatCellRenderer());
2743     setDefaultRenderer(Date.class, new DateCellRenderer());
2744     setDefaultRenderer(Icon.class, new IconCellRenderer());
2745     setDefaultRenderer(ImageIcon.class, new IconCellRenderer());    
2746   }
2747   
2748   /**
2749    * @deprecated 1.0.2, replaced by <code>new JScrollPane(JTable)</code>
2750    */
2751   public static JScrollPane createScrollPaneForTable(JTable table)
2752   {
2753     return new JScrollPane(table);
2754   }
2755   
2756   /**
2757    * Create the default table column model that is used if the user-defined
2758    * column model is not provided. The default method creates
2759    * {@link DefaultTableColumnModel}.
2760    * 
2761    * @return the created table column model.
2762    */
2763   protected TableColumnModel createDefaultColumnModel()
2764   {
2765     return new DefaultTableColumnModel();
2766   }
2767
2768   /**
2769    * Create the default table data model that is used if the user-defined
2770    * data model is not provided. The default method creates
2771    * {@link DefaultTableModel}.
2772    * 
2773    * @return the created table data model.
2774    */
2775   protected TableModel createDefaultDataModel()
2776   {
2777     return new DefaultTableModel();
2778   }
2779
2780   /**
2781    * Create the default table selection model that is used if the user-defined
2782    * selection model is not provided. The default method creates
2783    * {@link DefaultListSelectionModel}.
2784    * 
2785    * @return the created table data model.
2786    */
2787   protected ListSelectionModel createDefaultSelectionModel()
2788   {
2789     return new DefaultListSelectionModel();
2790   }
2791   
2792   /**
2793    * Create the default table header, if the user - defined table header is not
2794    * provided.
2795    * 
2796    * @return the default table header.
2797    */
2798   protected JTableHeader createDefaultTableHeader()
2799   {
2800     return new JTableHeader(columnModel);
2801   }
2802   
2803   /**
2804    * Invoked when the column is added. Revalidates and repains the table.
2805    */
2806   public void columnAdded (TableColumnModelEvent event)
2807   {
2808     revalidate();
2809     repaint();
2810   }
2811
2812   /**
2813    * Invoked when the column margin is changed. 
2814    * Revalidates and repains the table.
2815    */
2816   public void columnMarginChanged (ChangeEvent event)
2817   {
2818     revalidate();
2819     repaint();
2820   }
2821
2822   /**
2823    * Invoked when the column is moved. Revalidates and repains the table.
2824    */
2825   public void columnMoved (TableColumnModelEvent event)
2826   {
2827     if (isEditing())
2828       editingCanceled(null);
2829     revalidate();
2830     repaint();
2831   }
2832
2833   /**
2834    * Invoked when the column is removed. Revalidates and repains the table.
2835    */
2836   public void columnRemoved (TableColumnModelEvent event)
2837   {
2838     revalidate();
2839     repaint();
2840   }
2841   
2842   /**
2843    * Invoked when the the column selection changes, repaints the changed
2844    * columns. It is not recommended to override this method, register the
2845    * listener instead.
2846    */
2847   public void columnSelectionChanged (ListSelectionEvent event)
2848   {
2849     // We must limit the indices to the bounds of the JTable's model, because
2850     // we might get values of -1 or greater then columnCount in the case
2851     // when columns get removed.
2852     int idx0 = Math.max(0, Math.min(getColumnCount() - 1,
2853                                     event.getFirstIndex()));
2854     int idxn = Math.max(0, Math.min(getColumnCount() - 1,
2855                                     event.getLastIndex()));
2856
2857     int minRow = 0;
2858     int maxRow = getRowCount() - 1;
2859     if (getRowSelectionAllowed())
2860       {
2861         minRow = selectionModel.getMinSelectionIndex();
2862         maxRow = selectionModel.getMaxSelectionIndex();
2863         int leadRow = selectionModel.getLeadSelectionIndex();
2864         if (minRow == -1 && maxRow == -1)
2865           {
2866             minRow = leadRow;
2867             maxRow = leadRow;
2868           }
2869         else
2870           {
2871             // In this case we need to repaint also the range to leadRow, not
2872             // only between min and max.
2873             if (leadRow != -1)
2874               {
2875                 minRow = Math.min(minRow, leadRow);
2876                 maxRow = Math.max(maxRow, leadRow);
2877               }
2878           }
2879       }
2880     if (minRow != -1 && maxRow != -1)
2881       {
2882         Rectangle first = getCellRect(minRow, idx0, false);
2883         Rectangle last = getCellRect(maxRow, idxn, false);
2884         Rectangle dirty = SwingUtilities.computeUnion(first.x, first.y,
2885                                                       first.width,
2886                                                       first.height, last);
2887         repaint(dirty);
2888       }
2889   }
2890  
2891   /**
2892    * Invoked when the editing is cancelled.
2893    */
2894   public void editingCanceled (ChangeEvent event)
2895   {
2896     if (editorComp!=null)
2897       {
2898         remove(editorComp);
2899         repaint(editorComp.getBounds());        
2900         editorComp = null;
2901       }
2902   }
2903   
2904   /**
2905    * Finish the current editing session and update the table with the
2906    * new value by calling {@link #setValueAt}.
2907    * 
2908    * @param event the change event
2909    */
2910   public void editingStopped (ChangeEvent event)
2911   {
2912     if (editorComp!=null)
2913       {
2914         remove(editorComp);        
2915         setValueAt(cellEditor.getCellEditorValue(), editingRow, editingColumn);            
2916         repaint(editorComp.getBounds());
2917         editorComp = null;
2918       }
2919     requestFocusInWindow();
2920   }
2921
2922   /**
2923    * Invoked when the table changes.
2924    * <code>null</code> means everything changed.
2925    */
2926   public void tableChanged (TableModelEvent event)
2927   {
2928     // update the column model from the table model if the structure has
2929     // changed and the flag autoCreateColumnsFromModel is set
2930     if (event == null || (event.getFirstRow() == TableModelEvent.HEADER_ROW))
2931       handleCompleteChange(event);
2932     else if (event.getType() == TableModelEvent.INSERT)
2933       handleInsert(event);
2934     else if (event.getType() == TableModelEvent.DELETE)
2935       handleDelete(event);
2936     else
2937       handleUpdate(event);
2938   }
2939
2940   /**
2941    * Handles a request for complete relayout. This is the case when
2942    * event.getFirstRow() == TableModelEvent.HEADER_ROW.
2943    *
2944    * @param ev the table model event
2945    */
2946   private void handleCompleteChange(TableModelEvent ev)
2947   {
2948     clearSelection();
2949     checkSelection();
2950     rowHeights = null;
2951     if (getAutoCreateColumnsFromModel())
2952       createDefaultColumnsFromModel();
2953     else
2954       resizeAndRepaint();
2955   }
2956
2957   /**
2958    * Handles table model insertions.
2959    *
2960    * @param ev the table model event
2961    */
2962   private void handleInsert(TableModelEvent ev)
2963   {
2964     // Sync selection model with data model.
2965     int first = ev.getFirstRow();
2966     if (first < 0)
2967       first = 0;
2968     int last = ev.getLastRow();
2969     if (last < 0)
2970       last = getRowCount() - 1;
2971     selectionModel.insertIndexInterval(first, last - first + 1, true);
2972     checkSelection();
2973
2974     // For variable height rows we must update the SizeSequence thing.
2975     if (rowHeights != null)
2976       {
2977         rowHeights.insertEntries(first, last - first + 1, rowHeight);
2978         // TODO: We repaint the whole thing when the rows have variable
2979         // heights. We might want to handle this better though.
2980         repaint();
2981       }
2982     else
2983       {
2984         // Repaint the dirty region and revalidate.
2985         int rowHeight = getRowHeight();
2986         Rectangle dirty = new Rectangle(0, first * rowHeight,
2987                                         getColumnModel().getTotalColumnWidth(),
2988                                         (getRowCount() - first) * rowHeight);
2989         repaint(dirty);
2990       }
2991     revalidate();
2992   }
2993
2994   /**
2995    * Handles table model deletions.
2996    *
2997    * @param ev the table model event
2998    */
2999   private void handleDelete(TableModelEvent ev)
3000   {
3001     // Sync selection model with data model.
3002     int first = ev.getFirstRow();
3003     if (first < 0)
3004       first = 0;
3005     int last = ev.getLastRow();
3006     if (last < 0)
3007       last = getRowCount() - 1;
3008
3009     selectionModel.removeIndexInterval(first, last);
3010
3011     checkSelection();
3012
3013     if (dataModel.getRowCount() == 0)
3014       clearSelection();
3015
3016     // For variable height rows we must update the SizeSequence thing.
3017     if (rowHeights != null)
3018       {
3019         rowHeights.removeEntries(first, last - first + 1);
3020         // TODO: We repaint the whole thing when the rows have variable
3021         // heights. We might want to handle this better though.
3022         repaint();
3023       }
3024     else
3025       {
3026         // Repaint the dirty region and revalidate.
3027         int rowHeight = getRowHeight();
3028         int oldRowCount = getRowCount() + last - first + 1;
3029         Rectangle dirty = new Rectangle(0, first * rowHeight,
3030                                         getColumnModel().getTotalColumnWidth(),
3031                                         (oldRowCount - first) * rowHeight);
3032         repaint(dirty);
3033       }
3034     revalidate();
3035   }
3036
3037   /**
3038    * Handles table model updates without structural changes.
3039    *
3040    * @param ev the table model event
3041    */
3042   private void handleUpdate(TableModelEvent ev)
3043   {
3044     if (rowHeights == null)
3045       {
3046         // Some cells have been changed without changing the structure.
3047         // Figure out the dirty rectangle and repaint.
3048         int firstRow = ev.getFirstRow();
3049         int lastRow = ev.getLastRow();
3050         int col = ev.getColumn();
3051         Rectangle dirty;
3052         if (col == TableModelEvent.ALL_COLUMNS)
3053           {
3054             // All columns changed. 
3055             dirty = new Rectangle(0, firstRow * getRowHeight(),
3056                                   getColumnModel().getTotalColumnWidth(), 0);
3057           }
3058         else
3059           {
3060             // Only one cell or column of cells changed.
3061             // We need to convert to view column first.
3062             int column = convertColumnIndexToModel(col);
3063             dirty = getCellRect(firstRow, column, false);
3064           }
3065
3066         // Now adjust the height of the dirty region.
3067         dirty.height = (lastRow + 1) * getRowHeight();
3068         // .. and repaint.
3069         repaint(dirty);
3070       }
3071     else
3072       {
3073         // TODO: We repaint the whole thing when the rows have variable
3074         // heights. We might want to handle this better though.
3075         repaint();
3076       }
3077   }
3078
3079   /**
3080    * Helper method for adjusting the lead and anchor indices when the
3081    * table structure changed. This sets the lead and anchor to -1 if there's
3082    * no more rows, or set them to 0 when they were at -1 and there are actually
3083    * some rows now.
3084    */
3085   private void checkSelection()
3086   {
3087     TableModel m = getModel();
3088     ListSelectionModel sm = selectionModel;
3089     if (m != null)
3090       {
3091         int lead = sm.getLeadSelectionIndex();
3092         int c = m.getRowCount();
3093         if (c == 0 && lead != -1)
3094           {
3095             // No rows in the model, reset lead and anchor to -1.
3096             sm.setValueIsAdjusting(true);
3097             sm.setAnchorSelectionIndex(-1);
3098             sm.setLeadSelectionIndex(-1);
3099             sm.setValueIsAdjusting(false);
3100           }
3101         else if (c != 0 && lead == -1)
3102           {
3103             // We have rows, but no lead/anchor. Set them to 0. We
3104             // do a little trick here so that the actual selection is not
3105             // touched.
3106             if (sm.isSelectedIndex(0))
3107               sm.addSelectionInterval(0, 0);
3108             else
3109               sm.removeSelectionInterval(0, 0);
3110           }
3111         // Nothing to do in the other cases.
3112       }
3113   }
3114
3115   /**
3116    * Invoked when another table row is selected. It is not recommended
3117    * to override thid method, register the listener instead.
3118    */
3119   public void valueChanged (ListSelectionEvent event)
3120   {
3121     // If we are in the editing process, end the editing session.
3122     if (isEditing())
3123       editingStopped(null);
3124     
3125     // Repaint the changed region.
3126     int first = Math.max(0, Math.min(getRowCount() - 1, event.getFirstIndex()));
3127     int last = Math.max(0, Math.min(getRowCount() - 1, event.getLastIndex()));
3128     Rectangle rect1 = getCellRect(first, 0, false);
3129     Rectangle rect2 = getCellRect(last, getColumnCount() - 1, false);
3130     Rectangle dirty = SwingUtilities.computeUnion(rect2.x, rect2.y,
3131                                                   rect2.width, rect2.height,
3132                                                   rect1);
3133     repaint(dirty);
3134   }
3135
3136  /**
3137    * Returns index of the column that contains specified point 
3138    * or -1 if this table doesn't contain this point.
3139    *
3140    * @param point point to identify the column
3141    * @return index of the column that contains specified point or 
3142    * -1 if this table doesn't contain this point.
3143    */
3144   public int columnAtPoint(Point point)
3145   {
3146     int ncols = getColumnCount();
3147     Dimension gap = getIntercellSpacing();
3148     TableColumnModel cols = getColumnModel();
3149     int x = point.x;
3150
3151     for (int i = 0; i < ncols; ++i)
3152       {
3153         int width = cols.getColumn(i).getWidth()
3154                     + (gap == null ? 0 : gap.width);
3155         if (0 <= x && x < width)
3156           return i;
3157         x -= width;
3158       }
3159     return -1;
3160   }
3161
3162   /**
3163    * Returns index of the row that contains specified point or -1 if this table
3164    * doesn't contain this point.
3165    * 
3166    * @param point point to identify the row
3167    * @return index of the row that contains specified point or -1 if this table
3168    *         doesn't contain this point.
3169    */
3170   public int rowAtPoint(Point point)
3171   {
3172     if (point != null)
3173       {
3174         int nrows = getRowCount();
3175         int r;
3176         int y = point.y;
3177         if (rowHeights == null)
3178           {
3179             int height = getRowHeight();
3180             r = y / height;
3181           }
3182         else
3183           r = rowHeights.getIndex(y);
3184
3185         if (r < 0 || r >= nrows)
3186           return -1;
3187         else
3188           return r;
3189       }
3190     else
3191       return -1;
3192   }
3193
3194   /** 
3195    * Calculate the visible rectangle for a particular row and column. The
3196    * row and column are specified in visual terms; the column may not match
3197    * the {@link #dataModel} column.
3198    *
3199    * @param row the visible row to get the cell rectangle of
3200    *
3201    * @param column the visible column to get the cell rectangle of, which may
3202    * differ from the {@link #dataModel} column
3203    *
3204    * @param includeSpacing whether or not to include the cell margins in the
3205    * resulting cell. If <code>false</code>, the result will only contain the
3206    * inner area of the target cell, not including its margins.
3207    *
3208    * @return a rectangle enclosing the specified cell
3209    */
3210   public Rectangle getCellRect(int row,
3211                                int column,
3212                                boolean includeSpacing)
3213   {
3214     Rectangle cellRect = new Rectangle(0, 0, 0, 0);
3215
3216     // Check for valid range vertically.
3217     if (row >= getRowCount())
3218       {
3219         cellRect.height = getHeight();
3220       }
3221     else if (row >= 0)
3222       {
3223         cellRect.height = getRowHeight(row);
3224         if (rowHeights == null)
3225           cellRect.y = row * cellRect.height;
3226         else
3227           cellRect.y = rowHeights.getPosition(row);
3228
3229         if (! includeSpacing)
3230           {
3231             // The rounding here is important.
3232             int rMargin = getRowMargin();
3233             cellRect.y += rMargin / 2;
3234             cellRect.height -= rMargin;
3235           }
3236       }
3237     // else row < 0, y = height = 0
3238
3239     // Check for valid range horizontally.
3240     if (column < 0)
3241       {
3242         if (! getComponentOrientation().isLeftToRight())
3243           {
3244             cellRect.x = getWidth();
3245           }
3246       }
3247     else if (column >= getColumnCount())
3248       {
3249         if (getComponentOrientation().isLeftToRight())
3250           {
3251             cellRect.x = getWidth();
3252           }
3253       }
3254     else
3255       {
3256         TableColumnModel tcm = getColumnModel();
3257         if (getComponentOrientation().isLeftToRight())
3258           {
3259             for (int i = 0; i < column; i++)
3260               cellRect.x += tcm.getColumn(i).getWidth();
3261           }
3262         else
3263           {
3264             for (int i = tcm.getColumnCount() - 1; i > column; i--)
3265               cellRect.x += tcm.getColumn(i).getWidth();
3266           }
3267         cellRect.width = tcm.getColumn(column).getWidth();
3268         if (! includeSpacing)
3269           {
3270             // The rounding here is important.
3271             int cMargin = tcm.getColumnMargin();
3272             cellRect.x += cMargin / 2;
3273             cellRect.width -= cMargin;
3274           }
3275       } 
3276
3277     return cellRect;
3278   }
3279
3280   public void clearSelection()
3281   {
3282     selectionModel.clearSelection();
3283     getColumnModel().getSelectionModel().clearSelection();
3284   }
3285
3286   /**
3287    * Get the value of the selectedRow property by delegation to
3288    * the {@link ListSelectionModel#getMinSelectionIndex} method of the
3289    * {@link #selectionModel} field.
3290    *
3291    * @return The current value of the selectedRow property
3292    */
3293   public int getSelectedRow ()
3294   {    
3295     return selectionModel.getMinSelectionIndex();
3296   }
3297   
3298   /**
3299    * Get the value of the {@link #selectionModel} property.
3300    *
3301    * @return The current value of the property
3302    */
3303   public ListSelectionModel getSelectionModel()
3304   {
3305     //Neither Sun nor IBM returns null if rowSelection not allowed
3306     return selectionModel;
3307   }
3308   
3309   public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)
3310   {
3311     int block;
3312     if (orientation == SwingConstants.HORIZONTAL)
3313       {
3314         block = visibleRect.width;
3315       }
3316     else
3317       {
3318         int rowHeight = getRowHeight();
3319         if (rowHeight > 0)
3320           block = Math.max(rowHeight, // Little hack for useful rounding.
3321                            (visibleRect.height / rowHeight) * rowHeight);
3322         else
3323           block = visibleRect.height;
3324       }
3325     return block;
3326   }
3327
3328   /**
3329    * Get the value of the <code>scrollableTracksViewportHeight</code> property.
3330    *
3331    * @return The constant value <code>false</code>
3332    */
3333   public boolean getScrollableTracksViewportHeight()
3334   {
3335     return false;
3336   }
3337   
3338   /**
3339    * Get the value of the <code>scrollableTracksViewportWidth</code> property.
3340    *
3341    * @return <code>true</code> unless the {@link #autoResizeMode} property is
3342    * <code>AUTO_RESIZE_OFF</code>
3343    */
3344   public boolean getScrollableTracksViewportWidth()
3345   {
3346     if (autoResizeMode == AUTO_RESIZE_OFF)
3347       return false;
3348     else
3349       return true;
3350   }
3351   
3352   /**
3353    * Return the preferred scrolling amount (in pixels) for the given scrolling
3354    * direction and orientation. This method handles a partially exposed row by
3355    * returning the distance required to completely expose the item. When
3356    * scrolling the top item is completely exposed.
3357    * 
3358    * @param visibleRect the currently visible part of the component.
3359    * @param orientation the scrolling orientation
3360    * @param direction the scrolling direction (negative - up, positive -down).
3361    *          The values greater than one means that more mouse wheel or similar
3362    *          events were generated, and hence it is better to scroll the longer
3363    *          distance.
3364    *          
3365    * @author Roman Kennke (kennke@aicas.com)
3366    */
3367   public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
3368                                         int direction)
3369   {
3370     int unit;
3371     if (orientation == SwingConstants.HORIZONTAL)
3372       unit = 100;
3373     else
3374       {
3375         unit = getRowHeight();
3376         // The following adjustment doesn't work for variable height rows.
3377         // It fully exposes partially visible rows in the scrolling direction.
3378         if (rowHeights == null)
3379           {
3380             if (direction > 0)
3381               {
3382                 // Scroll down.
3383                 // How much pixles are exposed from the last item?
3384                 int exposed = (visibleRect.y + visibleRect.height) % unit;
3385                 if (exposed > 0 && exposed < unit - 1)
3386                   unit = unit - exposed - 1;
3387               }
3388             else
3389               {
3390                 // Scroll up.
3391                 int exposed = visibleRect.y % unit;
3392                 if (exposed > 0 && exposed < unit)
3393                   unit = exposed;
3394               }
3395           }
3396       }
3397     return unit;
3398   }
3399
3400   /**
3401    * Get the cell editor, suitable for editing the given cell. The default
3402    * method requests the editor from the column model. If the column model does
3403    * not provide the editor, the call is forwarded to the
3404    * {@link #getDefaultEditor(Class)} with the parameter, obtained from
3405    * {@link TableModel#getColumnClass(int)}.
3406    * 
3407    * @param row the cell row
3408    * @param column the cell column
3409    * @return the editor to edit that cell
3410    */
3411   public TableCellEditor getCellEditor(int row, int column)
3412   {
3413     TableCellEditor editor = columnModel.getColumn(column).getCellEditor();
3414
3415     if (editor == null)
3416       {
3417         int mcolumn = convertColumnIndexToModel(column);
3418         editor = getDefaultEditor(dataModel.getColumnClass(mcolumn));
3419       }
3420
3421     return editor;
3422   }
3423   
3424   /**
3425    * Get the default editor for editing values of the given type
3426    * (String, Boolean and so on).
3427    * 
3428    * @param columnClass the class of the value that will be edited.
3429    * 
3430    * @return the editor, suitable for editing this data type
3431    */
3432   public TableCellEditor getDefaultEditor(Class<?> columnClass)
3433   {
3434     if (defaultEditorsByColumnClass.containsKey(columnClass))
3435       return (TableCellEditor) defaultEditorsByColumnClass.get(columnClass);
3436     else
3437       {
3438         JTextField t = new TableTextField();        
3439         TableCellEditor r = new DefaultCellEditor(t);
3440         defaultEditorsByColumnClass.put(columnClass, r);
3441         return r;
3442       }
3443   }
3444
3445   /**
3446    * Get the cell renderer for rendering the given cell.
3447    * 
3448    * @param row the cell row
3449    * @param column the cell column
3450    * @return the cell renderer to render that cell.
3451    */
3452   public TableCellRenderer getCellRenderer(int row, int column)
3453   {
3454     TableCellRenderer renderer = null;
3455     if (columnModel.getColumnCount() > 0)
3456       renderer = columnModel.getColumn(column).getCellRenderer();
3457     if (renderer == null)
3458       {
3459         int mcolumn = convertColumnIndexToModel(column);
3460         renderer = getDefaultRenderer(dataModel.getColumnClass(mcolumn));
3461       }
3462     return renderer;
3463   }
3464
3465   /**
3466    * Set default renderer for rendering the given data type.
3467    * 
3468    * @param columnClass the data type (String, Boolean and so on) that must be
3469    *          rendered.
3470    * @param rend the renderer that will rend this data type
3471    */
3472   public void setDefaultRenderer(Class<?> columnClass, TableCellRenderer rend)
3473   {
3474     defaultRenderersByColumnClass.put(columnClass, rend);
3475   }
3476
3477   /**
3478    * Get the default renderer for rendering the given data type.
3479    * 
3480    * @param columnClass the data that must be rendered
3481    * 
3482    * @return the appropriate defauld renderer for rendering that data type.
3483    */
3484   public TableCellRenderer getDefaultRenderer(Class<?> columnClass)
3485   {
3486     if (defaultRenderersByColumnClass.containsKey(columnClass))
3487       return (TableCellRenderer) defaultRenderersByColumnClass.get(columnClass);
3488     else
3489       {
3490         TableCellRenderer r = new DefaultTableCellRenderer();
3491         defaultRenderersByColumnClass.put(columnClass, r);
3492         return r;
3493       }
3494   }
3495   
3496   /**
3497    * Convert the table model index into the table column number.
3498    * The model number need not match the real column position. The columns
3499    * may be rearranged by the user with mouse at any time by dragging the
3500    * column headers.
3501    *
3502    * @param vc the column number (0=first).
3503    * 
3504    * @return the table column model index of this column.
3505    * 
3506    * @see TableColumn#getModelIndex()
3507    */
3508   public int convertColumnIndexToModel(int vc)
3509   {
3510     if (vc < 0)
3511       return vc;
3512     else
3513       return columnModel.getColumn(vc).getModelIndex();
3514   }
3515   
3516   /**
3517    * Convert the table column number to the table column model index.
3518    * The model number need not match the real column position. The columns
3519    * may be rearranged by the user with mouse at any time by dragging the
3520    * column headers.
3521    *  
3522    * @param mc the table column index (0=first).
3523    * 
3524    * @return the table column number in the model
3525    * 
3526    * @see TableColumn#getModelIndex() 
3527    */
3528   public int convertColumnIndexToView(int mc)
3529   {
3530     if (mc < 0)
3531       return mc;
3532     int ncols = getColumnCount();
3533     for (int vc = 0; vc < ncols; ++vc)
3534       {
3535         if (columnModel.getColumn(vc).getModelIndex() == mc)
3536           return vc;
3537       }
3538     return -1;
3539   }
3540   
3541   /**
3542    * Prepare the renderer for rendering the given cell.
3543    * 
3544    * @param renderer the renderer being prepared
3545    * @param row the row of the cell being rendered
3546    * @param column the column of the cell being rendered
3547    * 
3548    * @return the component which .paint() method will paint the cell.
3549    */
3550   public Component prepareRenderer(TableCellRenderer renderer,
3551                                    int row,
3552                                    int column)
3553   {
3554     boolean rowSelAllowed = getRowSelectionAllowed();
3555     boolean colSelAllowed = getColumnSelectionAllowed();
3556     boolean isSel = false;
3557     if (rowSelAllowed && colSelAllowed || !rowSelAllowed && !colSelAllowed)
3558       isSel = isCellSelected(row, column);
3559     else
3560       isSel = isRowSelected(row) && getRowSelectionAllowed()
3561            || isColumnSelected(column) && getColumnSelectionAllowed();
3562
3563     // Determine the focused cell. The focused cell is the cell at the
3564     // leadSelectionIndices of the row and column selection model.
3565     ListSelectionModel rowSel = getSelectionModel();
3566     ListSelectionModel colSel = getColumnModel().getSelectionModel();
3567     boolean hasFocus = hasFocus() && isEnabled()
3568                        && rowSel.getLeadSelectionIndex() == row
3569                        && colSel.getLeadSelectionIndex() == column;
3570
3571     return renderer.getTableCellRendererComponent(this,
3572                                                   dataModel.getValueAt(row, 
3573                                                                        convertColumnIndexToModel(column)),
3574                                                   isSel,
3575                                                   hasFocus,
3576                                                   row, column);
3577   }
3578
3579
3580   /**
3581    * Get the value of the {@link #autoCreateColumnsFromModel} property.
3582    *
3583    * @return The current value of the property
3584    */
3585   public boolean getAutoCreateColumnsFromModel()
3586   {
3587     return autoCreateColumnsFromModel;
3588   }
3589
3590   /**
3591    * Get the value of the {@link #autoResizeMode} property.
3592    *
3593    * @return The current value of the property
3594    */
3595   public int getAutoResizeMode()
3596   {
3597     return autoResizeMode;
3598   }
3599
3600   /**
3601    * Get the value of the {@link #rowHeight} property.
3602    *
3603    * @return The current value of the property
3604    */
3605   public int getRowHeight()
3606   {
3607     return rowHeight;
3608   }
3609
3610   /**
3611    * Get the height of the specified row.
3612    *
3613    * @param row the row whose height to return
3614    */
3615   public int getRowHeight(int row)
3616   {
3617     int rh = rowHeight;
3618     if (rowHeights != null)
3619       rh = rowHeights.getSize(row);
3620     return rh;
3621   }
3622
3623
3624   /**
3625    * Get the value of the {@link #rowMargin} property.
3626    *
3627    * @return The current value of the property
3628    */
3629   public int getRowMargin()
3630   {
3631     return rowMargin;
3632   }
3633
3634   /**
3635    * Get the value of the {@link #rowSelectionAllowed} property.
3636    *
3637    * @return The current value of the property
3638    * 
3639    * @see #setRowSelectionAllowed(boolean)
3640    */
3641   public boolean getRowSelectionAllowed()
3642   {
3643     return rowSelectionAllowed;
3644   }
3645
3646   /**
3647    * Get the value of the {@link #cellSelectionEnabled} property.
3648    *
3649    * @return The current value of the property
3650    */
3651   public boolean getCellSelectionEnabled()
3652   {
3653     return getColumnSelectionAllowed() && getRowSelectionAllowed();
3654   }
3655
3656   /**
3657    * Get the value of the {@link #dataModel} property.
3658    *
3659    * @return The current value of the property
3660    */
3661   public TableModel getModel()
3662   {
3663     return dataModel;
3664   }
3665
3666   /**
3667    * Get the value of the <code>columnCount</code> property by
3668    * delegation to the {@link #columnModel} field.
3669    *
3670    * @return The current value of the columnCount property
3671    */
3672   public int getColumnCount()
3673   {
3674     return columnModel.getColumnCount();    
3675   }
3676
3677   /**
3678    * Get the value of the <code>rowCount</code> property by
3679    * delegation to the {@link #dataModel} field.
3680    *
3681    * @return The current value of the rowCount property
3682    */
3683   public int getRowCount()
3684   {
3685     return dataModel.getRowCount();
3686   }
3687
3688   /**
3689    * Get the value of the {@link #columnModel} property.
3690    *
3691    * @return The current value of the property
3692    */
3693   public TableColumnModel getColumnModel()
3694   {
3695     return columnModel;
3696   }
3697
3698   /**
3699    * Get the value of the <code>selectedColumn</code> property by
3700    * delegation to the {@link #columnModel} field.
3701    *
3702    * @return The current value of the selectedColumn property
3703    */
3704   public int getSelectedColumn()
3705   {
3706     return columnModel.getSelectionModel().getMinSelectionIndex();
3707   }
3708
3709   private static int countSelections(ListSelectionModel lsm)
3710   {
3711     int lo = lsm.getMinSelectionIndex();
3712     int hi = lsm.getMaxSelectionIndex();
3713     int sum = 0;
3714     if (lo != -1 && hi != -1)
3715       {
3716         switch (lsm.getSelectionMode())
3717           {
3718           case ListSelectionModel.SINGLE_SELECTION:
3719             sum = 1;
3720             break;
3721             
3722           case ListSelectionModel.SINGLE_INTERVAL_SELECTION:
3723             sum = hi - lo + 1;
3724             break;
3725             
3726           case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION:        
3727             for (int i = lo; i <= hi; ++i)
3728               if (lsm.isSelectedIndex(i))        
3729                 ++sum;
3730             break;
3731           }
3732       }
3733     return sum;
3734   }
3735
3736   private static int[] getSelections(ListSelectionModel lsm)
3737   {
3738     int sz = countSelections(lsm);
3739     int [] ret = new int[sz];
3740
3741     int lo = lsm.getMinSelectionIndex();
3742     int hi = lsm.getMaxSelectionIndex();
3743     int j = 0;
3744     if (lo != -1 && hi != -1)
3745       {
3746         switch (lsm.getSelectionMode())
3747           {
3748           case ListSelectionModel.SINGLE_SELECTION:
3749             ret[0] = lo;
3750             break;      
3751       
3752           case ListSelectionModel.SINGLE_INTERVAL_SELECTION:            
3753             for (int i = lo; i <= hi; ++i)
3754               ret[j++] = i;
3755             break;
3756             
3757           case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION:        
3758             for (int i = lo; i <= hi; ++i)
3759               if (lsm.isSelectedIndex(i))        
3760                 ret[j++] = i;
3761             break;
3762           }
3763       }
3764     return ret;
3765   }
3766
3767   /**
3768    * Get the value of the <code>selectedColumnCount</code> property by
3769    * delegation to the {@link #columnModel} field.
3770    *
3771    * @return The current value of the selectedColumnCount property
3772    */  
3773   public int getSelectedColumnCount()
3774   {
3775     return countSelections(columnModel.getSelectionModel());
3776   }
3777
3778   /**
3779    * Get the value of the <code>selectedColumns</code> property by
3780    * delegation to the {@link #columnModel} field.
3781    *
3782    * @return The current value of the selectedColumns property
3783    */
3784   public int[] getSelectedColumns()
3785   {
3786     return getSelections(columnModel.getSelectionModel());
3787   }
3788
3789   /**
3790    * Get the value of the <code>columnSelectionAllowed</code> property.
3791    *
3792    * @return The current value of the columnSelectionAllowed property
3793    * 
3794    * @see #setColumnSelectionAllowed(boolean)
3795    */
3796   public boolean getColumnSelectionAllowed()
3797   {
3798     return getColumnModel().getColumnSelectionAllowed();
3799   }
3800
3801   /**
3802    * Get the value of the <code>selectedRowCount</code> property by
3803    * delegation to the {@link #selectionModel} field.
3804    *
3805    * @return The current value of the selectedRowCount property
3806    */
3807   public int getSelectedRowCount()
3808   {
3809     return countSelections(selectionModel);
3810   }
3811
3812   /**
3813    * Get the value of the <code>selectedRows</code> property by
3814    * delegation to the {@link #selectionModel} field.
3815    *
3816    * @return The current value of the selectedRows property
3817    */
3818   public int[] getSelectedRows()
3819   {
3820     return getSelections(selectionModel);
3821   }
3822
3823   /**
3824    * Get the value of the {@link #accessibleContext} property.
3825    *
3826    * @return The current value of the property
3827    */
3828   public AccessibleContext getAccessibleContext()
3829   {
3830     if (accessibleContext == null)
3831       {
3832         AccessibleJTable ctx = new AccessibleJTable();
3833         addPropertyChangeListener(ctx);
3834         TableColumnModel tcm = getColumnModel();
3835         tcm.addColumnModelListener(ctx);
3836         tcm.getSelectionModel().addListSelectionListener(ctx);
3837         getSelectionModel().addListSelectionListener(ctx);
3838         
3839         accessibleContext = ctx;
3840       }
3841     return accessibleContext;
3842   }
3843
3844   /**
3845    * Get the value of the {@link #cellEditor} property.
3846    *
3847    * @return The current value of the property
3848    */
3849   public TableCellEditor getCellEditor()
3850   {
3851     return cellEditor;
3852   }
3853
3854   /**
3855    * Get the value of the {@link #dragEnabled} property.
3856    *
3857    * @return The current value of the property
3858    */
3859   public boolean getDragEnabled()
3860   {
3861     return dragEnabled;
3862   }
3863
3864   /**
3865    * Get the value of the {@link #gridColor} property.
3866    *
3867    * @return The current value of the property
3868    */
3869   public Color getGridColor()
3870   {
3871     return gridColor;
3872   }
3873
3874   /**
3875    * Get the value of the <code>intercellSpacing</code> property.
3876    *
3877    * @return The current value of the property
3878    */
3879   public Dimension getIntercellSpacing()
3880   {
3881     return new Dimension(columnModel.getColumnMargin(), rowMargin);
3882   }
3883
3884   /**
3885    * Get the value of the {@link #preferredViewportSize} property.
3886    *
3887    * @return The current value of the property
3888    */
3889   public Dimension getPreferredScrollableViewportSize()
3890   {
3891     return preferredViewportSize;
3892   }
3893
3894   /**
3895    * Get the value of the {@link #selectionBackground} property.
3896    *
3897    * @return The current value of the property
3898    */
3899   public Color getSelectionBackground()
3900   {
3901     return selectionBackground;
3902   }
3903
3904   /**
3905    * Get the value of the {@link #selectionForeground} property.
3906    *
3907    * @return The current value of the property
3908    */
3909   public Color getSelectionForeground()
3910   {
3911     return selectionForeground;
3912   }
3913
3914   /**
3915    * Get the value of the {@link #showHorizontalLines} property.
3916    *
3917    * @return The current value of the property
3918    */
3919   public boolean getShowHorizontalLines()
3920   {
3921     return showHorizontalLines;
3922   }
3923
3924   /**
3925    * Get the value of the {@link #showVerticalLines} property.
3926    *
3927    * @return The current value of the property
3928    */
3929   public boolean getShowVerticalLines()
3930   {
3931     return showVerticalLines;
3932   }
3933
3934   /**
3935    * Get the value of the {@link #tableHeader} property.
3936    *
3937    * @return The current value of the property
3938    */
3939   public JTableHeader getTableHeader()
3940   {
3941     return tableHeader;
3942   }
3943
3944   /**
3945    * Removes specified column from displayable columns of this table.
3946    *
3947    * @param column column to removed
3948    */
3949   public void removeColumn(TableColumn column)
3950   {    
3951     columnModel.removeColumn(column);
3952   }
3953
3954   /**
3955    * Moves column at the specified index to new given location.
3956    *
3957    * @param column index of the column to move
3958    * @param targetColumn index specifying new location of the column
3959    */ 
3960   public void moveColumn(int column,int targetColumn) 
3961   {
3962     columnModel.moveColumn(column, targetColumn);
3963   }
3964
3965   /**
3966    * Set the value of the {@link #autoCreateColumnsFromModel} flag.  If the
3967    * flag changes from <code>false</code> to <code>true</code>, the
3968    * {@link #createDefaultColumnsFromModel()} method is called.
3969    *
3970    * @param autoCreate  the new value of the flag.
3971    */ 
3972   public void setAutoCreateColumnsFromModel(boolean autoCreate)
3973   {
3974     if (autoCreateColumnsFromModel != autoCreate)
3975     {
3976       autoCreateColumnsFromModel = autoCreate;
3977       if (autoCreate)
3978         createDefaultColumnsFromModel();
3979     }
3980   }
3981
3982   /**
3983    * Set the value of the {@link #autoResizeMode} property.
3984    *
3985    * @param a The new value of the autoResizeMode property
3986    */ 
3987   public void setAutoResizeMode(int a)
3988   {
3989     autoResizeMode = a;
3990     revalidate();
3991     repaint();
3992   }
3993
3994   /**
3995    * Sets the height for all rows in the table. If you want to change the
3996    * height of a single row instead, use {@link #setRowHeight(int, int)}.
3997    *
3998    * @param r the height to set for all rows
3999    *
4000    * @see #getRowHeight()
4001    * @see #setRowHeight(int, int)
4002    * @see #getRowHeight(int)
4003    */ 
4004   public void setRowHeight(int r)
4005   {
4006     if (r < 1)
4007       throw new IllegalArgumentException();
4008
4009     clientRowHeightSet = true;
4010
4011     rowHeight = r;
4012     rowHeights = null;
4013     revalidate();
4014     repaint();
4015   }
4016   
4017   /**
4018    * Sets the height of a single row in the table.
4019    * 
4020    * @param rh the new row height
4021    * @param row the row to change the height of
4022    */
4023   public void setRowHeight(int row, int rh)
4024   {
4025     if (rowHeights == null)
4026       {
4027         rowHeights = new SizeSequence(getRowCount(), rowHeight);
4028       }
4029     rowHeights.setSize(row, rh);
4030   }
4031   
4032   /**
4033    * Set the value of the {@link #rowMargin} property.
4034    *
4035    * @param r The new value of the rowMargin property
4036    */ 
4037   public void setRowMargin(int r)
4038   {
4039     rowMargin = r;
4040     revalidate();
4041     repaint();
4042   }
4043
4044   /**
4045    * Set the value of the {@link #rowSelectionAllowed} property.
4046    *
4047    * @param r The new value of the rowSelectionAllowed property
4048    * 
4049    * @see #getRowSelectionAllowed()
4050    */ 
4051   public void setRowSelectionAllowed(boolean r)
4052   {
4053     if (rowSelectionAllowed != r) 
4054       {
4055         rowSelectionAllowed = r;
4056         firePropertyChange("rowSelectionAllowed", !r, r);
4057         repaint();
4058       }
4059   }
4060
4061   /**
4062    * Set the value of the {@link #cellSelectionEnabled} property.
4063    *
4064    * @param c The new value of the cellSelectionEnabled property
4065    */ 
4066   public void setCellSelectionEnabled(boolean c)
4067   {
4068     setColumnSelectionAllowed(c);
4069     setRowSelectionAllowed(c);
4070     // for backward-compatibility sake:
4071     cellSelectionEnabled = true;
4072   }
4073
4074   /**
4075    * <p>Set the value of the {@link #dataModel} property.</p>
4076    *
4077    * <p>Unregister <code>this</code> as a {@link TableModelListener} from
4078    * previous {@link #dataModel} and register it with new parameter
4079    * <code>m</code>.</p>
4080    *
4081    * @param m The new value of the model property
4082    */ 
4083   public void setModel(TableModel m)
4084   {
4085     // Throw exception is m is null.
4086     if (m == null)
4087       throw new IllegalArgumentException();
4088    
4089     // Don't do anything if setting the current model again.
4090     if (dataModel == m)
4091       return;
4092
4093     TableModel oldModel = dataModel;
4094
4095     // Remove table as TableModelListener from old model.
4096     if (dataModel != null)
4097       dataModel.removeTableModelListener(this);
4098     
4099     if (m != null)
4100       {
4101         // Set property.
4102         dataModel = m;
4103
4104         // Add table as TableModelListener to new model.
4105         dataModel.addTableModelListener(this);
4106
4107         // Notify the tableChanged method.
4108         tableChanged(new TableModelEvent(dataModel,
4109                                          TableModelEvent.HEADER_ROW));
4110
4111         // Automatically create columns.
4112         if (autoCreateColumnsFromModel)
4113           createDefaultColumnsFromModel();
4114       }
4115
4116     // This property is bound, so we fire a property change event.
4117     firePropertyChange("model", oldModel, dataModel);
4118
4119     // Repaint table.
4120     revalidate();
4121     repaint();
4122   }
4123
4124   /**
4125    * <p>Set the value of the {@link #columnModel} property.</p>
4126    *
4127    * <p>Unregister <code>this</code> as a {@link TableColumnModelListener}
4128    * from previous {@link #columnModel} and register it with new parameter
4129    * <code>c</code>.</p>
4130    *
4131    * @param c The new value of the columnModel property
4132    */ 
4133   public void setColumnModel(TableColumnModel c)
4134   {
4135     if (c == null)
4136       throw new IllegalArgumentException();
4137     TableColumnModel tmp = columnModel;
4138     if (tmp != null)
4139       tmp.removeColumnModelListener(this);
4140     if (c != null)
4141       c.addColumnModelListener(this);
4142     columnModel = c;
4143     if (dataModel != null && columnModel != null)
4144       {
4145         int ncols = getColumnCount();
4146         TableColumn column;
4147         for (int i = 0; i < ncols; ++i)
4148           {
4149             column = columnModel.getColumn(i); 
4150             if (column.getHeaderValue()==null)
4151               column.setHeaderValue(dataModel.getColumnName(i));
4152           }
4153       }
4154
4155     // according to Sun's spec we also have to set the tableHeader's
4156     // column model here
4157     if (tableHeader != null)
4158       tableHeader.setColumnModel(c);
4159
4160     revalidate();
4161     repaint();
4162   }
4163
4164   /**
4165    * Set the value of the <code>columnSelectionAllowed</code> property.
4166    *
4167    * @param c The new value of the property
4168    * 
4169    * @see #getColumnSelectionAllowed()
4170    */ 
4171   public void setColumnSelectionAllowed(boolean c)
4172   {
4173     if (columnModel.getColumnSelectionAllowed() != c)
4174       {
4175         columnModel.setColumnSelectionAllowed(c);
4176         firePropertyChange("columnSelectionAllowed", !c, c);
4177         repaint();
4178       }
4179   }
4180
4181   /**
4182    * <p>Set the value of the {@link #selectionModel} property.</p>
4183    *
4184    * <p>Unregister <code>this</code> as a {@link ListSelectionListener}
4185    * from previous {@link #selectionModel} and register it with new
4186    * parameter <code>s</code>.</p>
4187    *
4188    * @param s The new value of the selectionModel property
4189    */ 
4190   public void setSelectionModel(ListSelectionModel s)
4191   {
4192     if (s == null)
4193       throw new IllegalArgumentException();
4194     ListSelectionModel tmp = selectionModel;
4195     if (tmp != null)
4196       tmp.removeListSelectionListener(this);
4197     if (s != null)
4198       s.addListSelectionListener(this);
4199     selectionModel = s;
4200     checkSelection();
4201   }
4202
4203   /**
4204    * Set the value of the <code>selectionMode</code> property by
4205    * delegation to the {@link #selectionModel} field. The same selection
4206    * mode is set for row and column selection models.
4207    *
4208    * @param s The new value of the property
4209    */ 
4210   public void setSelectionMode(int s)
4211   { 
4212     selectionModel.setSelectionMode(s);    
4213     columnModel.getSelectionModel().setSelectionMode(s);
4214     
4215     repaint();
4216   }
4217
4218   /**
4219    * <p>Set the value of the {@link #cellEditor} property.</p>
4220    *
4221    * <p>Unregister <code>this</code> as a {@link CellEditorListener} from
4222    * previous {@link #cellEditor} and register it with new parameter
4223    * <code>c</code>.</p>
4224    *
4225    * @param c The new value of the cellEditor property
4226    */ 
4227   public void setCellEditor(TableCellEditor c)
4228   {
4229     TableCellEditor tmp = cellEditor;
4230     if (tmp != null)
4231       tmp.removeCellEditorListener(this);
4232     if (c != null)
4233       c.addCellEditorListener(this);
4234     cellEditor = c;
4235   }
4236
4237   /**
4238    * Set the value of the {@link #dragEnabled} property.
4239    *
4240    * @param d The new value of the dragEnabled property
4241    */ 
4242   public void setDragEnabled(boolean d)
4243   {
4244     dragEnabled = d;
4245   }
4246
4247   /**
4248    * Set the value of the {@link #gridColor} property.
4249    *
4250    * @param g The new value of the gridColor property
4251    */ 
4252   public void setGridColor(Color g)
4253   {
4254     gridColor = g;
4255     repaint();
4256   }
4257
4258   /**
4259    * Set the value of the <code>intercellSpacing</code> property.
4260    *
4261    * @param i The new value of the intercellSpacing property
4262    */ 
4263   public void setIntercellSpacing(Dimension i)
4264   {
4265     rowMargin = i.height;
4266     columnModel.setColumnMargin(i.width);
4267     repaint();
4268   }
4269
4270   /**
4271    * Set the value of the {@link #preferredViewportSize} property.
4272    *
4273    * @param p The new value of the preferredViewportSize property
4274    */ 
4275   public void setPreferredScrollableViewportSize(Dimension p)
4276   {
4277     preferredViewportSize = p;
4278     revalidate();
4279     repaint();
4280   }
4281
4282   /**
4283    * <p>Set the value of the {@link #selectionBackground} property.</p>
4284    *
4285    * <p>Fire a PropertyChangeEvent with name {@link
4286    * #SELECTION_BACKGROUND_CHANGED_PROPERTY} to registered listeners, if
4287    * selectionBackground changed.</p>
4288    *
4289    * @param s The new value of the selectionBackground property
4290    */ 
4291   public void setSelectionBackground(Color s)
4292   {
4293     Color tmp = selectionBackground;
4294     selectionBackground = s;
4295     if (((tmp == null && s != null)
4296          || (s == null && tmp != null)
4297          || (tmp != null && s != null && !tmp.equals(s))))
4298       firePropertyChange(SELECTION_BACKGROUND_CHANGED_PROPERTY, tmp, s);
4299     repaint();
4300   }
4301
4302   /**
4303    * <p>Set the value of the {@link #selectionForeground} property.</p>
4304    *
4305    * <p>Fire a PropertyChangeEvent with name {@link
4306    * #SELECTION_FOREGROUND_CHANGED_PROPERTY} to registered listeners, if
4307    * selectionForeground changed.</p>
4308    *
4309    * @param s The new value of the selectionForeground property
4310    */ 
4311   public void setSelectionForeground(Color s)
4312   {
4313     Color tmp = selectionForeground;
4314     selectionForeground = s;
4315     if (((tmp == null && s != null)
4316          || (s == null && tmp != null)
4317          || (tmp != null && s != null && !tmp.equals(s))))
4318       firePropertyChange(SELECTION_FOREGROUND_CHANGED_PROPERTY, tmp, s);
4319     repaint();
4320   }
4321
4322   /**
4323    * Set the value of the <code>showGrid</code> property.
4324    *
4325    * @param s The new value of the showGrid property
4326    */ 
4327   public void setShowGrid(boolean s)
4328   {
4329     setShowVerticalLines(s);
4330     setShowHorizontalLines(s);
4331   }
4332
4333   /**
4334    * Set the value of the {@link #showHorizontalLines} property.
4335    *
4336    * @param s The new value of the showHorizontalLines property
4337    */ 
4338   public void setShowHorizontalLines(boolean s)
4339   {
4340     showHorizontalLines = s;
4341     repaint();
4342   }
4343
4344   /**
4345    * Set the value of the {@link #showVerticalLines} property.
4346    *
4347    * @param s The new value of the showVerticalLines property
4348    */ 
4349   public void setShowVerticalLines(boolean s)
4350   {
4351     showVerticalLines = s;
4352     repaint();
4353   }
4354
4355   /**
4356    * Set the value of the {@link #tableHeader} property.
4357    *
4358    * @param t The new value of the tableHeader property
4359    */ 
4360   public void setTableHeader(JTableHeader t)
4361   {
4362     if (tableHeader != null)
4363       tableHeader.setTable(null);
4364     tableHeader = t;
4365     if (tableHeader != null)
4366       tableHeader.setTable(this);
4367     revalidate();
4368     repaint();
4369   }
4370
4371   protected void configureEnclosingScrollPane()
4372   {
4373     JScrollPane jsp = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, this);
4374     if (jsp != null && tableHeader != null)
4375       {
4376         jsp.setColumnHeaderView(tableHeader);
4377       }
4378   }
4379
4380   protected void unconfigureEnclosingScrollPane()
4381   {
4382     JScrollPane jsp = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, this);
4383     if (jsp != null)
4384       {
4385         jsp.setColumnHeaderView(null);
4386       }    
4387   }
4388
4389
4390   public void addNotify()
4391   {
4392     super.addNotify();
4393     configureEnclosingScrollPane();
4394   }
4395
4396   public void removeNotify()
4397   {
4398     super.addNotify();
4399     unconfigureEnclosingScrollPane();
4400   }
4401
4402
4403   /**
4404    * This distributes the superfluous width in a table evenly on its columns.
4405    *
4406    * The implementation used here is different to that one described in
4407    * the JavaDocs. It is much simpler, and seems to work very well.
4408    *
4409    * TODO: correctly implement the algorithm described in the JavaDoc
4410    */
4411   private void distributeSpill(TableColumn[] cols, int spill)
4412   {
4413     int average = spill / cols.length;
4414     for (int i = 0; i < cols.length; i++)
4415       {
4416         if (cols[i] != null)
4417           cols[i].setWidth(cols[i].getPreferredWidth() + average);
4418       }
4419   }
4420   
4421   /**
4422    * This distributes the superfluous width in a table, setting the width of the
4423    * column being resized strictly to its preferred width.
4424    */
4425   private void distributeSpillResizing(TableColumn[] cols, int spill,
4426                                        TableColumn resizeIt)
4427   {
4428     int average = 0;
4429     if (cols.length != 1)
4430       average = spill / (cols.length-1);
4431     for (int i = 0; i < cols.length; i++)
4432       {
4433         if (cols[i] != null && !cols[i].equals(resizeIt))
4434           cols[i].setWidth(cols[i].getPreferredWidth() + average);
4435       }
4436     resizeIt.setWidth(resizeIt.getPreferredWidth());
4437   }  
4438   
4439   /**
4440    * Set the widths of all columns, taking they preferred widths into
4441    * consideration. The excess space, if any, will be distrubuted between
4442    * all columns. This method also handles special cases when one of the
4443    * collumns is currently being resized.
4444    * 
4445    * @see TableColumn#setPreferredWidth(int)
4446    */
4447   public void doLayout()
4448   {
4449     TableColumn resizingColumn = null;
4450     
4451     int ncols = columnModel.getColumnCount();
4452     if (ncols < 1)
4453       return;
4454
4455     int prefSum = 0;
4456     int rCol = -1;
4457
4458     if (tableHeader != null)
4459       resizingColumn = tableHeader.getResizingColumn();
4460      
4461     for (int i = 0; i < ncols; ++i)
4462       {
4463         TableColumn col = columnModel.getColumn(i);
4464         int p = col.getPreferredWidth();
4465         prefSum += p;
4466         if (resizingColumn == col)
4467           rCol = i;
4468       }
4469  
4470     int spill = getWidth() - prefSum;
4471
4472     if (resizingColumn != null)
4473       {
4474         TableColumn col;
4475         TableColumn [] cols;
4476         
4477         switch (getAutoResizeMode())
4478           {
4479           case AUTO_RESIZE_LAST_COLUMN:
4480             col = columnModel.getColumn(ncols-1);
4481             col.setWidth(col.getPreferredWidth() + spill);
4482             break;
4483             
4484           case AUTO_RESIZE_NEXT_COLUMN:
4485             col = columnModel.getColumn(ncols-1);
4486             col.setWidth(col.getPreferredWidth() + spill);
4487             break;
4488
4489           case AUTO_RESIZE_ALL_COLUMNS:
4490             cols = new TableColumn[ncols];
4491             for (int i = 0; i < ncols; ++i)
4492               cols[i] = columnModel.getColumn(i);
4493             distributeSpillResizing(cols, spill, resizingColumn);
4494             break;
4495
4496           case AUTO_RESIZE_SUBSEQUENT_COLUMNS:
4497             
4498             // Subtract the width of the non-resized columns from the spill.
4499             int w = 0;
4500             int wp = 0;
4501             TableColumn column;
4502             for (int i = 0; i < rCol; i++)
4503               {
4504                 column = columnModel.getColumn(i);
4505                 w += column.getWidth();
4506                 wp+= column.getPreferredWidth();
4507               }
4508
4509             // The number of columns right from the column being resized.
4510             int n = ncols-rCol-1;
4511             if (n>0)
4512               {
4513                 // If there are any columns on the right sied to resize.
4514                 spill = (getWidth()-w) - (prefSum-wp);
4515                 int average = spill / n;
4516             
4517                  // For all columns right from the column being resized:
4518                 for (int i = rCol+1; i < ncols; i++)
4519                   {
4520                     column = columnModel.getColumn(i);
4521                     column.setWidth(column.getPreferredWidth() + average);
4522                   }
4523               }
4524             resizingColumn.setWidth(resizingColumn.getPreferredWidth());
4525             break;
4526
4527           case AUTO_RESIZE_OFF:
4528           default:
4529             int prefWidth = resizingColumn.getPreferredWidth();
4530             resizingColumn.setWidth(prefWidth);
4531           }
4532       }
4533     else
4534       {
4535         TableColumn[] cols = new TableColumn[ncols];
4536
4537         for (int i = 0; i < ncols; ++i)
4538           cols[i] = columnModel.getColumn(i);
4539
4540         distributeSpill(cols, spill);
4541       }
4542     
4543     if (editorComp!=null)
4544       moveToCellBeingEdited(editorComp);
4545     
4546     int leftBoundary = getLeftResizingBoundary();
4547     int width = getWidth() - leftBoundary;
4548     repaint(leftBoundary, 0, width, getHeight());
4549     if (tableHeader != null)
4550       tableHeader.repaint(leftBoundary, 0, width, tableHeader.getHeight());
4551   }
4552   
4553   /**
4554    * Get the left boundary of the rectangle which changes during the column
4555    * resizing.
4556    */
4557   int getLeftResizingBoundary()
4558   {
4559     if (tableHeader == null || getAutoResizeMode() == AUTO_RESIZE_ALL_COLUMNS)
4560       return 0;
4561     else
4562       {
4563         TableColumn resizingColumn = tableHeader.getResizingColumn();
4564         if (resizingColumn == null)
4565           return 0;
4566
4567         int rc = convertColumnIndexToView(resizingColumn.getModelIndex());
4568         int p = 0;
4569
4570         for (int i = 0; i < rc; i++)
4571           p += columnModel.getColumn(i).getWidth();
4572         
4573         return p;
4574       }
4575   }
4576   
4577   
4578   /**
4579    * @deprecated Replaced by <code>doLayout()</code>
4580    */
4581   public void sizeColumnsToFit(boolean lastColumnOnly)
4582   {
4583     doLayout();
4584   }
4585   
4586   /**
4587    * Obsolete since JDK 1.4. Please use <code>doLayout()</code>.
4588    */
4589   public void sizeColumnsToFit(int resizingColumn)
4590   {
4591     doLayout();
4592   }
4593
4594   public String getUIClassID()
4595   {
4596     return "TableUI";
4597   }
4598
4599   /**
4600    * This method returns the table's UI delegate.
4601    *
4602    * @return The table's UI delegate.
4603    */
4604   public TableUI getUI()
4605   {
4606     return (TableUI) ui;
4607   }
4608
4609   /**
4610    * This method sets the table's UI delegate.
4611    *
4612    * @param ui The table's UI delegate.
4613    */
4614   public void setUI(TableUI ui)
4615   {
4616     super.setUI(ui);
4617     // The editors and renderers must be recreated because they constructors
4618     // may use the look and feel properties.
4619     createDefaultEditors();
4620     createDefaultRenderers();
4621   }
4622
4623   public void updateUI()
4624   {
4625     setUI((TableUI) UIManager.getUI(this));
4626   }
4627
4628   /**
4629    * Get the class (datatype) of the column. The cells are rendered and edited
4630    * differently, depending from they data type.
4631    * 
4632    * @param column the column (not the model index).
4633    * 
4634    * @return the class, defining data type of that column (String.class for
4635    * String, Boolean.class for boolean and so on).
4636    */
4637   public Class<?> getColumnClass(int column)
4638   {
4639     return getModel().getColumnClass(convertColumnIndexToModel(column));
4640   }
4641   
4642   /**
4643    * Get the name of the column. If the column has the column identifier set,
4644    * the return value is the result of the .toString() method call on that
4645    * identifier. If the identifier is not explicitly set, the returned value
4646    * is calculated by 
4647    * {@link javax.swing.table.AbstractTableModel#getColumnName(int)}.
4648    * 
4649    * @param column the column
4650    * 
4651    * @return the name of that column.
4652    */
4653   public String getColumnName(int column)
4654   {
4655     int modelColumn = columnModel.getColumn(column).getModelIndex();
4656     return dataModel.getColumnName(modelColumn);
4657   }
4658
4659   /**
4660    * Get the column, currently being edited
4661    * 
4662    * @return the column, currently being edited.
4663    */
4664   public int getEditingColumn()
4665   {
4666     return editingColumn;
4667   }
4668
4669   /**
4670    * Set the column, currently being edited
4671    * 
4672    * @param column the column, currently being edited.
4673    */
4674   public void setEditingColumn(int column)
4675   {
4676     editingColumn = column;
4677   }
4678   
4679   /**
4680    * Get the row currently being edited.
4681    * 
4682    * @return the row, currently being edited.
4683    */
4684   public int getEditingRow()
4685   {
4686     return editingRow;
4687   }
4688
4689   /**
4690    * Set the row currently being edited.
4691    * 
4692    * @param row the row, that will be edited
4693    */
4694   public void setEditingRow(int row)
4695   {
4696     editingRow = row;
4697   }
4698   
4699   /**
4700    * Get the editor component that is currently editing one of the cells
4701    * 
4702    * @return the editor component or null, if none of the cells is being
4703    * edited.
4704    */
4705   public Component getEditorComponent()
4706   {
4707     return editorComp;
4708   }
4709   
4710   /**
4711    * Check if one of the table cells is currently being edited.
4712    * 
4713    * @return true if there is a cell being edited.
4714    */
4715   public boolean isEditing()
4716   {
4717     return editorComp != null;
4718   }
4719
4720   /**
4721    * Set the default editor for the given column class (column data type).
4722    * By default, String is handled by text field and Boolean is handled by
4723    * the check box.
4724    *  
4725    * @param columnClass the column data type
4726    * @param editor the editor that will edit this data type
4727    * 
4728    * @see TableModel#getColumnClass(int)
4729    */
4730   public void setDefaultEditor(Class<?> columnClass, TableCellEditor editor)
4731   {
4732     if (editor != null)
4733       defaultEditorsByColumnClass.put(columnClass, editor);
4734     else
4735       defaultEditorsByColumnClass.remove(columnClass);
4736   }
4737   
4738   public void addColumnSelectionInterval(int index0, int index1)
4739   {
4740     if ((index0 < 0 || index0 > (getColumnCount()-1)
4741          || index1 < 0 || index1 > (getColumnCount()-1)))
4742       throw new IllegalArgumentException("Column index out of range.");
4743     
4744     getColumnModel().getSelectionModel().addSelectionInterval(index0, index1);
4745   }
4746   
4747   public void addRowSelectionInterval(int index0, int index1)
4748   {            
4749     if ((index0 < 0 || index0 > (getRowCount()-1)
4750          || index1 < 0 || index1 > (getRowCount()-1)))
4751       throw new IllegalArgumentException("Row index out of range.");
4752         
4753     getSelectionModel().addSelectionInterval(index0, index1);
4754   }
4755   
4756   public void setColumnSelectionInterval(int index0, int index1)
4757   {
4758     if ((index0 < 0 || index0 > (getColumnCount()-1)
4759          || index1 < 0 || index1 > (getColumnCount()-1)))
4760       throw new IllegalArgumentException("Column index out of range.");
4761
4762     getColumnModel().getSelectionModel().setSelectionInterval(index0, index1);
4763   }
4764   
4765   public void setRowSelectionInterval(int index0, int index1)
4766   {    
4767     if ((index0 < 0 || index0 > (getRowCount()-1)
4768          || index1 < 0 || index1 > (getRowCount()-1)))
4769       throw new IllegalArgumentException("Row index out of range.");
4770
4771     getSelectionModel().setSelectionInterval(index0, index1);
4772   }
4773   
4774   public void removeColumnSelectionInterval(int index0, int index1)  
4775   {
4776     if ((index0 < 0 || index0 > (getColumnCount()-1)
4777          || index1 < 0 || index1 > (getColumnCount()-1)))
4778       throw new IllegalArgumentException("Column index out of range.");
4779
4780     getColumnModel().getSelectionModel().removeSelectionInterval(index0, index1);
4781   }
4782   
4783   public void removeRowSelectionInterval(int index0, int index1)
4784   {
4785     if ((index0 < 0 || index0 > (getRowCount()-1)
4786          || index1 < 0 || index1 > (getRowCount()-1)))
4787       throw new IllegalArgumentException("Row index out of range.");
4788
4789     getSelectionModel().removeSelectionInterval(index0, index1);
4790   }
4791   
4792   /**
4793    * Checks if the given column is selected.
4794    * 
4795    * @param column the column
4796    * 
4797    * @return true if the column is selected (as reported by the selection
4798    * model, associated with the column model), false otherwise.
4799    */
4800   public boolean isColumnSelected(int column)
4801   {
4802     return getColumnModel().getSelectionModel().isSelectedIndex(column);
4803   }
4804   
4805   /**
4806    * Checks if the given row is selected.
4807    * 
4808    * @param row the row
4809    * 
4810    * @return true if the row is selected (as reported by the selection model),
4811    * false otherwise.
4812    */
4813   public boolean isRowSelected(int row)
4814   {
4815     return getSelectionModel().isSelectedIndex(row);
4816   }
4817   
4818   /**
4819    * Checks if the given cell is selected. The cell is selected if both
4820    * the cell row and the cell column are selected.
4821    * 
4822    * @param row the cell row
4823    * @param column the cell column
4824    * 
4825    * @return true if the cell is selected, false otherwise
4826    */
4827   public boolean isCellSelected(int row, int column)
4828   {
4829     return isRowSelected(row) && isColumnSelected(column);
4830   }
4831   
4832   /**
4833    * Select all table.
4834    */
4835   public void selectAll()
4836   {
4837     // The table is empty - nothing to do!
4838     if (getRowCount() == 0 || getColumnCount() == 0)
4839       return;
4840     
4841     // rowLead and colLead store the current lead selection indices
4842     int rowLead = selectionModel.getLeadSelectionIndex();
4843     int colLead = getColumnModel().getSelectionModel().getLeadSelectionIndex();
4844     // the following calls to setSelectionInterval change the lead selection
4845     // indices
4846     setColumnSelectionInterval(0, getColumnCount() - 1);
4847     setRowSelectionInterval(0, getRowCount() - 1);
4848     // the following addSelectionInterval calls restore the lead selection
4849     // indices to their previous values
4850     addColumnSelectionInterval(colLead,colLead);
4851     addRowSelectionInterval(rowLead, rowLead);
4852   }
4853   
4854   /**
4855    * Get the cell value at the given position.
4856    * 
4857    * @param row the row to get the value
4858    * @param column the actual column number (not the model index) 
4859    * to get the value.
4860    * 
4861    * @return the cell value, as returned by model.
4862    */
4863   public Object getValueAt(int row, int column)
4864   {
4865     return dataModel.getValueAt(row, convertColumnIndexToModel(column));
4866   }
4867   
4868   /**
4869    * Set value for the cell at the given position. The modified cell is
4870    * repainted.
4871    * 
4872    * @param value the value to set
4873    * @param row the row of the cell being modified
4874    * @param column the column of the cell being modified
4875    */
4876   public void setValueAt(Object value, int row, int column)
4877   {
4878     dataModel.setValueAt(value, row, convertColumnIndexToModel(column));
4879     
4880     repaint(getCellRect(row, column, true));
4881   }
4882   
4883   /**
4884    * Get table column with the given identified.
4885    * 
4886    * @param identifier the column identifier
4887    * 
4888    * @return the table column with this identifier
4889    * 
4890    * @throws IllegalArgumentException if <code>identifier</code> is 
4891    *         <code>null</code> or there is no column with that identifier.
4892    * 
4893    * @see TableColumn#setIdentifier(Object)
4894    */
4895   public TableColumn getColumn(Object identifier)
4896   {
4897     return columnModel.getColumn(columnModel.getColumnIndex(identifier));
4898   }
4899
4900   /**
4901    * Returns <code>true</code> if the specified cell is editable, and
4902    * <code>false</code> otherwise.
4903    *
4904    * @param row  the row index.
4905    * @param column  the column index.
4906    *
4907    * @return true if the cell is editable, false otherwise.
4908    */
4909   public boolean isCellEditable(int row, int column)
4910   {
4911     return dataModel.isCellEditable(row, convertColumnIndexToModel(column));
4912   }
4913
4914   /**
4915    * Clears any existing columns from the <code>JTable</code>'s
4916    * {@link TableColumnModel} and creates new columns to match the values in
4917    * the data ({@link TableModel}) used by the table.
4918    *
4919    * @see #setAutoCreateColumnsFromModel(boolean)
4920    */
4921   public void createDefaultColumnsFromModel()
4922   {
4923     assert columnModel != null : "The columnModel must not be null.";
4924
4925     // remove existing columns
4926     int columnIndex = columnModel.getColumnCount() - 1;
4927     while (columnIndex >= 0)
4928     {
4929       columnModel.removeColumn(columnModel.getColumn(columnIndex));
4930       columnIndex--;
4931     }
4932   
4933     // add new columns to match the TableModel
4934     int columnCount = dataModel.getColumnCount();
4935     for (int c = 0; c < columnCount; c++)
4936     {
4937       TableColumn column = new TableColumn(c);
4938       column.setIdentifier(dataModel.getColumnName(c));
4939       column.setHeaderValue(dataModel.getColumnName(c));
4940       columnModel.addColumn(column);
4941       column.addPropertyChangeListener(tableColumnPropertyChangeHandler);
4942     }
4943   }
4944
4945   public void changeSelection (int rowIndex, int columnIndex, boolean toggle, boolean extend)
4946   {
4947     if (toggle && extend)
4948       {
4949         // Leave the selection state as is, but move the anchor
4950         //   index to the specified location
4951         selectionModel.setAnchorSelectionIndex(rowIndex);
4952         getColumnModel().getSelectionModel().setAnchorSelectionIndex(columnIndex);
4953       }
4954     else if (toggle)
4955       {
4956         // Toggle the state of the specified cell
4957         if (isCellSelected(rowIndex,columnIndex))
4958           {
4959             selectionModel.removeSelectionInterval(rowIndex,rowIndex);
4960             getColumnModel().getSelectionModel().removeSelectionInterval(columnIndex,columnIndex);
4961           }
4962         else
4963           {
4964             selectionModel.addSelectionInterval(rowIndex,rowIndex);
4965             getColumnModel().getSelectionModel().addSelectionInterval(columnIndex,columnIndex);
4966           }
4967       }
4968     else if (extend)
4969       {
4970         // Extend the previous selection from the anchor to the 
4971         // specified cell, clearing all other selections
4972         selectionModel.setLeadSelectionIndex(rowIndex);
4973         getColumnModel().getSelectionModel().setLeadSelectionIndex(columnIndex);
4974       }
4975     else
4976       {
4977         // Clear the previous selection and ensure the new cell
4978         // is selected
4979          selectionModel.clearSelection();
4980         selectionModel.setSelectionInterval(rowIndex,rowIndex);
4981         getColumnModel().getSelectionModel().clearSelection();
4982         getColumnModel().getSelectionModel().setSelectionInterval(columnIndex, columnIndex);
4983         
4984         
4985       }
4986   }
4987
4988   /**
4989    * Programmatically starts editing the specified cell.
4990    * 
4991    * @param row the row of the cell to edit.
4992    * @param column the column of the cell to edit.
4993    */
4994   public boolean editCellAt(int row, int column)
4995   {
4996     // Complete the previous editing session, if still active.
4997     if (isEditing())
4998       editingStopped(new ChangeEvent("editingStopped"));
4999
5000     TableCellEditor editor = getCellEditor(row, column);
5001     
5002     // The boolean values are inverted by the single click without the
5003     // real editing session.
5004     if (editor == booleanInvertingEditor && isCellEditable(row, column))
5005       {
5006         if (Boolean.TRUE.equals(getValueAt(row, column)))
5007           setValueAt(Boolean.FALSE, row, column);
5008         else
5009           setValueAt(Boolean.TRUE, row, column);
5010         return false;
5011       }
5012     else
5013       {
5014         editingRow = row;
5015         editingColumn = column;
5016
5017         setCellEditor(editor);
5018         editorComp = prepareEditor(cellEditor, row, column);
5019
5020         // Remove the previous editor components, if present. Only one
5021         // editor component at time is allowed in the table.
5022         removeAll();
5023         add(editorComp);
5024         moveToCellBeingEdited(editorComp);
5025         scrollRectToVisible(editorComp.getBounds());
5026         editorComp.requestFocusInWindow();
5027         
5028         // Deliver the should select event.
5029         return editor.shouldSelectCell(null);        
5030       }
5031   }
5032
5033   /**
5034    * Move the given component under the cell being edited. 
5035    * The table must be in the editing mode.
5036    * 
5037    * @param component the component to move.
5038    */
5039   private void moveToCellBeingEdited(Component component)
5040   {
5041      Rectangle r = getCellRect(editingRow, editingColumn, true);
5042      // Adjust bounding box of the editing component, so that it lies
5043      // 'above' the grid on all edges, not only right and bottom.
5044      // The table grid is painted only at the right and bottom edge of a cell.
5045      r.x -= 1;
5046      r.y -= 1;
5047      r.width += 1;
5048      r.height += 1;
5049      component.setBounds(r);
5050   }
5051
5052   /**
5053    * Programmatically starts editing the specified cell.
5054    *
5055    * @param row the row of the cell to edit.
5056    * @param column the column of the cell to edit.
5057    */
5058   public boolean editCellAt (int row, int column, EventObject e)
5059   {
5060     return editCellAt(row, column);
5061   }
5062
5063   /**
5064    * Discards the editor object.
5065    */
5066   public void removeEditor()
5067   {
5068     editingStopped(new ChangeEvent(this));
5069   }
5070
5071   /**
5072    * Prepares the editor by querying for the value and selection state of the
5073    * cell at (row, column).
5074    *
5075    * @param editor the TableCellEditor to set up
5076    * @param row the row of the cell to edit
5077    * @param column the column of the cell to edit
5078    * @return the Component being edited
5079    */
5080   public Component prepareEditor (TableCellEditor editor, int row, int column)
5081   {
5082     return editor.getTableCellEditorComponent
5083       (this, getValueAt(row, column), isCellSelected(row, column), row, column);
5084   }
5085
5086   /**
5087    * This revalidates the <code>JTable</code> and queues a repaint.
5088    */
5089   protected void resizeAndRepaint()
5090   {
5091     revalidate();
5092     repaint();
5093   }
5094
5095   /**
5096    * Sets whether cell editors of this table should receive keyboard focus
5097    * when the editor is activated by a keystroke. The default setting is
5098    * <code>false</code> which means that the table should keep the keyboard
5099    * focus until the cell is selected by a mouse click.
5100    *
5101    * @param value the value to set
5102    *
5103    * @since 1.4
5104    */
5105   public void setSurrendersFocusOnKeystroke(boolean value)
5106   {
5107     // TODO: Implement functionality of this property (in UI impl).
5108     surrendersFocusOnKeystroke = value;
5109   }
5110   
5111   /**
5112    * Returns whether cell editors of this table should receive keyboard focus
5113    * when the editor is activated by a keystroke. The default setting is
5114    * <code>false</code> which means that the table should keep the keyboard
5115    * focus until the cell is selected by a mouse click.
5116    *
5117    * @return whether cell editors of this table should receive keyboard focus
5118    *         when the editor is activated by a keystroke
5119    *
5120    * @since 1.4
5121    */
5122   public boolean getSurrendersFocusOnKeystroke()
5123   {
5124     // TODO: Implement functionality of this property (in UI impl).
5125     return surrendersFocusOnKeystroke;
5126   }
5127
5128   /**
5129    * Helper method for
5130    * {@link LookAndFeel#installProperty(JComponent, String, Object)}.
5131    * 
5132    * @param propertyName the name of the property
5133    * @param value the value of the property
5134    *
5135    * @throws IllegalArgumentException if the specified property cannot be set
5136    *         by this method
5137    * @throws ClassCastException if the property value does not match the
5138    *         property type
5139    * @throws NullPointerException if <code>c</code> or
5140    *         <code>propertyValue</code> is <code>null</code>
5141    */
5142   void setUIProperty(String propertyName, Object value)
5143   {
5144     if (propertyName.equals("rowHeight"))
5145       {
5146         if (! clientRowHeightSet)
5147           {
5148             setRowHeight(((Integer) value).intValue());
5149             clientRowHeightSet = false;
5150           }
5151       }
5152     else
5153       {
5154         super.setUIProperty(propertyName, value);
5155       }
5156   }
5157 }