001/* JTable.java -- 
002   Copyright (C) 2002, 2004, 2005, 2006  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing;
040
041import java.awt.Color;
042import java.awt.Component;
043import java.awt.Cursor;
044import java.awt.Dimension;
045import java.awt.Font;
046import java.awt.FontMetrics;
047import java.awt.Point;
048import java.awt.Rectangle;
049import java.awt.event.FocusListener;
050import java.beans.PropertyChangeEvent;
051import java.beans.PropertyChangeListener;
052import java.text.DateFormat;
053import java.text.NumberFormat;
054import java.util.Date;
055import java.util.EventObject;
056import java.util.Hashtable;
057import java.util.Locale;
058import java.util.Vector;
059
060import javax.accessibility.Accessible;
061import javax.accessibility.AccessibleComponent;
062import javax.accessibility.AccessibleContext;
063import javax.accessibility.AccessibleExtendedTable;
064import javax.accessibility.AccessibleRole;
065import javax.accessibility.AccessibleSelection;
066import javax.accessibility.AccessibleState;
067import javax.accessibility.AccessibleStateSet;
068import javax.accessibility.AccessibleTable;
069import javax.accessibility.AccessibleTableModelChange;
070import javax.swing.event.CellEditorListener;
071import javax.swing.event.ChangeEvent;
072import javax.swing.event.ListSelectionEvent;
073import javax.swing.event.ListSelectionListener;
074import javax.swing.event.TableColumnModelEvent;
075import javax.swing.event.TableColumnModelListener;
076import javax.swing.event.TableModelEvent;
077import javax.swing.event.TableModelListener;
078import javax.swing.plaf.TableUI;
079import javax.swing.table.DefaultTableCellRenderer;
080import javax.swing.table.DefaultTableColumnModel;
081import javax.swing.table.DefaultTableModel;
082import javax.swing.table.JTableHeader;
083import javax.swing.table.TableCellEditor;
084import javax.swing.table.TableCellRenderer;
085import javax.swing.table.TableColumn;
086import javax.swing.table.TableColumnModel;
087import javax.swing.table.TableModel;
088
089/**
090 * The table component, displaying information, organized in rows and columns.
091 * The table can be placed in the scroll bar and have the optional header
092 * that is always visible. Cell values may be editable after double clicking
093 * on the cell. Cell columns may have various data types, that are 
094 * displayed and edited by the different renderers and editors. It is possible
095 * to set different column width. The columns are also resizeable by 
096 * dragging the column boundary in the header.
097 */
098public class JTable
099  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}