KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > swingwtx > swing > JTable


1 /*
2    SwingWT
3    Copyright(c)2003-2004, R. Rawson-Tetley
4
5    For more information on distributing and using this program, please
6    see the accompanying "COPYING" file.
7
8    Contact me by electronic mail: bobintetley@users.sourceforge.net
9
10    $Log: JTable.java,v $
11    Revision 1.64 2004/05/06 16:48:04 laurentmartelli
12    Show "CellRenderer not JLabel" in the right cell
13
14    Revision 1.63 2004/05/06 00:16:39 laurentmartelli
15    Changed paramter name for setRowHeight(int,int) from col to height
16
17    Revision 1.62 2004/05/05 13:53:38 bobintetley
18    (Laurent Martelli) - CellRenderers warn if they do not return JLabel
19
20    Revision 1.61 2004/05/05 12:43:21 bobintetley
21    Patches/new files from Laurent Martell
22
23    Revision 1.60 2004/05/04 11:31:20 bobintetley
24    Additional cellrenderer methods
25
26    Revision 1.59 2004/05/01 09:32:18 bobintetley
27    Fix for null parents
28
29    Revision 1.58 2004/04/30 23:18:26 dannaab
30    List selection support, misc bug fixes
31
32    Revision 1.57 2004/04/28 08:38:12 bobintetley
33    Hierarchy fixes, code cleanup for base classes, additional javadocs and use of flag to identify JComponent descendants with peers
34
35    Revision 1.56 2004/04/19 13:19:11 bobintetley
36    Win32 fix for JTable editors
37
38    Revision 1.55 2004/04/19 10:49:37 bobintetley
39    Fix to cell editing with DefaultEditor/JComboBox and fix so JTable/JTree
40    cell renderers are used after editor updates
41
42    Revision 1.54 2004/04/18 14:59:42 bobintetley
43    Virtual table support (much much faster) and removal of deprecated API
44    for JClosableTabbedPane
45
46    Revision 1.53 2004/04/16 18:29:24 bobintetley
47    Fixes to JTable to only use TableCursors if necessary (at least one row of data and at least one editable column)
48
49    Revision 1.52 2004/04/16 14:38:47 bobintetley
50    Table and Tree cell editor support
51
52    Revision 1.51 2004/04/16 10:19:06 dannaab
53    Misc bug fixes, InputMap implementation, preliminary undo support
54
55    Revision 1.50 2004/04/15 11:24:33 bobintetley
56    (Dan Naab) ComponentUI, UIDefaults/UIManager and Accessibility support.
57    (Antonio Weber) TableColumnModelListener implementation and support
58
59    Revision 1.49 2004/04/07 06:20:23 bobintetley
60    Selection model MULTI/SINGLE translates correctly to SWT selection now
61
62    Revision 1.48 2004/04/06 12:30:53 bobintetley
63    JTable thread safety, ListSelectionModel implementation for JList/JTable
64
65    Revision 1.47 2004/04/06 10:50:37 bobintetley
66    Thread safety work
67
68    Revision 1.46 2004/03/31 08:07:38 bobintetley
69    JTable bug fixed that prevented it redrawing after being dropped from
70    a container. Protected component method allows catching of when a component
71    is removed from a container.
72
73    Revision 1.45 2004/03/30 10:42:46 bobintetley
74    Many minor bug fixes, event improvements by Dan Naab. Full swing.Icon support
75
76    Revision 1.44 2004/03/02 08:39:53 bobintetley
77    Less resource intensive event pump and JTable defaults gridlines now
78
79    Revision 1.43 2004/03/01 15:58:47 bobintetley
80    Various little bug fixes
81
82    Revision 1.42 2004/02/27 16:16:15 bobintetley
83    Threading fixes
84
85    Revision 1.41 2004/02/24 09:36:39 bobintetley
86    Compatibility methods
87
88    Revision 1.40 2004/02/23 12:11:24 bobintetley
89    JScrollPane bug fixed, tabbing in JTextArea fixed
90
91    Revision 1.39 2004/02/23 10:07:10 bobintetley
92    Cell render font support
93
94    Revision 1.38 2004/02/23 09:58:18 bobintetley
95    JTree/JTable now support fonts from cell renderer
96
97    Revision 1.37 2004/02/19 09:58:44 bobintetley
98    Various small bug fixes and JTextArea should be much faster/lighter
99
100    Revision 1.36 2004/02/13 15:09:23 bobintetley
101    JComboBox/Abstract button non-peer selection and JTable threading fixed
102
103    Revision 1.35 2004/02/13 12:36:24 bobintetley
104    JTable tracks model changes more efficiently
105
106    Revision 1.34 2004/01/27 11:06:09 bobintetley
107    Fixed bugs in dropping/re-adding the same components
108
109    Revision 1.33 2004/01/27 09:05:11 bobintetley
110    ListModel and List Selection implemented. ScrollPane fix so all components
111       scrollable
112
113    Revision 1.32 2004/01/26 11:14:26 bobintetley
114    Fix to colours in JTable cell rendering
115
116    Revision 1.31 2004/01/26 08:11:00 bobintetley
117    Many bugfixes and addition of SwingSet
118
119    Revision 1.30 2004/01/16 09:35:47 bobintetley
120    Full event dispatch thread support!
121
122    Revision 1.29 2004/01/12 10:58:12 bobintetley
123    JTable updates only changed rows when data changes
124
125    Revision 1.28 2004/01/08 15:36:59 bobintetley
126    Multiselection works correctly in tables and JList now
127
128    Revision 1.27 2004/01/07 09:26:25 bobintetley
129    Render widths now work correctly
130
131    Revision 1.26 2004/01/06 15:38:30 bobintetley
132    Adjusted render width calculations. Fixed horrible button border under Win32
133
134    Revision 1.25 2004/01/06 15:31:02 bobintetley
135    New render width function for accurate auto-sizing
136
137    Revision 1.24 2004/01/05 12:31:14 bobintetley
138    Table/List/Toolbar fixes for correct layout
139
140    Revision 1.23 2003/12/22 09:13:34 bobintetley
141    Fix to broken click events on JTable
142
143    Revision 1.22 2003/12/18 09:37:33 bobintetley
144    Enabled support for JTabbedPane and JClosableTabbedPane (SWT doesn't
145    support, so a bit of magic in here)
146
147    Revision 1.21 2003/12/17 17:27:20 bobintetley
148    Better table autosizing if no column widths are specified
149
150    Revision 1.20 2003/12/17 10:57:35 bobintetley
151    JTableHeader implementation plus Table event/model fixes
152
153    Revision 1.19 2003/12/16 17:46:17 bobintetley
154    Additional thread safety methods
155
156    Revision 1.18 2003/12/16 15:47:45 bobintetley
157    Thread safety added to common methods
158
159    Revision 1.17 2003/12/16 13:14:33 bobintetley
160    Use of SwingWTUtils.isSWTControlAvailable instead of null test
161
162    Revision 1.16 2003/12/16 12:23:31 bobintetley
163    Corrected handling of table selection + keyboard action events
164
165    Revision 1.15 2003/12/16 11:55:57 bobintetley
166    Removed debug code
167
168    Revision 1.14 2003/12/16 11:40:37 bobintetley
169    JTable refreshes now when model updates
170
171    Revision 1.13 2003/12/15 18:29:57 bobintetley
172    Changed setParent() method to setSwingWTParent() to avoid conflicts with applications
173
174    Revision 1.12 2003/12/15 16:40:04 bobintetley
175    Core methods + skeleton JTableHeader/JScrollBar support
176
177    Revision 1.11 2003/12/15 15:54:25 bobintetley
178    Additional core methods
179
180    Revision 1.10 2003/12/14 09:13:38 bobintetley
181    Added CVS log to source headers
182
183 */

