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