KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jdesktop > swing > JXTreeTable


1 /*
2  * $Id: JXTreeTable.java,v 1.18 2005/02/22 17:12:07 kleopatra Exp $
3  *
4  * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
5  * Santa Clara, California 95054, U.S.A. All rights reserved.
6  */

7
8
9 package org.jdesktop.swing;
10
11 import java.util.Enumeration JavaDoc;
12 import java.util.EventObject JavaDoc;
13 import java.util.Enumeration JavaDoc;
14
15 import java.awt.Color JavaDoc;
16 import java.awt.Component JavaDoc;
17 import java.awt.Dimension JavaDoc;
18 import java.awt.Graphics JavaDoc;
19 import java.awt.Point JavaDoc;
20 import java.awt.Rectangle JavaDoc;
21 import java.awt.event.ActionEvent JavaDoc;
22 import java.awt.event.InputEvent JavaDoc;
23 import java.awt.event.MouseEvent JavaDoc;
24 import java.beans.PropertyChangeEvent JavaDoc;
25 import java.beans.PropertyChangeListener JavaDoc;
26
27 import javax.swing.ActionMap JavaDoc;
28 import javax.swing.BorderFactory JavaDoc;
29 import javax.swing.Icon JavaDoc;
30 import javax.swing.JTable JavaDoc;
31 import javax.swing.JTree JavaDoc;
32 import javax.swing.ListSelectionModel JavaDoc;
33 import javax.swing.SwingUtilities JavaDoc;
34 import javax.swing.UIManager JavaDoc;
35 import javax.swing.border.Border JavaDoc;
36 import javax.swing.event.ListSelectionEvent JavaDoc;
37 import javax.swing.event.ListSelectionListener JavaDoc;
38 import javax.swing.event.TreeExpansionEvent JavaDoc;
39 import javax.swing.event.TreeExpansionListener JavaDoc;
40 import javax.swing.event.TreeModelEvent JavaDoc;
41 import javax.swing.event.TreeModelListener JavaDoc;
42 import javax.swing.plaf.UIResource JavaDoc;
43 import javax.swing.plaf.basic.BasicTreeUI JavaDoc;
44 import javax.swing.table.AbstractTableModel JavaDoc;
45 import javax.swing.table.TableCellRenderer JavaDoc;
46 import javax.swing.table.TableModel JavaDoc;
47 import javax.swing.tree.DefaultTreeCellRenderer JavaDoc;
48 import javax.swing.tree.DefaultTreeSelectionModel JavaDoc;
49 import javax.swing.tree.TreeCellRenderer JavaDoc;
50 import javax.swing.tree.TreePath JavaDoc;
51 import javax.swing.tree.TreeSelectionModel JavaDoc;
52
53 import org.jdesktop.swing.decorator.ComponentAdapter;
54 import org.jdesktop.swing.treetable.AbstractTreeTableModel;
55 import org.jdesktop.swing.treetable.DefaultTreeTableModel;
56 import org.jdesktop.swing.treetable.TreeTableCellEditor;
57 import org.jdesktop.swing.treetable.TreeTableModel;
58
59 /**
60  * <p><code>JXTreeTable</code> is a specialized {@link javax.swing.JTable table}
61  * consisting of a single column in which to display hierarchical data, and any
62  * number of other columns in which to display regular data. The interface for
63  * the data model used by a <code>JXTreeTable</code> is
64  * {@link org.jdesktop.swing.treetable.TreeTableModel}. It extends the
65  * {@link javax.swing.tree.TreeModel} interface to allow access to cell data by
66  * column indices within each node of the tree hierarchy.</p>
67  *
68  * <p>The most straightforward way create and use a <code>JXTreeTable</code>, is to
69  * first create a suitable data model for it, and pass that to a
70  * <code>JXTreeTable</code> constructor, as shown below:
71  * <pre>
72  * TreeTableModel treeTableModel = new FileSystemModel(); // any TreeTableModel
73  * JXTreeTable treeTable = new JXTreeTable(treeTableModel);
74  * JScrollPane scrollpane = new JScrollPane(treeTable);
75  * </pre>
76  * See {@link javax.swing.JTable} for an explanation of why putting the treetable
77  * inside a scroll pane is necessary.</p>
78  *
79  * <p>A single treetable model instance may be shared among more than one
80  * <code>JXTreeTable</code> instances. To access the treetable model, always call
81  * {@link #getTreeTableModel() getTreeTableModel} and
82  * {@link #setTreeTableModel(org.jdesktop.swing.treetable.TreeTableModel) setTreeTableModel}.
83  * <code>JXTreeTable</code> wraps the supplied treetable model inside a private
84  * adapter class to adapt it to a {@link javax.swing.table.TableModel}. Although
85  * the model adapter is accessible through the {@link #getModel() getModel} method, you
86  * should avoid accessing and manipulating it in any way. In particular, each
87  * model adapter instance is tightly bound to a single table instance, and any
88  * attempt to share it with another table (for example, by calling
89  * {@link #setModel(javax.swing.table.TableModel) setModel})
90  * will throw an <code>IllegalArgumentException</code>!
91  *
92  * @author Philip Milne
93  * @author Scott Violet
94  * @author Ramesh Gupta
95  */