184
185
186 package swingwtx.swing;
187
188 import swingwtx.swing.table.*;
189 import swingwtx.swing.table.TableColumn;
190 import swingwtx.swing.event.*;
191 import swingwt.awt.event.MouseEvent;
192
193 import org.eclipse.swt.widgets.*;
194 import org.eclipse.swt.*;
195
196 import java.util.*;
197
198
199
200 public class JTable extends swingwtx.swing.JComponent implements TableModelListener,
201                                                                  TableColumnModelListener,
202                                                                  ListSelectionListener,
203                                                                  CellEditorListener {
204
205     public static final int AUTO_RESIZE_OFF = 0;
206     public static final int AUTO_RESIZE_NEXT_COLUMN = 1;
207     public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
208     public static final int AUTO_RESIZE_LAST_COLUMN = 3;
209     public static final int AUTO_RESIZE_ALL_COLUMNS = 4;
210     
211     protected Table ppeer = null;
212     protected JTableHeader header = null;
213     private TableModel model = null;
214     protected TableColumnModel columnModel = null;
215     protected ListSelectionModel listSelectionModel = null;
216     protected TableCellEditor cellEditor = null;
217     protected int pRowHeight = 20;
218     protected swingwt.awt.Dimension pIntercell = null;
219     /** Cache - whether to show grid lines */
220     protected boolean pLines = true;
221     protected int pSelRow = -1;
222     protected int pSelCol = -1;
223     /** Cache of values for current cell editor */
224     protected int editingColumn = -1;
225     protected int editingRow = -1;
226     protected TableCellEditor editingEditor = null;
227     protected swingwt.awt.Component editingComponent = null;
228     /** Whether cell selection (and thus cell editing) is enabled */
229     protected boolean cellSelectionEnabled = true;
230     /** The SWT table editor */
231     protected org.eclipse.swt.custom.TableEditor swtEditor = null;
232     /** The SWT table cursor */
233     protected org.eclipse.swt.custom.TableCursor swtCursor = null;
234     
235     /** Whether the table has been displayed yet. If it has then we force a redraw
236      * when setSwingWTParent is called since it must mean it has been removed
237      * from a container and redrawn.
238      * This is used in conjunction with modelDirty to make sure we only fill
239      * the table from the model when we need to.
240      */

241     protected boolean tableDrawnOnce = false;
242
243     /** Whether the model has been changed. Used by setSwingWTParent to decide whether
244         or not to refresh the data. */

245     private boolean modelDirty = true;
246     private boolean columnModelDirty = true;
247
248      public JTable() {
249          this(null);
250      }
251      public JTable(int numRows, int numCols) {
252          this(new DefaultTableModel(numRows, numCols));
253      }
254      public JTable(Object JavaDoc[][] rowData, Object JavaDoc[] columnNames) {
255          this(new DefaultTableModel(rowData, columnNames));
256      }
257      public JTable(Vector rowData, Vector columnNames) {
258          this(new DefaultTableModel(rowData, columnNames));
259      }
260      public JTable(TableModel dm) {
261          this(dm, null);
262      }
263      public JTable(TableModel dm, TableColumnModel columnModel) {
264          this(dm, columnModel, null);
265      }
266      public JTable(TableModel dm, TableColumnModel columnModel, ListSelectionModel selectionModel) {
267
268          if (dm == null)
269              dm = new DefaultTableModel();
270
271          if (columnModel == null) {
272              model = dm;
273              generateDefaultColumnModel();
274              columnModel = this.columnModel;
275          }
276
277          if (selectionModel == null)
278              selectionModel = new DefaultListSelectionModel(this);
279
280          setModel(dm);
281          setColumnModel(columnModel);
282          setSelectionModel(selectionModel);
283          setCellEditor(new DefaultCellEditor(new JTextField()));
284          
285      }
286
287     public TableModel getModel() { return model; }
288     public void setModel(TableModel dm, boolean noRefresh) {
289         if (model == dm) return;
290         model = dm;
291         generateDefaultColumnModel();
292         model.addTableModelListener(this);
293     }
294     public void setModel(TableModel dm) {
295         setModel(dm, true);
296         modelDirty = true;
297         refreshTable();
298     }
299     public void clearSelection() { if (!SwingWTUtils.isSWTControlAvailable(ppeer)) return; ppeer.deselectAll(); }
300     public void doLayout() { refreshTable(); }
301     public int getColumnCount() { return model.getColumnCount(); }
302     public String JavaDoc getColumnName(int index) { return model.getColumnName(index); }
303     public swingwtx.swing.table.TableColumn getColumn(Object JavaDoc identifier) { return columnModel.getColumn(columnModel.getColumnIndex(identifier)); }
304     public swingwtx.swing.table.TableColumn getColumn(int index) { return columnModel.getColumn(index); }
305     public int getRowCount() { return model.getRowCount(); }
306     /** NOT IMPLEMENTED */
307     public int getSelectedColumn() { if (!SwingWTUtils.isSWTControlAvailable(ppeer)) return pSelCol; else return -1; }
308     /** NOT IMPLEMENTED */
309     public int getSelectedColumnCount() { return 0; }
310     /** NOT IMPLEMENTED */
311     public int[] getSelectedColumns() { return null; }
312     public int getSelectedRow() {
313         final int[] sel = new int[1];
314         SwingUtilities.invokeSync(new Runnable JavaDoc() {
315             public void run() {
316                 if (!SwingWTUtils.isSWTControlAvailable(ppeer))
317                     sel[0] = pSelRow;
318                 else
319                     sel[0] = ppeer.getSelectionIndex();
320             }
321         });
322         return sel[0];
323     }
324     public int getSelectedRowCount() {
325         final int[] sel = new int[1];
326         SwingUtilities.invokeSync(new Runnable JavaDoc() {
327             public void run() {
328                 if (!SwingWTUtils.isSWTControlAvailable(ppeer))
329                     sel[0] = 0;
330                 else
331                     sel[0] = ppeer.getSelectionCount();
332                 }
333         });
334         return sel[0];
335     }
336     private int[] selRows = new int[0];
337     public int[] getSelectedRows() {
338         SwingUtilities.invokeSync(new Runnable JavaDoc() {
339             public void run() {
340                 if (!SwingWTUtils.isSWTControlAvailable(ppeer))
341                     selRows = null;
342                 else
343                     selRows = ppeer.getSelectionIndices();
344             }
345         });
346         return selRows;
347     }
348     public boolean getShowHorizontalLines() { return isShowGrid(); }
349     public boolean isShowHorizontalLines() { return isShowGrid(); }
350     public boolean getShowVerticalLines() { return isShowGrid(); }
351     public boolean isShowVerticalLines() { return isShowGrid(); }
352     public boolean getShowGrid() { return isShowGrid(); }
353     public boolean isShowGrid() {
354         final boolean[] ret = new boolean[1];
355         SwingUtilities.invokeSync(new Runnable JavaDoc() {
356             public void run() {
357                 if (!SwingWTUtils.isSWTControlAvailable(ppeer))
358                     ret[0] = false;
359                 else
360                     ret[0] = ppeer.getLinesVisible();
361             }
362         });
363         return ret[0];
364     }
365     public void setShowHorizontalLines(boolean b) { setShowGrid(b); }
366     public void setShowVerticalLines(boolean b) { setShowGrid(b); }
367     public void setShowGrid(final boolean b) {
368         SwingUtilities.invokeSync(new Runnable JavaDoc() {
369             public void run() {
370                 if (!SwingWTUtils.isSWTControlAvailable(ppeer))
371                     pLines = b;
372                 else
373                     ppeer.setLinesVisible(b);
374             }
375         });
376     }
377     public Object JavaDoc getValueAt(int row, int col) { return model.getValueAt(row, col); }
378     public void resizeAndRepaint() { refreshTable(); }
379     public void selectAll() { if (SwingWTUtils.isSWTControlAvailable(ppeer)) ppeer.selectAll(); }
380     public void setValueAt(Object JavaDoc value, int row, int col) { model.setValueAt(value, row, col); }
381     public TableColumnModel getColumnModel() { return columnModel; }
382     /** NOT IMPLEMENTED - just override the column model produced - you won't even notice */
383     public void setAutoCreateColumnsFromModel(boolean b) {}
384     public void setColumnModel(TableColumnModel model) {
385         if (columnModel == model) return;
386         columnModel = model;
387         modelDirty = true;
388         refreshTable();
389         columnModel.addColumnModelListener(this);
390     }
391     /** NOT IMPLEMENTED */
392     public void setRowSelectionAllowed(boolean b) { }
393     /** NOT IMPLEMENTED */
394     public void setColumnSelectionAllowed(boolean b) { }
395     public boolean getRowSelectionAllowed(boolean b) { return true; }
396     public void setCellSelectionEnabled(boolean b) { cellSelectionEnabled = b; modelDirty = true; refreshTable(); }
397     public boolean getCellSelectionEnabled(boolean b) { return cellSelectionEnabled; }
398     public boolean getColumnSelectionAllowed(boolean b) { return false; }
399     /** NOT IMPLEMENTED - HARD RETURNS A COLOUR VALUE */
400     public swingwt.awt.Color getSelectionBackground() { return swingwt.awt.Color.BLUE; }
401     /** NOT IMPLEMENTED - HARD RETURNS A COLOUR VALUE */
402     public swingwt.awt.Color getSelectionForeground() { return swingwt.awt.Color.WHITE; }
403     /** NOT IMPLEMENTED - MEANINGLESS TO PLATFORM TABLE */
404     public void setSelectionBackground(swingwt.awt.Color c) {}
405     /** NOT IMPLEMENTED - MEANINGLESS TO PLATFORM TABLE */
406     public void setSelectionForeground(swingwt.awt.Color c) {}
407     /** NOT IMPLEMENTED */
408     public void setIntercellSpacing(swingwt.awt.Dimension d) { pIntercell = d; }
409     public swingwt.awt.Dimension getIntercellSpacing() { if (pIntercell == null) return new swingwt.awt.Dimension(0, 0); else return pIntercell; }
410     public int getRowHeight() { return pRowHeight; }
411     /** NOT IMPLEMENTED */
412     public void setRowHeight(int height) { pRowHeight = height; }
413     /** NOT IMPLEMENTED */
414     public void setRowHeight(int row, int height) { setRowHeight(height); }
415     /** NOT IMPLEMENTED */
416     public int rowAtPoint(swingwt.awt.Point p) { return -1; }
417     /** NOT IMPLEMENTED */
418     public int getAutoResizeMode() { return 0; }
419     /** NOT IMPLEMENTED */
420     public void setAutoResizeMode(int size) {}
421
422     public ListSelectionModel getSelectionModel() { return listSelectionModel; }
423     public void setSelectionModel(ListSelectionModel l) {
424         if (l != null) {
425             listSelectionModel = l;
426             l.addListSelectionListener(this);
427         }
428     }
429
430     public void setSelectionMode(int mode) {
431         listSelectionModel.setSelectionMode(mode);
432     }
433
434     public TableCellRenderer getCellRenderer(int row, int column) {
435     return columnModel.getColumn(column).getCellRenderer();
436     }
437
438     public swingwt.awt.Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
439     return renderer.getTableCellRendererComponent( this,
440         getValueAt(row,column),
441         isCellSelected(row,column),
442         false /*TODO*/,
443         row,
444         column);
445     }
446
447     public boolean isCellSelected(int row, int col) {
448     int srow = -1;
449     int scol = -1;
450     try {
451             srow = ((Integer JavaDoc) swtCursor.getRow().getData("rowindex")).intValue();
452             scol = swtCursor.getColumn();
453     }
454     catch (Exception JavaDoc e) {}
455     if (srow == row && scol == col) return true;
456     if (getSelectedRow() == row) return true;
457     return false;
458     }
459
460     /**
461      * Tells the table that it needs to redraw when
462      * refreshTable() is next called.
463      * @param Whether the table should be redrawn
464      * when refreshTable() is next called.
465      */

