KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > swingwtx > swing > JTree


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: JTree.java,v $
11    Revision 1.34 2004/05/06 00:12:01 laurentmartelli
12    Added addSelectionPaths(TreePath[]) stub
13
14    Revision 1.33 2004/05/05 16:46:54 bobintetley
15    JTree rendering fix for collapse/expansion
16
17    Revision 1.32 2004/05/05 13:53:38 bobintetley
18    (Laurent Martelli) - CellRenderers warn if they do not return JLabel
19
20    Revision 1.31 2004/05/05 12:43:21 bobintetley
21    Patches/new files from Laurent Martell
22
23    Revision 1.30 2004/04/30 16:52:17 bobintetley
24    MenuListener support, JViewport support, TreeSelectionModel stubs, additional JTree methods
25
26    Revision 1.29 2004/04/29 12:49:28 bobintetley
27    Additional JOptionePane constants, missing JTree methods and improved awt.Image support
28
29    Revision 1.28 2004/04/28 08:38:12 bobintetley
30    Hierarchy fixes, code cleanup for base classes, additional javadocs and use of flag to identify JComponent descendants with peers
31
32    Revision 1.27 2004/04/19 10:49:37 bobintetley
33    Fix to cell editing with DefaultEditor/JComboBox and fix so JTable/JTree
34    cell renderers are used after editor updates
35
36    Revision 1.26 2004/04/16 14:38:47 bobintetley
37    Table and Tree cell editor support
38
39    Revision 1.25 2004/03/30 10:42:46 bobintetley
40    Many minor bug fixes, event improvements by Dan Naab. Full swing.Icon support
41
42    Revision 1.24 2004/03/26 12:04:42 bobintetley
43    Fixed bug in TreeModel that caused events not to fire down to JTree
44
45    Revision 1.23 2004/02/23 10:07:10 bobintetley
46    Cell render font support
47
48    Revision 1.22 2004/02/23 09:58:18 bobintetley
49    JTree/JTable now support fonts from cell renderer
50
51    Revision 1.21 2004/02/12 10:14:58 bobintetley
52    collapse/expandPath() support
53
54    Revision 1.20 2004/01/27 09:05:12 bobintetley
55    ListModel and List Selection implemented. ScrollPane fix so all components
56       scrollable
57
58    Revision 1.19 2004/01/26 15:49:48 bobintetley
59    Whoops typo
60
61    Revision 1.18 2004/01/26 14:05:23 bobintetley
62    Compatibility methods
63
64    Revision 1.17 2004/01/15 18:13:10 bobintetley
65    TreeWillExpand support
66
67    Revision 1.16 2004/01/10 11:46:27 bobintetley
68    JTree/TreePath fixes by Sachin (broken path, rootVisible support) and Rob
69      (Missing root node from path, couldn't represent TreePath as string)
70  
71    Revision 1.15 2003/12/16 17:46:17 bobintetley
72    Additional thread safety methods
73  
74    Revision 1.14 2003/12/16 13:14:33 bobintetley
75    Use of SwingWTUtils.isSWTControlAvailable instead of null test
76  
77    Revision 1.13 2003/12/15 18:29:57 bobintetley
78    Changed setParent() method to setSwingWTParent() to avoid conflicts with applications
79  
80    Revision 1.12 2003/12/14 09:13:38 bobintetley
81    Added CVS log to source headers
82  
83  */

84
85 package swingwtx.swing;
86
87 import org.eclipse.swt.widgets.*;
88 import org.eclipse.swt.events.*;
89 import org.eclipse.swt.*;
90
91 import swingwtx.swing.event.*;
92 import swingwtx.swing.tree.*;
93
94 import java.util.*;
95
96 public class JTree extends swingwtx.swing.JComponent implements TreeModelListener, CellEditorListener {
97     
98     protected Tree ppeer = null;
99     protected TreeModel model = null;
100     protected TreeNode root = null;
101     protected TreeCellRenderer cellRenderer = new DefaultTreeCellRenderer();
102     protected TreeCellEditor cellEditor = new DefaultCellEditor(new JTextField());
103     protected boolean isEditable = false;
104     protected boolean isRootVisible = true;
105     protected TreePath anchorSelectionPath = null;
106     /** SWT Editor */
107     protected org.eclipse.swt.custom.TreeEditor swtEditor = null;
108     protected org.eclipse.swt.widgets.TreeItem editingTreeItem = null;
109     protected DefaultMutableTreeNode editingNode = null;
110     protected swingwt.awt.Component editingComponent = null;
111     
112     /** Thread safe return value */
113     private Object JavaDoc retval = null;
114     
115     protected Vector treeWillExpansionListeners = new Vector();
116     protected Vector treeExpansionListeners = new Vector();
117     protected Vector treeSelectionListeners = new Vector();
118     
119     public JTree() { cellEditor.addCellEditorListener(this); }
120     public JTree(TreeNode root) { this.root = root; cellEditor.addCellEditorListener(this); }
121     public JTree(TreeModel model) { this.model = model; root = (TreeNode) model.getRoot(); cellEditor.addCellEditorListener(this); }
122     
123     public void addTreeExpansionListener(TreeExpansionListener l) {
124         treeExpansionListeners.add(l);
125     }
126     public void removeTreeExpansionListener(TreeExpansionListener l) {
127         treeExpansionListeners.remove(l);
128     }
129     public void addWillTreeExpansionListener(TreeWillExpandListener l) {
130         treeWillExpansionListeners.add(l);
131     }
132     public void removeTreeWillExpansionListener(TreeWillExpandListener l) {
133         treeWillExpansionListeners.remove(l);
134     }
135     public void addTreeSelectionListener(TreeSelectionListener l) {
136         treeSelectionListeners.add(l);
137     }
138     public void removeTreeSelectionListener(TreeSelectionListener l) {
139         treeSelectionListeners.remove(l);
140     }
141     
142     public void setModel(TreeModel model){
143         this.model = model;
144         root = (TreeNode) model.getRoot();
145         model.addTreeModelListener(this);
146         drawTree();
147     }
148     
149     public TreeModel getModel(){
150         return model;
151     }
152     
153     public boolean isEditable() { return isEditable; }
154     public void setEditable(boolean b) { isEditable = b; }
155     public void setCellEditor(TreeCellEditor cell) { cellEditor = cell; }
156     public TreeCellEditor getCellEditor() { return cellEditor; }
157     
158     /**
159      * Once a parent component receives an "add" call for a child, this being
160      * the child, this should be called to tell us to instantiate the peer
161      * and load in any cached properties.
162      */

163     public void setSwingWTParent(swingwt.awt.Container parent) throws Exception JavaDoc {
164         descendantHasPeer = true;
165         ppeer = new Tree(parent.getComposite(), SWT.BORDER );
166         
167         // Editor
168
swtEditor = new org.eclipse.swt.custom.TreeEditor(ppeer);
169         
170         // Cached properties
171
peer = ppeer;
172         this.parent = parent;
173         
174         drawTree();
175         
176         registerTreeEvents();
177         
178     }
179     
180     /**
181      * Registers some tree specific events
182      * and maps them to Swing events.
183      */

184     protected void registerTreeEvents() {
185         
186         ppeer.addSelectionListener(new SelectionListener() {
187             public void widgetSelected(SelectionEvent e) {
188                 processTreeSelection(e);
189                 processTreeEdit((TreeNode) e.item.getData(), (org.eclipse.swt.widgets.TreeItem) e.item);
190             }
191             public void widgetDefaultSelected(SelectionEvent e) {
192             }
193         });
194         
195         ppeer.addTreeListener(new TreeListener() {
196             public void treeCollapsed(TreeEvent e) {
197                 processTreeExpansion(e, true);
198             }
199             public void treeExpanded(TreeEvent e) {
200                 processTreeExpansion(e, false);
201             }
202         });
203         
204     }
205     
206     /**
207      * Called back when the user selects a node to allow them to
208      * edit the value (if the tree is editable)
209      */

210     protected void processTreeEdit(TreeNode node, org.eclipse.swt.widgets.TreeItem item) {
211         
212         // If cell selection isn't enabled, don't bother - we can't edit
213
if (!isEditable) return;
214         
215         // We can't edit things that aren't descended from DefaultMutableTreeNode
216
if (!(node instanceof DefaultMutableTreeNode)) return;
217         
218         DefaultMutableTreeNode dmt = (DefaultMutableTreeNode) node;
219         editingTreeItem = item;
220         editingNode = dmt;
221         
222         // Get the editing component for the tree
223
editingComponent = cellEditor.getTreeCellEditorComponent(this, dmt.getUserObject(), true, true, dmt.isLeaf(), 1);
224
225         // Clean up any previous editor
226
if (swtEditor != null) {
227             if (swtEditor.getEditor() != null)
228                 swtEditor.getEditor().dispose();
229             swtEditor.dispose();
230             swtEditor = null;
231         }
232
233         // The control that will be the editor must be a child of the Tree.
234
// I use a private class here that basically pretends to be a
235
// container, but allows containment of an SWT Table (which isn't
236
// really a container, but needs to be for the editor)
237
try {
238             editingComponent.setSwingWTParent(new TreeEditorContainer(this));
239             editingComponent.registerEvents();
240         }
241         catch (Exception JavaDoc e) {
242             e.printStackTrace();
243         }
244         
245         // Open the editor in the right place
246
swtEditor = new org.eclipse.swt.custom.TreeEditor(ppeer);
247         swtEditor.horizontalAlignment = SWT.LEFT;
248         swtEditor.grabHorizontal = true;
249         swtEditor.minimumWidth = 50;
250         swtEditor.setEditor(editingComponent.getPeer(), item);
251         
252         // Make sure the value is correct
253
if (cellEditor instanceof DefaultCellEditor) {
254             ((DefaultCellEditor) cellEditor).getHandler().setValue(dmt.getUserObject());
255         }
256
257         // Assign focus to the editor
258
editingComponent.grabFocus();
259     }
260     
261     /** Callback when the editor is stopped - need to
262      * put any changes back into the model.
263      */

264     public void editingStopped(ChangeEvent e) {
265         // Get new value
266
Object JavaDoc value = cellEditor.getCellEditorValue();
267         
268         // Update model values
269
editingNode.setUserObject(value);
270         
271         // Update on-screen value using cell renderer
272
if (editingNode instanceof DefaultMutableTreeNode) {
273             
274             DefaultMutableTreeNode dmt = (DefaultMutableTreeNode) editingNode;
275             
276             // Get the peer from the node
277
org.eclipse.swt.widgets.TreeItem item = dmt.peer;
278             
279             // Get the renderer for this thing
280
JLabel cr = (JLabel) cellRenderer.getTreeCellRendererComponent(this,
281                 dmt,
282                 false, dmt.isLeaf(),
283                 dmt.isLeaf(), 0,
284                 true);
285             
286             // Textual value
287
item.setText(cr.getText());
288             
289             // Icon
290
if (cr.getIcon() != null)
291                 item.setImage(SwingWTUtils.getSWTImageFromSwingIcon(this, cr.getIcon()));
292             
293             // Colours
294
if (cr.getBackground() != null)
295                 if (cr.getBackground().getSWTColor() != null)
296                     item.setBackground(cr.getBackground().getSWTColor());
297             if (cr.getForeground() != null)
298                 if (cr.getForeground().getSWTColor() != null)
299                     item.setForeground(cr.getForeground().getSWTColor());
300             
301             // Font
302
if (cr.hasSetFont())
303                 item.setFont(cr.getFont().getSWTFont());
304         }
305         else
306             System.out.println("FIXME: Node does not descend from DefaultMutableTreeNode");
307     }
308     
309     public void fireTreeExpanded(TreePath path) {
310         TreeExpansionEvent event = new TreeExpansionEvent(this, path);
311         Iterator i = treeExpansionListeners.iterator();
312         while(i.hasNext()) {
313             ((TreeExpansionListener)i.next()).treeExpanded(event);
314         }
315     }
316     
317     public TreePath getAnchorSelectionPath() {
318         return anchorSelectionPath;
319     }
320     public void setAnchorSelectionPath(TreePath path) {
321         this.anchorSelectionPath = path;
322     }
323     
324     protected void processTreeSelection(SelectionEvent e) {
325         if (treeSelectionListeners.size() == 0) return;
326         Iterator i = treeSelectionListeners.iterator();
327         //TreeSelectionEvent ev = new TreeSelectionEvent(e.data, getTreePath((TreeNode) e.item.getData()), false, getTreePath((TreeNode) e.item.getData()), getTreePath((TreeNode) e.item.getData()));
328
// Check this - are we sure it's the JTree and not the selected item as the event source?
329
TreeSelectionEvent ev = new TreeSelectionEvent(this, getTreePath((TreeNode) e.item.getData()), false, getTreePath((TreeNode) e.item.getData()), getTreePath((TreeNode) e.item.getData()));
330         while (i.hasNext()) {
331             TreeSelectionListener l = (TreeSelectionListener) i.next();
332             l.valueChanged(ev);
333         }
334     }
335     
336     protected void processTreeExpansion(TreeEvent e, boolean collapse) {
337         try {
338             fireTreeWillExpandOrCollapse(e,collapse);
339         }
340         catch (ExpandVetoException ex) {
341             e.doit = false;
342             return;
343         }
344  
345     // Re-render the expanded/collapsed node since it's changed
346
renderNode((org.eclipse.swt.widgets.TreeItem) e.item);
347        
348         if (treeExpansionListeners.size() == 0) return;
349         Iterator i = treeExpansionListeners.iterator();
350         TreeExpansionEvent ev = new TreeExpansionEvent(e.item.getData(), getTreePath((TreeNode) e.item.getData()));
351         while (i.hasNext()) {
352             TreeExpansionListener l = (TreeExpansionListener) i.next();
353             if (collapse)
354                 l.treeCollapsed(ev);
355             else
356                 l.treeExpanded(ev);
357         }
358     }
359     
360     /**
361      * Notifies all listeners that have registered interest for
362      * notification on this event type. The event instance
363      * is created using <code>path</code> parameter.
364      *
365      * @param e the TreeExpansionEvent instance
366      * @param collapse boolean indication for collapse state of the tree
367      */

368     public void fireTreeWillExpandOrCollapse(TreeEvent e, boolean collapse) throws ExpandVetoException {
369         if (treeWillExpansionListeners.size() != 0) {
370             Iterator itrWillExpand = treeWillExpansionListeners.iterator();
371             TreeExpansionEvent ev = new TreeExpansionEvent(e.item.getData(), getTreePath((TreeNode) e.item.getData()));
372             while (itrWillExpand.hasNext()) {
373                 TreeWillExpandListener l = (TreeWillExpandListener) itrWillExpand.next();
374                 if (collapse) {
375                     l.treeWillCollapse(ev);
376                 }
377                 else {
378                     l.treeWillExpand(ev);
379                 }
380             }
381         }
382     }
383
384     
385     /** Returns a TreePath from a given node - not a real Swing
386      * method, but useful for us here for generating events */

387     public TreePath getTreePath(TreeNode node) {
388         Vector path = new Vector();
389         path.add(node);
390         while (node.getParent() != null) {
391             node = node.getParent();
392             path.add(node);
393         }
394         Object JavaDoc[] retPath = path.toArray();
395         path.removeAllElements();
396         path = null;
397         return new TreePath(retPath);
398     }
399
400     public void addSelectionPaths(TreePath[] path) {/* TODO */}
401
402     public TreePath getSelectionPath() {
403         
404         if (!SwingWTUtils.isSWTControlAvailable(ppeer)) return null;
405         
406         SwingUtilities.invokeSync( new Runnable JavaDoc() {
407             public void run() {
408                 TreeItem[] selpath = ppeer.getSelection();
409                 if (selpath.length == 0) { retval = null; return; }
410
411                 Object JavaDoc[] nodes = new Object JavaDoc[selpath.length];
412                 for (int i = 0; i < selpath.length; i++) {
413                     nodes[i] = selpath[i].getData();
414                 }
415                 retval = new TreePath(nodes);
416             }
417         });
418         
419         return (TreePath) retval;
420     }
421     
422     public TreePath[] getSelectionPaths() {
423         return new TreePath[] { getSelectionPath() };
424     }
425     
426     public void addSelectionPath(TreePath t) {
427         setSelectionPath(t);
428     }
429     
430     public void removeSelectionPath(TreePath t) {
431         SwingUtilities.invokeSync(new Runnable JavaDoc() {
432             public void run() {
433                 if (SwingWTUtils.isSWTControlAvailable(ppeer))
434                     ppeer.deselectAll();
435             }
436         });
437     }
438     
439     public void removeSelectionPaths(TreePath t[]) {
440         removeSelectionPath(null);
441     }
442     
443     /** NOT IMPLEMENTED */
444     public void setScrollsOnExpand(boolean b) {
445     }
446     
447     /** NOT IMPLEMENTED */
448     public void setShowsRootHandles(boolean b) {
449     }
450     
451     /** NOT IMPLEMENTED */
452     public void setSelectionModel(TreeSelectionModel model) {
453     }
454     
455     /** NOT IMPLEMENTED - RETURNS DUMMY STUB */
456     public TreeSelectionModel getSelectionModel() {
457         return new DefaultTreeSelectionModel();
458     }
459     
460     /** Scrolls the Tree to show the selected path */
461     public void scrollPathToVisible(final TreePath t) {
462         SwingUtilities.invokeSync(new Runnable JavaDoc() {
463             public void run() {
464                 if (SwingWTUtils.isSWTControlAvailable(ppeer)) {
465                     DefaultMutableTreeNode dmt = (DefaultMutableTreeNode) t.getLastPathComponent();
466                     ppeer.showItem(dmt.peer);
467                 }
468             }
469         });
470     }
471     
472     public void setSelectionPaths(TreePath[] t) {
473         setSelectionPath(t[0]);
474     }
475
476     public void setSelectionPath(TreePath t) {
477         
478         if (t == null) return;
479         if (t.getPathCount() == 0) return;
480         
481         final Object JavaDoc[] nodes = t.getPath();
482         
483         SwingUtilities.invokeSync( new Runnable JavaDoc() {
484             public void run() {
485                 TreeItem[] ti = new TreeItem[nodes.length];
486                 for (int i = 0; i < nodes.length; i++) {
487                     ti[i] = ((DefaultMutableTreeNode) nodes[i]).peer;
488                 }
489                 ppeer.setSelection(ti);
490             }
491         });
492         
493     }
494     
495     public TreePath getPathForLocation(int x, int y) {
496         return getClosestPathForLocation(x, y);
497     }
498     
499     public TreePath getClosestPathForLocation(final int x, final int y) {
500         final TreePath[] path = new TreePath[1];
501         SwingUtilities.invokeSync(new Runnable JavaDoc() {
502             public void run() {
503                 if (SwingWTUtils.isSWTControlAvailable(ppeer)) {
504                     TreeItem item = ppeer.getItem(new org.eclipse.swt.graphics.Point(x, y));
505                     if (item!=null)
506                         path[0] = new TreePath((TreeNode) item.getData());
507                     else
508                         path[0] = null;
509                 }
510                 else
511                     path[0] = null;
512             }
513         });
514         return path[0];
515     }
516     
517     /**
518      * Because SWT Trees don't have a row concept (apart from
519      * a row count), we have to make a guess. Now, because
520      * our JTree.drawTree() works down the model from it's
521      * root, we guess that drawn item x = row x - which should
522      * work for the most part (apart from it being horribly
523      * wrong with collapsed items).
524      */

525     public TreePath getPathForRow(final int row) {
526         final TreePath[] path = new TreePath[1];
527         SwingUtilities.invokeSync(new Runnable JavaDoc() {
528             public void run() {
529                 if (SwingWTUtils.isSWTControlAvailable(ppeer)) {
530                     TreeItem item = ppeer.getItems()[row];
531                     TreeNode node = (TreeNode) item.getData();
532                     path[0] = new TreePath(node);
533                 }
534                 else
535                     path[0] = null;
536             }
537         });
538         return path[0];
539     }
540     
541     public int getRowCount() {
542         final int[] rowCount = new int[1];
543         SwingUtilities.invokeSync(new Runnable JavaDoc() {
544             public void run() {
545                 if (SwingWTUtils.isSWTControlAvailable(ppeer))
546                     rowCount[0] = ppeer.getItemHeight();
547                 else
548                     rowCount[0] = 0;
549             }
550         });
551         return rowCount[0];
552     }
553     
554     /**
555      * @see getPathForRow for faults with row based stuff - use
556      * path methods if possible.
557      */

558     public void expandRow(int row) {
559         expandPath(getPathForRow(row));
560     }
561     
562     /**
563      * @see getPathForRow for faults with row based stuff - use
564      * path methods if possible.
565      */

566     public void collapseRow(int row) {
567         collapsePath(getPathForRow(row));
568     }
569     
570     public void expandPath(TreePath parent) {
571         if (parent == null)
572             return;
573         Object JavaDoc element = parent.getLastPathComponent();
574         if (parent.getParentPath()!=null && parent.getLastPathComponent()!=null){
575             expandPath(parent.getParentPath());
576         }
577         if (element == null)
578             return;
579         
580         fireTreeExpanded(parent);
581         
582         if (element instanceof DefaultMutableTreeNode) {
583             DefaultMutableTreeNode node = (DefaultMutableTreeNode) element;
584             TreeItem peeritem = node.peer;
585             if (peeritem != null)
586                if (!peeritem.isDisposed()) {
587                    if (node.isLeaf()) {
588                        if (!peeritem.getExpanded()) {
589                            peeritem.setExpanded(true);
590                renderNode(peeritem);
591                }
592                    }
593                }
594         }
595        
596     }
597
598     public void collapsePath(TreePath parent) {
599         if (parent == null)
600             return;
601         Object JavaDoc element = parent.getLastPathComponent();
602         if (parent.getParentPath()!=null && parent.getLastPathComponent()!=null){
603             collapsePath(parent.getParentPath());
604         }
605         if (element == null)
606             return;
607         
608         if (element instanceof DefaultMutableTreeNode) {
609             DefaultMutableTreeNode node = (DefaultMutableTreeNode) element;
610             TreeItem peeritem = node.peer;
611             if (peeritem != null)
612                if (!peeritem.isDisposed()) {
613                    if (node.getChildCount() != 0) {
614                        if (peeritem.getExpanded()) {
615                            peeritem.setExpanded(false);
616                renderNode(peeritem);
617                }
618                    }
619                }
620         }
621     }
622     
623     /**
624      * Draws the tree from the model data
625      */

626     public void drawTree() {
627         
628         // Don't bother drawing if no peer has been created
629
if (!SwingWTUtils.isSWTControlAvailable(ppeer)) return;
630         
631         SwingUtilities.invokeSync(new Runnable JavaDoc() {
632             public void run() {
633                 
634                 // Clear the tree
635
ppeer.removeAll();
636                 
637                 // ROOT BASED RENDER:
638
// =====================================
639
if (root != null) {
640                     if(isRootVisible){
641                         addNodes(ppeer, null, root);
642                     }
643                     else {
644                         if (root.getChildCount() > 0) {
645                             for (Enumeration e = root.children(); e.hasMoreElements();) {
646                                 addNodes(ppeer, null, (TreeNode)e.nextElement());
647                             }
648                         }
649                     }
650                 }
651             }
652         });
653     }
654     
655     public Object JavaDoc getLastSelectedPathComponent() {
656         TreePath t = getSelectionPath();
657         return t != null ? t.getLastPathComponent() : null;
658     }
659
660     /**
661      * Responsible for adding a branch of the tree. Will
662      * recursively call itself until the tree is complete.
663      */

664     private void addNodes(Tree tree, TreeItem treeItem, TreeNode swingNode) {
665         
666         // This node
667
TreeItem item = null;
668         if (tree != null) {
669             item = new TreeItem(tree, SWT.BORDER);
670             // Swing auto expands root nodes
671
item.setExpanded(true);
672         }
673         else
674             item = new TreeItem(treeItem, SWT.BORDER);
675         
676         // Get user object - little unsure here if people aren't using
677
// DefaultMutableTreeNode as the stock TreeNode interface doesn't
678
// seem to support retreival of a data object from the node.
679
// Need to do some research here and see how Swing handles it.
680
if (swingNode instanceof DefaultMutableTreeNode)
681             // Set peer so user apps can tweak items directly if they want
682
((DefaultMutableTreeNode)swingNode).peer = item;
683         else
684             item.setText("FIXME: Node does not descend from DefaultMutableTreeNode");
685             
686         // Get the renderer for this thing
687
swingwt.awt.Component renderer =
688             cellRenderer.getTreeCellRendererComponent(
689                 this,
690                 swingNode,
691                 false, // selected
692
!(tree == null), // expanded (true for root nodes here)
693
swingNode.isLeaf(), // leaf
694
0, // row
695
true); // hasFocus
696

697     // Draw it
698
renderNode(item, renderer);
699     
700         // Store the node in the peer (could be nasty cyclic
701
// reference for GC).
702
item.setData(swingNode);
703         
704         // Any children
705
if (swingNode.getChildCount() > 0) {
706             for (Enumeration e = swingNode.children() ; e.hasMoreElements() ;) {
707                 addNodes(null, item, (TreeNode) e.nextElement());
708             }
709         }
710     }
711
712
713     /** Overloaded renderNode - grabs the cell renderer and
714      * swingNode from the TreeItem and calls the other renderNode -
715      * this is useful once the node has already been created and
716      * we need to redraw it. Used by collapse/expand stuff to
717      * update icons correctly.
718      */

719     private void renderNode(org.eclipse.swt.widgets.TreeItem item) {
720
721     TreeNode swingNode = (TreeNode) item.getData();
722         
723     // Get user object - little unsure here if people aren't using
724
// DefaultMutableTreeNode as the stock TreeNode interface doesn't
725
// seem to support retreival of a data object from the node.
726
// Need to do some research here and see how Swing handles it.
727
if (swingNode instanceof DefaultMutableTreeNode)
728             // Set peer so user apps can tweak items directly if they want
729
((DefaultMutableTreeNode)swingNode).peer = item;
730         else
731             item.setText("FIXME: Node does not descend from DefaultMutableTreeNode");
732             
733         // Get the renderer for this thing
734
swingwt.awt.Component renderer =
735             cellRenderer.getTreeCellRendererComponent(
736                 this,
737                 swingNode,
738                 false, // selected
739
!item.getExpanded(),// expanded
740
swingNode.isLeaf(), // leaf
741
0, // row
742
true); // hasFocus
743

744     renderNode(item, renderer);
745
746     }
747     
748     /** Helper routine - given an SWT TreeItem for a node and
749      * and a component cell renderer, this routine will
750      * appropriately draw the SWT TreeItem. This is used by
751      * drawTree().
752      */

753     private void renderNode(org.eclipse.swt.widgets.TreeItem item, swingwt.awt.Component renderer) {
754
755         // If the renderer is a JLabel, get the
756
// text and image from it.
757
if (renderer instanceof JLabel) {
758             
759             JLabel cr = (JLabel) renderer;
760
761             // Textual value
762
item.setText(cr.getText());
763
764             // Icon
765
if (cr.getIcon() != null)
766                 item.setImage(SwingWTUtils.getSWTImageFromSwingIcon(this, cr.getIcon()));
767
768             // Colours
769
if (cr.getBackground() != null)
770                 if (cr.getBackground().getSWTColor() != null)
771                     item.setBackground(cr.getBackground().getSWTColor());
772             if (cr.getForeground() != null)
773                 if (cr.getForeground().getSWTColor() != null)
774                     item.setForeground(cr.getForeground().getSWTColor());
775
776             // Font
777
if (cr.hasSetFont())
778                 item.setFont(cr.getFont().getSWTFont());
779             
780         }
781         else
782         {
783             item.setText("CellRenderer not JLabel: " + renderer.getClass().getName());
784         }
785     }
786
787     public void setCellRenderer(TreeCellRenderer renderer) { cellRenderer = renderer; }
788     public TreeCellRenderer getCellRenderer() { return cellRenderer; }
789     
790     
791     public void treeNodesChanged(TreeModelEvent e) { drawTree(); }
792     public void treeNodesInserted(TreeModelEvent e) { drawTree(); }
793     public void treeNodesRemoved(TreeModelEvent e) { drawTree(); }
794     public void treeStructureChanged(TreeModelEvent e) { drawTree(); }
795     
796     /**
797      * Determines whether or not the root node from the TreeModel is visible.
798      * @param rootVisible true if the root node of the tree is to be displayed
799      */

800     public void setRootVisible(boolean rootVisible){
801         isRootVisible = rootVisible;
802     }
803     
804     /**
805      * Returns true if the root node of the tree is displayed
806      * @return true if the root node of the tree is displayed
807      */

808     public boolean isRootVisible(){
809         return isRootVisible;
810     }
811     
812     public void editingCanceled(ChangeEvent e) {
813     }
814     
815     /**
816      * A class containing an SWT tree that pretends to be a container
817      * - this is for cell editing purposes.
818      */

819     private class TreeEditorContainer extends swingwt.awt.Container {
820         public TreeEditorContainer(JTree parent) {
821             this.peer = parent.getPeer();
822             this.composite = (org.eclipse.swt.widgets.Composite) parent.getPeer();
823         }
824     }
825     
826     
827 }
828
Popular Tags