96 public class JXTreeTable extends JXTable {
97     // TOTAL HACK to fix icons that disappeared in a regression after M3!
98
private Icon JavaDoc collapsedIcon = null;
99     private Icon JavaDoc expandedIcon = null;
100     private Icon JavaDoc closedIcon = null;
101     private Icon JavaDoc openIcon = null;
102     private Icon JavaDoc leafIcon = null;
103
104     /**
105      * Renderer used to render cells within the
106      * {@link #isHierarchical(int) hierarchical} column.
107      */

108     private TreeTableCellRenderer renderer = null;
109     // renderer extends JXTree and implements TableCellRenderer
110

111     /**
112      * Constructs a JXTreeTable using a
113      * {@link org.jdesktop.swing.treetable.DefaultTreeTableModel}.
114      */

115     public JXTreeTable() {
116         this(new DefaultTreeTableModel());
117     }
118
119     /**
120      * Constructs a JXTreeTable using the specified
121      * {@link org.jdesktop.swing.treetable.TreeTableModel}.
122      *
123      * @param treeModel model for the JXTreeTable
124      */

125     public JXTreeTable(TreeTableModel treeModel) {
126         // Implementation note:
127
// Make sure that the SAME instance of treeModel is passed to the
128
// constructor for TreeTableCellRenderer as is passed in the first
129
// argument to the following chained constructor for this JXTreeTable:
130
this(treeModel, new JXTreeTable.TreeTableCellRenderer(treeModel));
131     }
132
133     /**
134      * Constructs a <code>JXTreeTable</code> using the specified
135      * {@link org.jdesktop.swing.treetable.TreeTableModel} and
136      * {@link org.jdesktop.swing.treetable.TreeTableCellRenderer}. The renderer
137      * must have been constructed using the same instance of
138      * {@link org.jdesktop.swing.treetable.TreeTableModel} as passed to this
139      * constructor.
140      *
141      * @param treeModel model for the JXTreeTable
142      * @param renderer cell renderer for the tree portion of this JXTreeTable instance.
143      * @throws IllegalArgumentException if an attempt is made to instantiate
144      * JXTreeTable and TreeTableCellRenderer with different instances of TreeTableModel.
145      */

146     private JXTreeTable(TreeTableModel treeModel, TreeTableCellRenderer renderer) {
147         // To avoid unnecessary object creation, such as the construction of a
148
// DefaultTableModel, it is better to invoke super(TreeTableModelAdapter)
149
// directly, instead of first invoking super() followed by a call to
150
// setTreeTableModel(TreeTableModel).
151

152         // Adapt tree model to table model before invoking super()
153
super(new TreeTableModelAdapter(treeModel, renderer));
154
155         // Enforce referential integrity; bail on fail
156
if (treeModel != renderer.getModel()) { // do not use assert here!
157
throw new IllegalArgumentException JavaDoc("Mismatched TreeTableModel");
158         }
159
160         // renderer-related initialization -- also called from setTreeTableModel()
161
init(renderer); // private method
162
initActions();
163
164         // Install the default editor.
165
setDefaultEditor(AbstractTreeTableModel.hierarchicalColumnClass,
166             new TreeTableCellEditor(this, renderer));
167
168         // No grid.
169
setShowGrid(false); // superclass default is "true"
170

171         // Default intercell spacing
172
setIntercellSpacing(spacing); // for both row margin and column margin
173

174         // JTable supports row margins and intercell spacing, but JTree doesn't.
175
// We must reconcile the differences in the semantics of rowHeight as
176
// understood by JTable and JTree by overriding both setRowHeight() and
177
// setRowMargin();
178
setRowHeight(getRowHeight()); // call overridden setRowHeight()
179
setRowMargin(getRowMargin()); // call overridden setRowMargin()
180

181     }
182
183
184     private void initActions() {
185         // Register the actions that this class can handle.
186
ActionMap JavaDoc map = getActionMap();
187         map.put("expand-all", new Actions("expand-all"));
188         map.put("collapse-all", new Actions("collapse-all"));
189     }
190
191     /**
192      * A small class which dispatches actions.
193      * TODO: Is there a way that we can make this static?
194      */

195     private class Actions extends UIAction {
196         Actions(String JavaDoc name) {
197             super(name);
198         }
199
200         public void actionPerformed(ActionEvent JavaDoc evt) {
201             if ("expand-all".equals(getName())) {
202         expandAll();
203             }
204             else if ("collapse-all".equals(getName())) {
205                 collapseAll();
206             }
207         }
208     }
209
210     /**
211      * Overrides superclass version to be a no-op.
212      */

213     protected void resetSorter() {
214         // no-op
215
}
216
217     /**
218      * Overrides superclass version to be a no-op.
219      */

220     protected void setSorter(int columnIndex) {
221         // no-op
222
}
223
224     /**
225      * <p>Sets whether the table draws horizontal lines between cells. It draws
226      * the lines if <code>show</code> is true; otherwise it doesn't. By default,
227      * a table draws the lines.</p>
228      *
229      * <p>If you want the lines to be drawn, make sure that the row margin or
230      * horizontal intercell spacing is greater than zero.</p>
231      *
232      * @param show true, if horizontal lines should be drawn; false, if lines
233      * should not be drawn
234      * @see javax.swing.JTable#getShowHorizontalLines() getShowHorizontalLines
235      * @see #setRowMargin(int) setRowMargin
236      * @see javax.swing.JTable#setIntercellSpacing(java.awt.Dimension) setIntercellSpacing
237      */

238     public void setShowHorizontalLines(boolean show) {
239         super.setShowHorizontalLines(show);
240     }
241
242     /**
243      * <p>Sets whether the table draws vertical lines between cells. It draws
244      * the lines if <code>show</code> is true; otherwise it doesn't. By default,
245      * a table draws the lines.</p>
246      *
247      * <p>If you want the lines to be drawn, make sure that the column margin or
248      * vertical intercell spacing is greater than zero.</p>
249      *
250      * @param show true, if vertical lines should be drawn; false, if lines
251      * should not be drawn
252      * @see javax.swing.JTable#getShowVerticalLines() getShowVerticalLines
253      * @see #setColumnMargin(int) setColumnMargin
254      * @see javax.swing.JTable#setIntercellSpacing(java.awt.Dimension) setIntercellSpacing
255      */

256     public void setShowVerticalLines(boolean show) {
257         super.setShowVerticalLines(show);
258     }
259
260     /**
261      * Overriden to invoke repaint for the particular location if
262      * the column contains the tree. This is done as the tree editor does
263      * not fill the bounds of the cell, we need the renderer to paint
264      * the tree in the background, and then draw the editor over it.
265      * You should not need to call this method directly.
266      *
267      * {@inheritDoc}
268      */

269     public boolean editCellAt(int row, int column, EventObject JavaDoc e) {
270         expandOrCollapseNode(e); // RG: Fix Issue 49!
271
boolean canEdit = super.editCellAt(row, column, e);
272         if (canEdit && isHierarchical(column)) {
273             repaint(getCellRect(row, column, false));
274         }
275         return canEdit;
276     }
277
278     private void expandOrCollapseNode(EventObject JavaDoc e) {
279         if (e instanceof MouseEvent JavaDoc) {
280             MouseEvent JavaDoc me = (MouseEvent JavaDoc) e;
281             // If the modifiers are not 0 (or the left mouse button),
282
// tree may try and toggle the selection, and table
283
// will then try and toggle, resulting in the
284
// selection remaining the same. To avoid this, we
285
// only dispatch when the modifiers are 0 (or the left mouse
286
// button).
287
if (me.getModifiers() == 0 ||
288                 me.getModifiers() == InputEvent.BUTTON1_MASK) {
289                 final int count = getColumnCount();
290                 for (int i = count - 1; i >= 0; i--) {
291                     if (isHierarchical(i)) {
292                         
293                         int savedHeight = renderer.getRowHeight();
294                         renderer.setRowHeight(getRowHeight());
295                         MouseEvent JavaDoc pressed = new MouseEvent JavaDoc
296                             (renderer,
297                              me.getID(),
298                              me.getWhen(),
299                              me.getModifiers(),
300                              me.getX() - getCellRect(0, i, false).x,
301                              me.getY(),
302                              me.getClickCount(),
303                              me.isPopupTrigger());
304                         renderer.dispatchEvent(pressed);
305                         // For Mac OS X, we need to dispatch a MOUSE_RELEASED as well
306
MouseEvent JavaDoc released = new MouseEvent JavaDoc
307                             (renderer,
308                              java.awt.event.MouseEvent.MOUSE_RELEASED,
309                              pressed.getWhen(),
310                              pressed.getModifiers(),
311                              pressed.getX(),
312                              pressed.getY(),
313                              pressed.getClickCount(),
314                              pressed.isPopupTrigger());
315                         renderer.dispatchEvent(released);
316                         renderer.setRowHeight(savedHeight);
317                         break;
318                     }
319                 }
320             }
321         }
322     }
323
324     /**
325      * Overridden to provide a workaround for BasicTableUI anomaly. Make sure
326      * the UI never tries to resize the editor. The UI currently uses different
327      * techniques to paint the renderers and editors. So, overriding setBounds()
328      * is not the right thing to do for an editor. Returning -1 for the
329      * editing row in this case, ensures the editor is never painted.
330      *
331      * {@inheritDoc}
332      */

333     public int getEditingRow() {
334         return isHierarchical(editingColumn) ? -1 : editingRow;
335     }
336
337     /**
338      * Returns the actual row that is editing as <code>getEditingRow</code>
339      * will always return -1.
340      */

341     private int realEditingRow() {
342         return editingRow;
343     }
344
345     /**
346      * Sets the data model for this JXTreeTable to the specified
347      * {@link org.jdesktop.swing.treetable.TreeTableModel}. The same data model
348      * may be shared by any number of JXTreeTable instances.
349      *
350      * @param treeModel data model for this JXTreeTable
351      */

352     public void setTreeTableModel(TreeTableModel treeModel) {
353         // The original TreeTable implementation didn't support this signature.
354

355 // CHANGED LINE TO CORRECT ISSUE 151 - rlopes
356
//renderer = new TreeTableCellRenderer(treeModel);
357
renderer.setModel(treeModel);
358         // Adapt tree model to table model before invoking setModel()
359
setModel(new TreeTableModelAdapter(treeModel, renderer));
360         // Enforce referential integrity; bail on fail
361
if (treeModel != renderer.getModel()) { // do not use assert here!
362
throw new IllegalArgumentException JavaDoc("Mismatched TreeTableModel");
363         }
364 // COMMENTED LINE TO CORRECT ISSUE 151 - rlopes
365
// Not needed because the renderer doesn't change, and is already initialized
366
// in the constructor
367
// init(renderer); // renderer is a JTree
368

369         // Install the default editor.
370
setDefaultEditor(AbstractTreeTableModel.hierarchicalColumnClass,
371             new TreeTableCellEditor(this, renderer));
372
373         // JTable supports row margins and intercell spacing, but JTree doesn't.
374
// We must reconcile the differences in the semantics of rowHeight as
375
// understood by JTable and JTree by overriding both setRowHeight() and
376
// setRowMargin();
377
setRowHeight(getRowHeight()); // call overridden setRowHeight()
378
setRowMargin(getRowMargin()); // call overridden setRowMargin()
379
}
380
381     /**
382      * Returns the underlying TreeTableModel for this JXTreeTable.
383      *
384      * @return the underlying TreeTableModel for this JXTreeTable
385      */

386     public TreeTableModel getTreeTableModel() {
387         return ((TreeTableModelAdapter) getModel()).getTreeTableModel();
388     }
389
390     /**
391      * <p>Overrides superclass version to make sure that the specified
392      * {@link javax.swing.table.TableModel} is compatible with JXTreeTable before
393      * invoking the inherited version.</p>
394      *
395      * <p>Because JXTreeTable internally adapts an
396      * {@link org.jdesktop.swing.treetable.TreeTableModel} to make it a compatible
397      * TableModel, <b>this method should never be called directly</b>. Use
398      * {@link #setTreeTableModel(org.jdesktop.swing.treetable.TreeTableModel) setTreeTableModel} instead.</p>
399      *
400      * <p>While it is possible to obtain a reference to this adapted
401      * version of the TableModel by calling {@link javax.swing.JTable#getModel()},
402      * any attempt to call setModel() with that adapter will fail because
403      * the adapter might have been bound to a different JXTreeTable instance. If
404      * you want to extract the underlying TreeTableModel, which, by the way,
405      * <em>can</em> be shared, use {@link #getTreeTableModel() getTreeTableModel}
406      * instead</p>.
407      *
408      * @param tableModel must be a TreeTableModelAdapter
409      * @throws IllegalArgumentException if the specified tableModel is not an
410      * instance of TreeTableModelAdapter
411      */

412     public final void setModel(TableModel JavaDoc tableModel) { // note final keyword
413
if (tableModel instanceof TreeTableModelAdapter) {
414             if (((TreeTableModelAdapter) tableModel).getTreeTable() == null) {
415                 // Passing the above test ensures that this method is being
416
// invoked either from JXTreeTable/JTable constructor or from
417
// setTreeTableModel(TreeTableModel)
418
super.setModel(tableModel); // invoke superclass version
419

420                 ((TreeTableModelAdapter) tableModel).bind(this); // permanently bound
421
// Once a TreeTableModelAdapter is bound to any JXTreeTable instance,
422
// invoking JXTreeTable.setModel() with that adapter will throw an
423
// IllegalArgumentException, because we really want to make sure
424
// that a TreeTableModelAdapter is NOT shared by another JXTreeTable.
425
}
426             else {
427                 throw new IllegalArgumentException JavaDoc("model already bound");
428             }
429         }
430         else {
431             throw new IllegalArgumentException JavaDoc("unsupported model type");
432         }
433     }
434
435     /**
436      * Throws UnsupportedOperationException because variable height rows are
437      * not supported.
438      *
439      * @param row ignored
440      * @param rowHeight ignored
441      * @throws UnsupportedOperationException because variable height rows are
442      * not supported
443      */

444     public final void setRowHeight(int row, int rowHeight) {
445         throw new UnsupportedOperationException JavaDoc("variable height rows not supported");
446     }
447
448     /**
449      * Sets the row height for this JXTreeTable. Reconciles semantic differences
450      * between JTable and JTree regarding row height.
451      *
452      * @param rowHeight height of a row
453      */

454     public void setRowHeight(int rowHeight) {
455         super.setRowHeight(rowHeight);
456         adjustTreeRowHeight(); // JTree doesn't have setRowMargin. So adjust.
457
}
458
459     /**
460      * <p>Sets the margin between columns.</p>
461      *
462      * <p>If you set the column margin to zero, make sure that you also set
463      * <code>showVerticalLines</code> to <code>false</code>.</p>
464      *
465      * @param columnMargin margin between columns; must be greater than or equal to zero.
466      * @see #setShowVerticalLines(boolean) setShowVerticalLines
467      */

468     public void setColumnMargin(int columnMargin) {
469         super.setColumnMargin(columnMargin);
470     }
471
472     /**
473      * <p>Overridden to ensure that private renderer state is kept in sync with the
474      * state of the component. Calls the inherited version after performing the
475      * necessary synchronization. If you override this method, make sure you call
476      * this version from your version of this method.</p>
477      *
478      * <p>If you set row margin to zero, make sure that you also set
479      * <code>showHorizontalLines</code> to <code>false</code>.</p>
480      *
481      * @param rowMargin margin or intercell spacing between rows
482      * @see #setShowHorizontalLines(boolean) setShowHorizontalLines
483      */

484     public void setRowMargin(int rowMargin) {
485         // No need to override setIntercellSpacing, because the change in
486
// rowMargin will be funneled through this method anyway.
487
super.setRowMargin(rowMargin);
488         adjustTreeRowHeight(); // JTree doesn't have setRowMargin. So adjust.
489
}
490
491     /**
492      * Reconciles semantic differences between JTable and JTree regarding
493      * row height.
494      */

495     private void adjustTreeRowHeight() {
496         final int treeRowHeight = rowHeight + (rowMargin << 1);
497         if (renderer != null && renderer.getRowHeight() != treeRowHeight) {
498             renderer.setRowHeight(treeRowHeight);
499         }
500     }
501
502     /**
503      * <p>Overridden to ensure that private renderer state is kept in sync with the
504      * state of the component. Calls the inherited version after performing the
505      * necessary synchronization. If you override this method, make sure you call
506      * this version from your version of this method.</p>
507      *
508      * <p>This version maps the selection mode used by the renderer to match the
509      * selection mode specified for the table. Specifically, the modes are mapped
510      * as follows:
511      * <pre>
512      * ListSelectionModel.SINGLE_INTERVAL_SELECTION: TreeSelectionModel.CONTIGUOUS_TREE_SELECTION;
513      * ListSelectionModel.MULTIPLE_INTERVAL_SELECTION: TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION;
514      * any other (default): TreeSelectionModel.SINGLE_TREE_SELECTION;
515      * </pre>
516      *
517      * {@inheritDoc}
518      *
519      * @param mode any of the table selection modes
520      */

521     public void setSelectionMode(int mode) {
522         if (renderer != null) {
523             switch (mode) {
524                 case ListSelectionModel.SINGLE_INTERVAL_SELECTION: {
525                     renderer.getSelectionModel().setSelectionMode(
526                         TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
527                     break;
528                 }
529                 case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION: {
530                     renderer.getSelectionModel().setSelectionMode(
531                         TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
532                     break;
533                 }
534                 default: {
535                     renderer.getSelectionModel().setSelectionMode(
536                         TreeSelectionModel.SINGLE_TREE_SELECTION);
537                     break;
538                 }
539             }
540         }
541         super.setSelectionMode(mode);
542     }
543
544     /**
545      * Overrides superclass version to provide support for cell decorators.
546      *
547      * @param renderer the <code>TableCellRenderer</code> to prepare
548      * @param row the row of the cell to render, where 0 is the first row
549      * @param column the column of the cell to render, where 0 is the first column
550      * @return the <code>Component</code> used as a stamp to render the specified cell
551      */

552     public Component JavaDoc prepareRenderer(TableCellRenderer JavaDoc renderer, int row,
553         int column) {
554         // TOTAL HACK to fix icons that disappeared in a regression after M3!
555
if (isHierarchical(column)) {
556             if (collapsedIcon != null) {
557                 setCollapsedIcon(collapsedIcon);
558             }
559             if (expandedIcon != null) {
560                 setExpandedIcon(expandedIcon);
561             }
562             if (openIcon != null) {
563                 setOpenIcon(openIcon);
564             }
565             if (closedIcon != null) {
566                 setClosedIcon(closedIcon);
567             }
568             if (leafIcon != null) {
569                 setLeafIcon(leafIcon);
570             }
571         }
572         
573         Component JavaDoc component = super.prepareRenderer(renderer, row, column);
574         // MUST ALWAYS ACCESS dataAdapter through accessor method!!!
575
ComponentAdapter adapter = getComponentAdapter();
576         adapter.row = row;
577         adapter.column = column;
578         
579         return applyRenderer(component, //super.prepareRenderer(renderer, row, column),
580
adapter);
581     }
582
583     /**
584      * Performs necessary housekeeping before the renderer is actually applied.
585      *
586      * @param component
587      * @param adapter component data adapter
588      * @throws NullPointerException if the specified component or adapter is null
589      */

590     protected Component JavaDoc applyRenderer(Component JavaDoc component,
591         ComponentAdapter adapter) {
592         if (component == null) {
593             throw new IllegalArgumentException JavaDoc("null component");
594         }
595         if (adapter == null) {
596             throw new IllegalArgumentException JavaDoc("null component data adapter");
597         }
598
599         if (isHierarchical(adapter.column)) {
600             // After all decorators have been applied, make sure that relevant
601
// attributes of the table cell renderer are applied to the
602
// tree cell renderer before the hierarchical column is rendered!
603
TreeCellRenderer JavaDoc tcr = renderer.getCellRenderer();
604
605             if (tcr instanceof DefaultTreeCellRenderer JavaDoc) {
606                 DefaultTreeCellRenderer JavaDoc dtcr = ((DefaultTreeCellRenderer JavaDoc) tcr);
607                 if (adapter.isSelected()) {
608                     dtcr.setTextSelectionColor(component.getForeground());
609                     dtcr.setBackgroundSelectionColor(component.getBackground());
610                } else {
611                     dtcr.setTextNonSelectionColor(component.getForeground());
612                     dtcr.setBackgroundNonSelectionColor(component.getBackground());
613                 }
614             }
615         }
616         return component;
617     }
618
619     /**
620      * Sets the specified TreeCellRenderer as the Tree cell renderer.
621      *
622      * @param cellRenderer to use for rendering tree cells.
623      */

624     public void setCellRenderer(TreeCellRenderer JavaDoc cellRenderer) {
625         if (renderer != null) {
626             renderer.setCellRenderer(cellRenderer);
627         }
628     }
629
630
631     /**
632      * Sets the specified icon as the icon to use for rendering collapsed nodes.
633      *
634      * @param icon to use for rendering collapsed nodes
635      */

636     public void setCollapsedIcon(Icon JavaDoc icon) {
637         try {
638             ( (BasicTreeUI JavaDoc) (renderer.getUI())).setCollapsedIcon(icon);
639             // TOTAL HACK to fix icons that disappeared in a regression after M3!
640
collapsedIcon = icon;
641         }
642         catch (ClassCastException JavaDoc ex) {
643             /** @todo use logging apis instead */
644             System.err.println(ex);
645         }
646     }
647
648     /**
649      * Sets the specified icon as the icon to use for rendering expanded nodes.
650      *
651      * @param icon to use for rendering expanded nodes
652      */

653     public void setExpandedIcon(Icon JavaDoc icon) {
654         try {
655             ( (BasicTreeUI JavaDoc) (renderer.getUI())).setExpandedIcon(icon);
656             // TOTAL HACK to fix icons that disappeared in a regression after M3!
657
expandedIcon = icon;
658         }
659         catch (ClassCastException JavaDoc ex) {
660             /** @todo use logging apis instead */
661             System.err.println(ex);
662         }
663     }
664
665     /**
666      * Sets the specified icon as the icon to use for rendering open container nodes.
667      *
668      * @param icon to use for rendering open nodes
669      */

670     public void setOpenIcon(Icon JavaDoc icon) {
671         try {
672             ((DefaultTreeCellRenderer JavaDoc) renderer.getCellRenderer()).setOpenIcon(icon);
673             // TOTAL HACK to fix icons that disappeared in a regression after M3!
674
openIcon = icon;
675         }
676         catch (ClassCastException JavaDoc ex) {
677             /** @todo use logging apis instead */
678             System.err.println(ex);
679         }
680     }
681
682     /**
683      * Sets the specified icon as the icon to use for rendering closed container nodes.
684      *
685      * @param icon to use for rendering closed nodes
686      */

687     public void setClosedIcon(Icon JavaDoc icon) {
688         try {
689             ((DefaultTreeCellRenderer JavaDoc) renderer.getCellRenderer()).setClosedIcon(icon);
690             // TOTAL HACK to fix icons that disappeared in a regression after M3!
691
closedIcon = icon;
692         }
693         catch (ClassCastException JavaDoc ex) {
694             /** @todo use logging apis instead */
695             System.err.println(ex);
696         }
697     }
698
699     /**
700      * Sets the specified icon as the icon to use for rendering leaf nodes.
701      *
702      * @param icon to use for rendering leaf nodes
703      */

704     public void setLeafIcon(Icon JavaDoc icon) {
705         try {
706             ((DefaultTreeCellRenderer JavaDoc) renderer.getCellRenderer()).setLeafIcon(icon);
707             // TOTAL HACK to fix icons that disappeared in a regression after M3!
708
leafIcon = icon;
709         }
710         catch (ClassCastException JavaDoc ex) {
711             /** @todo use logging apis instead */
712             System.err.println(ex);
713         }
714     }
715
716     /**
717      * Overridden to ensure that private renderer state is kept in sync with the
718      * state of the component. Calls the inherited version after performing the
719      * necessary synchronization. If you override this method, make sure you call
720      * this version from your version of this method.
721      */

722     public void clearSelection() {
723         if (renderer != null) {
724             renderer.clearSelection();
725         }
726         super.clearSelection();
727     }
728
729     /**
730      * Collapses all nodes in the treetable.
731      */

732     public void collapseAll() {
733         renderer.collapseAll();
734     }
735
736     /**
737      * Expands all nodes in the treetable.
738      */

739     public void expandAll() {
740         renderer.expandAll();
741     }
742
743     /**
744      * Collapses the node at the specified path in the treetable.
745      *
746      * @param path path of the node to collapse
747      */

748     public void collapsePath(TreePath JavaDoc path) {
749         renderer.collapsePath(path);
750     }
751
752     /**
753      * Expands the the node at the specified path in the treetable.
754      *
755      * @param path path of the node to expand
756      */

757     public void expandPath(TreePath JavaDoc path) {
758         renderer.expandPath(path);
759     }
760
761     /**
762      * Collapses the row in the treetable. If the specified row index is
763      * not valid, this method will have no effect.
764      */

765     public void collapseRow(int row) {
766         renderer.collapseRow(row);
767     }
768
769     /**
770      * Expands the specified row in the treetable. If the specified row index is
771      * not valid, this method will have no effect.
772      */

773     public void expandRow(int row) {
774         renderer.expandRow(row);
775     }
776
777     /**
778      * Determines whether or not the root node from the TreeModel is visible.
779      *
780      * @param visible true, if the root node is visible; false, otherwise
781      */

782     public void setRootVisible(boolean visible) {
783         renderer.setRootVisible(visible);
784     }
785
786     /**
787      * Returns true if the root node of the tree is displayed.
788      *
789      * @return true if the root node of the tree is displayed
790      */

791     public boolean isRootVisible() {
792         return renderer.isRootVisible();
793     }
794
795     /**
796      * Returns true if the value identified by path is currently viewable, which
797      * means it is either the root or all of its parents are expanded. Otherwise,
798      * this method returns false.
799      *
800      * @return true, if the value identified by path is currently viewable;
801      * false, otherwise
802      */

803     public boolean isVisible(TreePath JavaDoc path) {
804         return renderer.isVisible(path);
805     }
806
807     /**
808      * Returns true if the node identified by path is currently expanded.
809      * Otherwise, this method returns false.
810      *
811      * @param path path
812      * @return true, if the value identified by path is currently expanded;
813      * false, otherwise
814      */

815     public boolean isExpanded(TreePath JavaDoc path) {
816         return renderer.isExpanded(path);
817     }
818
819     /**
820      * Returns true if the node at the specified display row is currently expanded.
821      * Otherwise, this method returns false.
822      *
823      * @param row row
824      * @return true, if the node at the specified display row is currently expanded.
825      * false, otherwise
826      */

827     public boolean isExpanded(int row) {
828         return renderer.isExpanded(row);
829     }
830
831     /**
832      * Returns true if the node identified by path is currently collapsed,
833      * this will return false if any of the values in path are currently not
834      * being displayed.
835      *
836      * @param path path
837      * @return true, if the value identified by path is currently collapsed;
838      * false, otherwise
839      */

840     public boolean isCollapsed(TreePath JavaDoc path) {
841         return renderer.isCollapsed(path);
842     }
843
844     /**
845      * Returns true if the node at the specified display row is collapsed.
846      *
847      * @param row row
848      * @return true, if the node at the specified display row is currently collapsed.
849      * false, otherwise
850      */

851     public boolean isCollapsed(int row) {
852         return renderer.isCollapsed(row);
853     }
854
855     
856     /**
857      * Returns an <code>Enumeration</code> of the descendants of the
858      * path <code>parent</code> that
859      * are currently expanded. If <code>parent</code> is not currently
860      * expanded, this will return <code>null</code>.
861      * If you expand/collapse nodes while
862      * iterating over the returned <code>Enumeration</code>
863      * this may not return all
864      * the expanded paths, or may return paths that are no longer expanded.
865      *
866      * @param parent the path which is to be examined
867      * @return an <code>Enumeration</code> of the descendents of
868      * <code>parent</code>, or <code>null</code> if
869      * <code>parent</code> is not currently expanded
870      */

871     
872     public Enumeration JavaDoc getExpandedDescendants(TreePath JavaDoc parent) {
873         return renderer.getExpandedDescendants(parent);
874    &n