466     public void setModelDirty(boolean b) {
467         modelDirty = b;
468     }
469
470     public void changeSelection(final int row, final int col, final boolean toggle, final boolean extend) {
471         pSelRow = row;
472         pSelCol = col;
473         SwingUtilities.invokeSync(new Runnable JavaDoc() {
474             public void run() {
475                 if (SwingWTUtils.isSWTControlAvailable(ppeer))
476                     ppeer.setSelection(row);
477             }
478         });
479     }
480
481     /** Scrolls the table to the selected row. This is not a Swing method */
482     public void showSelection() {
483         SwingUtilities.invokeSync(new Runnable JavaDoc() {
484             public void run() {
485                 if (SwingWTUtils.isSWTControlAvailable(ppeer))
486                     ppeer.showSelection();
487             }
488         });
489     }
490
491     /**
492      * SWT table columns aren't movable, so columnIndex == modelIndex
493      */

494     public int convertColumnIndexToModel(int index) {
495         return index;
496     }
497
498     /**
499      * Given that we have a valid table model, generates the default
500      * column model for it.
501      */

502     private void generateDefaultColumnModel() {
503         columnModel = new DefaultTableColumnModel();
504         for (int i = 0; i < model.getColumnCount(); i++) {
505
506             swingwtx.swing.table.TableColumn tc = new swingwtx.swing.table.TableColumn();
507
508             // Column width calculation
509
//int colWidth = (model.getColumnName(i).length() * 10) * 2;
510
int colWidth = 0;
511             // Set values
512
tc.setWidth(colWidth);
513             tc.setPreferredWidth(colWidth);
514             tc.setMaxWidth(colWidth);
515             tc.setMinWidth(colWidth);
516             tc.setHeaderValue(model.getColumnName(i));
517             tc.setIdentifier(model.getColumnName(i));
518             tc.setCellRenderer(new DefaultTableCellRenderer());
519             tc.setCellEditor(cellEditor); // Default the cell editor for the whole table
520
tc.setModelIndex(i);
521             tc.setResizable(true);
522
523             columnModel.addColumn(tc);
524         }
525     }
526
527     public JTableHeader getTableHeader() {
528         if (header == null)
529             header = new JTableHeader(this);
530         return header;
531     }
532
533     /**
534      * Once a parent component receives an "add" call for a child, this being
535      * the child, this should be called to tell us to instantiate the peer
536      * and load in any cached properties.
537      */

