OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [swing/] [JTable.java] - Blame information for rev 858

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.