538     public void setSwingWTParent(swingwt.awt.Container parent) throws Exception JavaDoc {
539         descendantHasPeer = true;
540         ppeer = new Table(parent.getComposite(), SWT.BORDER );
541         peer = ppeer;
542         this.parent = parent;
543         
544         // Cached values
545
ppeer.setLinesVisible(pLines);
546
547         // Is this the first time? If it is, then don't do anything as we've
548
// taken care of that stuff. If not, force a reload as this must be
549
// added to a container for the nth time so the data will need to
550
// be reloaded, irrespective of whether the model is dirty.
551
if (!tableDrawnOnce)
552             tableDrawnOnce = true;
553         else
554             setDirty(true);
555
556         // Load data if necessary
557
if (modelDirty) refreshTable();
558
559         // Selection
560
if (pSelRow != -1) ppeer.setSelection(pSelRow);
561     }
562
563     /**
564      * Sets whether the model is dirty for forcing updates
565      */

566     public void setDirty(boolean b) {
567         modelDirty = b;
568     }
569
570     /**
571      * Forces a complete rebuild of the peer from the
572      * data model.
573      */

574     public void refreshTable() {
575
576         // Don't do anything if the model hasn't changed
577
if (!modelDirty) return;
578         modelDirty = false;
579
580         final JTable table = this;
581         SwingUtilities.invokeSync(new Runnable JavaDoc() {
582             public void run() {
583                 // Don't do anything if we can't see the table anyway - the
584
// model is still dirty though
585
if (!SwingWTUtils.isSWTControlAvailable(ppeer)) { modelDirty = true; return; }
586
587                 // Clear out everything from the peer if necessary
588
ppeer.removeAll();
589                 ppeer.setHeaderVisible(true);
590
591                 // Regenerate SWT table columns
592

593                 // Drop any existing columns by redoing the table
594
ppeer.dispose();
595                 
596                 // Some components don't have a layout
597
if (parent.getLayout() != null)
598                     parent.getLayout().removeLayoutComponent(table);
599                 
600                 ppeer = new Table(parent.getComposite(), SWT.BORDER |
601             (listSelectionModel.getSelectionMode() == ListSelectionModel.MULTIPLE_INTERVAL_SELECTION ? SWT.MULTI : SWT.SINGLE) |
602             (!cellSelectionEnabled ? SWT.FULL_SELECTION : SWT.NONE) |
603                         SWT.VIRTUAL
604                         );
605                                                         
606                 parent.addComponentToLayout(table);
607                 ppeer.setHeaderVisible(true);
608                 peer = ppeer;
609
610                 // Lay it out so we see it
611
parent.invalidate();
612
613                 for (int i = 0; i < columnModel.getColumnCount(); i++) {
614
615                     org.eclipse.swt.widgets.TableColumn tc =
616                         new org.eclipse.swt.widgets.TableColumn(ppeer, 0);
617
618                     tc.setText(columnModel.getColumn(i).getHeaderValue().toString());
619                     tc.setResizable(columnModel.getColumn(i).isResizable());
620
621                     // If no col width was set in the model, use the width of
622
// the text in the column as a starting point, then scan all the data
623
// in the column to find the widest one
624
if (columnModel.getColumn(i).getWidth() == 0) {
625                         int colwidth = SwingWTUtils.getRenderStringWidth(columnModel.getColumn(i).getHeaderValue().toString());
626                         int contentwidth = 0;
627                         for (int z = 0; z < model.getRowCount(); z++) {
628                             Object JavaDoc value = model.getValueAt(z, i);
629                             if (value == null) value = "";
630                             contentwidth = (SwingWTUtils.getRenderStringWidth(value.toString()));
631                             if (contentwidth > colwidth) colwidth = contentwidth;
632                         }
633                         tc.setWidth(colwidth);
634                     }
635                     else
636                         tc.setWidth(columnModel.getColumn(i).getWidth());
637
638                     // Event catcher for a column being clicked
639
final int index = i;
640                     tc.addSelectionListener( new org.eclipse.swt.events.SelectionListener() {
641                         public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
642                             processColumnClick(index);
643                         }
644                         public void widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent e) {}
645                     });
646                 }
647
648                 // Cached values and events
649
ppeer.setLinesVisible(pLines);
650                 setCachedProperties();
651                 registerEvents();
652
653         // Create a cursor and editor if there's some data and
654
// at least one editable cell. This is because the cursors frankly look
655
// like total shite, so we need to avoid them if the table isn't editable.
656
if (model.getRowCount() > 0) {
657             boolean hasOneEditableColumn = false;
658                 for (int i = 0; i < model.getColumnCount(); i++)
659             if (model.isCellEditable(0, i)) hasOneEditableColumn = true;
660             if (hasOneEditableColumn) {
661                         swtEditor = new org.eclipse.swt.custom.TableEditor(ppeer);
662                         createTableCursor();
663             }
664         }
665                 
666                 // Set the data size within the table
667
ppeer.setItemCount(model.getRowCount());
668                 
669                 // Set a callback on the table peer for loading
670
// items from the model.
671
ppeer.addListener (SWT.SetData, new Listener () {
672                     public void handleEvent (Event event) {
673                         
674                         TableItem ti = (TableItem) event.item;
675                         int i = ppeer.indexOf(ti);
676                         
677                         // Store index for retrieval from table cursor
678
ti.setData("rowindex", new Integer JavaDoc(i));
679                         
680                         for (int z = 0; z < model.getColumnCount(); z++) {
681
682                             // Get the cell renderer for this item
683
swingwt.awt.Component cr =
684                                 columnModel.getColumn(z).getCellRenderer().getTableCellRendererComponent(
685                                     table, model.getValueAt(i, z),
686                                     getSelectedRow() == i,
687                                     true,
688                                     i, z);
689                             
690                             if (cr instanceof JLabel) {
691                                 
692                                 JLabel renderer = (JLabel) cr;
693
694                                 // Use the text from the renderer
695
ti.setText(z, renderer.getText() );
696
697                                 // If there's an image, render it:
698
if (renderer.getIcon() != null)
699                                     ti.setImage(z, SwingWTUtils.getSWTImageFromSwingIcon(table, renderer.getIcon()));
700
701                                 // Colours
702
if (renderer.getBackground() != null)
703                                     if (renderer.getBackground().getSWTColor() != null)
704                                         ti.setBackground(z, renderer.getBackground().getSWTColor());
705                                 if (renderer.getForeground() != null)
706                                     if (renderer.getForeground().getSWTColor() != null)
707                                         ti.setForeground(z, renderer.getForeground().getSWTColor());
708
709                                 // Font
710
if (renderer.hasSetFont())
711                                     ti.setFont(z, renderer.getFont().getSWTFont());
712                                 
713                             }
714                             else
715                                 ti.setText(z,"CellRenderer not JLabel: " + cr.getClass().getName());
716                         }
717                     }
718                 });
719             }
720         });
721     }
722
723     /**
724      * Just like refreshTable(), except it does not generate
725      * the column headers and only updates the rows specified.
726      * This is used for change events from the model.
727      */

728     public void refreshTable(final int rowFrom, final int rowTo) {
729
730         // Don't do anything if the model hasn't changed
731
if (!modelDirty) return;
732         modelDirty = false;
733
734         final JTable table = this;
735         SwingUtilities.invokeAsync(new Runnable JavaDoc() {
736             public void run() {
737                 // Don't do anything if we can't see the table anyway
738
if (!SwingWTUtils.isSWTControlAvailable(ppeer)) return;
739                 // Now that we have those, lets generate the
740
// table data
741
for (int i = rowFrom; i < model.getRowCount() && i < rowTo; i++) {
742                     TableItem ti = ppeer.getItem(i);
743                     for (int z = 0; z < model.getColumnCount(); z++) {
744
745                         // Get the cell renderer for this item
746
swingwt.awt.Component cr =
747                             columnModel.getColumn(z).getCellRenderer().getTableCellRendererComponent(
748                                 table, model.getValueAt(i, z),
749                                 getSelectedRow() == i,
750                                 true,
751                                 i, z);
752
753                         if (cr instanceof JLabel) {
754                             
755                             JLabel renderer = (JLabel) cr;
756                             
757                             // Use the text from the renderer
758
ti.setText(z, renderer.getText() );
759
760                             // If there's an image, render it:
761
if (renderer.getIcon() != null)
762                                 ti.setImage(z, SwingWTUtils.getSWTImageFromSwingIcon(table, renderer.getIcon()));
763
764                             // Colours
765
if (renderer.getBackground() != null)
766                                 if (renderer.getBackground().getSWTColor() != null)
767                                     ti.setBackground(z, renderer.getBackground().getSWTColor());
768                             if (renderer.getForeground() != null)
769                                 if (renderer.getForeground().getSWTColor() != null)
770                                     ti.setForeground(z, renderer.getForeground().getSWTColor());
771
772                             // Font
773
if (renderer.hasSetFont())
774                                 ti.setFont(z, renderer.getFont().getSWTFont());
775                         }
776                         else
777                             ti.setText("CellRenderer must descend JLabel");
778                     }
779                 }
780             }
781         });
782
783     }
784
785     /**
786      * Assigns events to the cursor for selection so that we can
787      * update the ListSelectionModel for this component.
788      */

789     protected void registerSelectionEvents() {
790         final JTable pthis = this;
791         swtCursor.addSelectionListener( new org.eclipse.swt.events.SelectionAdapter() {
792             public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
793                 processListSelection();
794                 processCellEdit();
795                 
796             }
797         });
798     }
799     
800     /**
801      * Called back when a row/cell is selected in the table
802      * to fire events on to user processes.
803      */

804     protected void processListSelection() {
805         // Handle ListSelectionModel
806
if (listSelectionModel instanceof DefaultListSelectionModel) {
807             if (listSelectionModel.getSelectionMode() == ListSelectionModel.MULTIPLE_INTERVAL_SELECTION) {
808                 int lowest = ppeer.getSelectionIndex(); int highest = ppeer.getSelectionIndex();
809                 int sel[] = ppeer.getSelectionIndices();
810                 for (int i = 0; i < sel.length; i++) {
811                     if (lowest > sel[i]) lowest = sel[i];
812                     if (highest < sel[i]) highest = sel[i];
813                 }
814                 ((DefaultListSelectionModel) listSelectionModel).fireListSelectionEvent(JTable.this, lowest, highest);
815             }
816             else {
817                 ((DefaultListSelectionModel) listSelectionModel).fireListSelectionEvent(JTable.this, ppeer.getSelectionIndex(),
818                                                                                         ppeer.getSelectionIndex());
819             }
820         }
821     }
822     
823     
824     /**
825      * Called back when the user selects a cell in the table
826      * to handle the editing
827      */

828     protected void processCellEdit() {
829               
830         // If cell selection isn't enabled, don't bother - we can't edit
831
if (!cellSelectionEnabled) return;
832         
833         // If we have no cursor, then we're in the middle of something and it's
834
// gone wrong so try to recover as best we can and bail !
835
if (swtCursor != null) {
836             if (swtCursor.isDisposed()) {
837                 createTableCursor();
838                 return;
839             }
840     }
841     else {
842         // If the cursor isn't created, we don't have any data
843
// so there's nothing to edit
844
return;
845     }
846         
847         // Identify selected row and column
848
editingRow = ((Integer JavaDoc) swtCursor.getRow().getData("rowindex")).intValue();
849         editingColumn = swtCursor.getColumn();
850         
851         // If the model says we can't edit this field, don't do it
852
if (!model.isCellEditable(editingRow, editingColumn)) return;
853         
854         // Get the editing component for the column
855
editingEditor = columnModel.getColumn(editingColumn).getCellEditor();
856         if (editingEditor == null) editingEditor = cellEditor;
857         editingComponent = editingEditor.getTableCellEditorComponent(this, model.getValueAt(editingRow, editingColumn), true, editingRow, editingColumn);
858
859         // Make sure we are listening for changes to the editor
860
if (editingEditor instanceof DefaultCellEditor)
861             if (((DefaultCellEditor) editingEditor).getCellEditorListeners() == null)
862                 editingEditor.addCellEditorListener(this);
863         
864         // Clean up any previous editor
865
if (swtEditor != null) {
866             if (swtEditor.getEditor() != null)
867                 swtEditor.getEditor().dispose();
868             swtEditor.dispose();
869             swtEditor = null;
870         }
871         
872         // Get current SWT row
873
TableItem item = ppeer.getItem(editingRow);
874
875         // The control that will be the editor must be a child of the Table.
876
// I use a private class here that basically pretends to be a
877
// container, but allows containment of an SWT Table (which isn't
878
// really a container, but needs to be for the editor)
879
try {
880             editingComponent.setSwingWTParent(new TableEditorContainer(this));
881             editingComponent.registerEvents();
882         }
883         catch (Exception JavaDoc e) {
884             e.printStackTrace();
885         }
886
887         // Destroy the cursor
888
swtCursor.dispose();
889         
890         // Open the editor in the right place
891
swtEditor = new org.eclipse.swt.custom.TableEditor(ppeer);
892         swtEditor.horizontalAlignment = SWT.LEFT;
893         swtEditor.grabHorizontal = true;
894         swtEditor.minimumWidth = 50;
895         swtEditor.setEditor(editingComponent.getPeer(), item, editingColumn);
896         
897         // Make sure the value is correct
898
if (editingEditor instanceof DefaultCellEditor) {
899             ((DefaultCellEditor) editingEditor).getHandler().setValue(model.getValueAt(editingRow, editingColumn));
900         }
901
902         // Assign focus to the editor
903
editingComponent.grabFocus();
904
905     }
906     
907     /** Callback when the editor is cancelled - need to regenerate the table cursor*/
908     public void editingCanceled(ChangeEvent e) {
909         createTableCursor();
910     }
911     
912     /** Callback when the editor is stopped - need to regenerate the table cursor
913      * and put any changes back into the model.
914      */

915     public void editingStopped(ChangeEvent e) {
916         // Get new value
917
Object JavaDoc value = editingEditor.getCellEditorValue();
918         
919         // Update model values
920
model.setValueAt(value, editingRow, editingColumn);
921         // Update the on-screen value
922
//ppeer.getItem(editingRow).setText(editingColumn, value.toString());
923
modelDirty = true;
924         refreshTable(editingRow, editingRow + 1);
925         
926         // Recreate the cursor
927
createTableCursor();
928     }
929
930     /**
931      * When a column is clicked by the user, this routine gets fired,
932      * which generates a mouse event for the thing and then
933      * sends it to the TableHeader mouseEvent listeners for
934      * dispatch to the user process
935      */

936     protected void processColumnClick(int index) {
937
938         // If the TableColumnModel is compatible, store
939
// the last clicked index there
940
if (columnModel instanceof DefaultTableColumnModel)
941             ((DefaultTableColumnModel) columnModel).lastColClicked = index;
942
943         MouseEvent e = new MouseEvent(this.getTableHeader());
944         e.eventID = MouseEvent.CLICKED;
945         e.setX(SwingWTUtils.getDisplay().getCursorLocation().x);
946         e.setY(SwingWTUtils.getDisplay().getCursorLocation().y);
947         e.setButton(SWT.BUTTON1);
948         e.clickCount = 1;
949         getTableHeader().processMouseEvent(e);
950     }
951     
952     
953     public TableCellEditor getCellEditor() {
954         return cellEditor;
955     }
956     
957     public TableCellEditor getCellEditor(int row, int col) {
958         return cellEditor;
959     }
960     
961     public void setCellEditor(TableCellEditor cell) {
962         cellEditor = cell;
963         cellEditor.addCellEditorListener(this);
964     }
965
966     public int getEditingColumn() {
967         return getSelectedColumn();
968     }
969     
970     public void setEditingColumn(int aColumn) {
971         editingColumn = aColumn;
972     }
973     
974     public int getEditingRow() {
975         return getSelectedRow();
976     }
977     
978     public void setEditingRow(int aRow) {
979         editingRow = aRow;
980         changeSelection(aRow, editingColumn, false, false);
981     }
982     
983     /**
984      * Called by the model to let us know when things change.
985      */

986     public void tableChanged(TableModelEvent e) {
987         modelDirty = true;
988         // Redraw if all the columns have changed - this means
989
// that some kind of structure change took place.
990
if (e.getColumn() == TableModelEvent.ALL_COLUMNS)
991             refreshTable();
992         else
993             // otherwise, just update the data in the changed rows
994
refreshTable(e.getFirstRow(), e.getLastRow());
995     }
996
997     public void valueChanged(ListSelectionEvent e) {
998         columnSelectionChanged(e);
999     }
1000
1001    public void columnAdded(TableColumnModelEvent e) {
1002        modelDirty = true;
1003        refreshTable();
1004    }
1005
1006    public void columnMarginChanged(ChangeEvent e) {
1007        // FIXME: Not implemented
1008
}
1009
1010    public void columnMoved(TableColumnModelEvent e) {
1011        modelDirty = true;
1012        refreshTable();
1013    }
1014
1015    public void columnRemoved(TableColumnModelEvent e) {
1016        modelDirty = true;
1017        refreshTable();
1018    }
1019
1020    public void columnSelectionChanged(ListSelectionEvent e) {
1021        // FIXME: Not implemented
1022
}
1023
1024    /** Creates the table cursor and maps events to it */
1025    protected void createTableCursor() {
1026        swtCursor = new org.eclipse.swt.custom.TableCursor(ppeer, SWT.NONE);
1027        registerSelectionEvents();
1028    }
1029    
1030    /**
1031     * A class containing an SWT table that pretends to be a container
1032     * - this is for cell editing purposes.
1033     */

1034    private class TableEditorContainer extends swingwt.awt.Container {
1035        public TableEditorContainer(JTable parent) {
1036            this.peer = parent.getPeer();
1037            this.composite = (org.eclipse.swt.widgets.Composite) parent.getPeer();
1038        }
1039    }
1040
1041    public boolean isEditing() {
1042    boolean isEdit = false;
1043    isEdit = swtCursor != null; // If cursor is null we can't be editing
1044
if (swtCursor != null)
1045        isEdit = swtCursor.isDisposed(); // Cursor is disposed during edit
1046
return isEdit;
1047    }
1048
1049    public void removeColumn(TableColumn tableColumn) {
1050        getColumnModel().removeColumn(tableColumn);
1051    }
1052
1053}
1054
Popular Tags