Annotation of java/classes/org/w3c/tools/widgets/TreeBrowser.java, revision 1.15
1.1 abaird 1: // TreeBrowser.java
1.15 ! ylafon 2: // $Id: TreeBrowser.java,v 1.14 2000/08/16 21:37:57 ylafon Exp $ */
1.7 ylafon 3: // Authors: Jean-Michel.Leon@sophia.inria.fr,
4: // Yves.Lafon@w3.org :
5: // - Lines, insert/remove, awt 1.1 version
6: // Thierry.Kormann@sophia.inria.fr
7: // - Insert debug, horizontal scrollbar, javadoc,
8: // selection graphic customization, scrollbar policy,
9: // lightweight version.
1.1 abaird 10:
1.7 ylafon 11: package org.w3c.tools.widgets ;
1.1 abaird 12:
1.14 ylafon 13: import java.awt.Canvas;
14: import java.awt.Color;
15: import java.awt.Component;
16: import java.awt.Dimension;
17: import java.awt.FontMetrics;
18: import java.awt.Graphics;
19: import java.awt.Image;
20: import java.awt.Rectangle;
21: import java.awt.Scrollbar;
22:
23: import java.awt.event.AdjustmentEvent;
24: import java.awt.event.AdjustmentListener;
25: import java.awt.event.MouseAdapter;
26: import java.awt.event.MouseEvent;
27:
28: import java.util.Enumeration;
29: import java.util.EventObject;
30: import java.util.Stack;
31: import java.util.Vector;
1.1 abaird 32:
33: /**
34: * The TreeBrowser class.
35: *
36: * This class is a generic framework to browser any hierachical structure.
37: *
1.7 ylafon 38: * <p>Genericity is obtained through the use of 'handlers': the TreeBrowser
39: * itself does not perform any action in response to user events, but simply
40: * forward them as <b>notifications</b> to <b>handlers</b>. Each item inserted
41: * may have its own handler, but handlers may also (this is the most common
42: * case) be shared between handlers.
1.1 abaird 43: *
1.7 ylafon 44: * <p>Any item added in the Tree is displayed with an icon and a label. When a
1.1 abaird 45: * handler receive a notification on a node, it may change this node, to modify
46: * or update its appearance.
47: *
48: * @author Jean-Michel.Leon@sophia.inria.fr
1.11 ylafon 49: * @author Yves.Lafon@w3.org
1.7 ylafon 50: * @author Thierry.Kormann@sophia.inria.fr
51: */
1.1 abaird 52: public class TreeBrowser extends Canvas implements AdjustmentListener {
1.3 ylafon 53:
1.7 ylafon 54: /**
55: * Specifies that the horizontal/vertical scrollbars should always be shown
56: * regardless of the respective sizes of the TreeBrowser.
57: */
58: public static final int SCROLLBARS_ALWAYS = 0;
59: /**
60: * Specifies that horizontal/vertical scrollbars should be shown only when
61: * the size of the nodes exceeds the size of the TreeBrowser in the
62: * horizontal/vertical dimension.
63: */
64: public static final int SCROLLBARS_ASNEEDED = 1;
65: /**
66: * This policy that lets just one node selected at the same time.
67: */
1.9 ylafon 68: public static final int SINGLE = 0;
1.7 ylafon 69: /**
70: * The policy that enables a multiple selection of nodes.
71: */
72: public static final int MULTIPLE = 1;
1.14 ylafon 73:
1.1 abaird 74: static final int HMARGIN = 5;
75: static final int VMARGIN = 5;
76: static final int HGAP = 10;
77: static final int DXLEVEL = HGAP*2;
1.14 ylafon 78:
1.3 ylafon 79: /**
80: * The inner mouse listener in charge of all the node expansion
81: * selection and execution
82: */
83: private class BrowserMouseListener extends MouseAdapter {
1.7 ylafon 84:
1.3 ylafon 85: private void clickAt(TreeNode node, MouseEvent me) {
86: if(node == null)
87: return;
88: int x = me.getX() - HMARGIN;
89: if(node.handler == null)
90: return;
91: // node.handler.notifyExpand(this, node);
92: if((x >= node.level*DXLEVEL) &&
93: (x <= node.level*DXLEVEL + DXLEVEL)) {
94: // click on expand/collapse button
95: if(node.children != TreeNode.NOCHILD) {
1.4 ylafon 96: node.handler.notifyCollapse(TreeBrowser.this, node);
1.3 ylafon 97: }
98: else {
1.4 ylafon 99: node.handler.notifyExpand(TreeBrowser.this, node);
1.3 ylafon 100: }
101: }
102: else if(x > node.level*DXLEVEL + HGAP) {
103: // item selection
1.4 ylafon 104: node.handler.notifySelect(TreeBrowser.this, node);
1.3 ylafon 105: }
106: }
1.7 ylafon 107:
1.3 ylafon 108: /**
109: * Handles events and send notifications ot handlers.
110: * is sent, depending on the node's current state.<br>
111: * on MOUSE_DOWN on a label, a <b>Select</b> notificaiton is sent.<br>
112: * on DOUBLE_CLICK on a label, an <b>Execute</b> notification is sent.
113: */
114: public void mousePressed(MouseEvent me) {
115: int y = me.getY() - VMARGIN;
116: if(me.getClickCount() == 1) {
1.4 ylafon 117: clickAt(itemAt(y), me);
1.3 ylafon 118: }
119: }
1.7 ylafon 120:
1.3 ylafon 121: public void mouseClicked(MouseEvent me) {
1.9 ylafon 122: if(me.getClickCount() > 1) {
1.3 ylafon 123: int y = me.getY() - VMARGIN;
1.4 ylafon 124: TreeNode node = itemAt(y);
1.3 ylafon 125: if((node != null) && (node.handler != null)) {
1.4 ylafon 126: node.handler.notifyExecute(TreeBrowser.this, node);
1.3 ylafon 127: }
128: }
129: }
130: }
1.14 ylafon 131:
1.1 abaird 132: private Scrollbar vscroll;
133: private Scrollbar hscroll;
1.7 ylafon 134: private int maxwidth = 0;
135: private int startx = 0;
136: private Color selectColor = new Color(0, 0, 128);
137: private Color selectFontColor = Color.white;
1.13 bmahe 138: private int scrollbarDisplayPolicy = SCROLLBARS_ASNEEDED;
1.7 ylafon 139: private boolean hierarchyChanged = true;
1.14 ylafon 140:
1.1 abaird 141: protected Vector items;
142: protected Vector selection;
143: protected int topItem = 0;
144: protected int visibleItemCount = 20;
145: protected int selectionPolicy = SINGLE;
146: protected int fontHeight;
1.14 ylafon 147:
1.1 abaird 148: /**
149: * Builds a new browser instance
150: *
151: * @param root the root node for this hierarchy
152: * @param label the label that should be displayed for this item
153: * @param handler the handler for this node
154: * @param icon the icon that must be displayed for this item
155: */
156: public TreeBrowser(Object root, String label,
157: NodeHandler handler, Image icon) {
158: this();
159: initialize(root, label, handler, icon);
160: }
161:
162: protected TreeBrowser() {
163: selection = new Vector(1, 1);
164: items = new Vector();
165: topItem = 0;
1.4 ylafon 166: addMouseListener(new BrowserMouseListener());
1.1 abaird 167: }
168:
169: protected void initialize(Object item,String label,
170: NodeHandler handler, Image icon) {
171: items.addElement(new TreeNode(item,label, handler, icon, 0));
172: }
173:
1.7 ylafon 174: public Dimension getPreferredSize() {
175: return new Dimension(200, 400);
176: }
1.1 abaird 177:
1.7 ylafon 178: /**
179: * Sets the color of a selected node to the specified color.
180: * @param color the color used to paint a selected node
181: */
182: public void setSelectionFontColor(Color color) {
183: this.selectFontColor = color;
184: }
1.1 abaird 185:
1.7 ylafon 186: /**
187: * Sets the background color of a selected node to the specified color.
188: * @param color the color used to paint the background of a selected node
189: */
190: public void setSelectionBackgroudColor(Color color) {
191: this.selectColor = color;
192: }
1.1 abaird 193:
1.7 ylafon 194: /**
195: * Sets the scrollbars display policy to the specified policy. The default
196: * is SCROLLBARS_ALWAYS
197: * @param scrollbarDisplayPolicy SCROLLBARS_NEVER | SCROLLBARS_ASNEEDED |
198: * SCROLLBARS_ALWAYS
199: */
200: public void setScrollbarDisplayPolicy(int scrollbarDisplayPolicy) {
201: this.scrollbarDisplayPolicy = scrollbarDisplayPolicy;
202: hierarchyChanged = false;
1.1 abaird 203: }
1.14 ylafon 204:
1.7 ylafon 205: /**
206: * repaints the View.
207: */
1.1 abaird 208: public void paint(Graphics g) {
209: fontHeight = g.getFontMetrics().getHeight();
210: int fontAscent = g.getFontMetrics().getAscent();
211: int itemCount = items.size();
212:
1.7 ylafon 213: Dimension dim = getSize();
214: int myHeight = dim.height-VMARGIN*2;
215: int myWidth = dim.width-HMARGIN*2;
216:
217: g.clipRect(HMARGIN, VMARGIN, myWidth, myHeight);
1.1 abaird 218: g.translate(HMARGIN, VMARGIN);
1.7 ylafon 219:
1.1 abaird 220: int y = 0;
221: int dx, fatherIndex;
222: int level;
1.7 ylafon 223:
1.1 abaird 224: Stack indexStack = new Stack();
225: Graphics bg = g.create();
226: bg.setColor(selectColor);
1.7 ylafon 227: g.setFont(getFont());
1.1 abaird 228: visibleItemCount = 0;
229: TreeNode node;
230: level = -1;
1.7 ylafon 231:
232: int labelwidth;
233: if (hierarchyChanged) {
234: maxwidth = 0;
235: }
236:
1.1 abaird 237: // we push the indexes of the inner levels to speed up things
238: for(int i = 0; i < topItem; i++) {
1.7 ylafon 239: node = (TreeNode) items.elementAt(i);
240: // hscroll
241: if (hierarchyChanged) {
242: dx = node.level * DXLEVEL;
243: labelwidth = g.getFontMetrics().stringWidth(node.label);
244: maxwidth = Math.max(maxwidth, dx + DXLEVEL + labelwidth);
245: }
246:
1.1 abaird 247: if(node.level > level) {
248: indexStack.push(new Integer(i-1));
249: level = node.level;
250: }
251: if(node.level < level) {
252: for(int j=node.level; j<level; j++)
253: indexStack.pop();
254: level = node.level;
255: }
256: }
1.7 ylafon 257:
258: int nitems = myHeight/fontHeight;
259: int ditems = itemCount - topItem;
260: if (ditems < nitems) {
261: topItem = Math.max(0, topItem-(nitems-ditems));
262: }
1.8 ylafon 263: if (myWidth >= maxwidth) {
264: startx = 0;
265: } else if (startx+myWidth > maxwidth) {
266: startx = (maxwidth - myWidth);
267: }
1.14 ylafon 268:
1.8 ylafon 269: for(int i = topItem; i < itemCount ; i++) {
270: node = (TreeNode) items.elementAt(i);
271: if(node.level > level) {
272: indexStack.push(new Integer(i-1));
273: level = node.level;
274: }
275: if(node.level < level) {
276: for(int j=node.level; j<level; j++)
277: indexStack.pop();
278: level = node.level;
279: }
1.7 ylafon 280:
1.8 ylafon 281: dx = (node.level * DXLEVEL)-startx;
282: if(y <= myHeight) {
283: if(node.selected) {
1.9 ylafon 284: bg.fillRect(dx, y-1,
285: Math.max(myWidth-1, maxwidth-1), fontHeight);
1.8 ylafon 286: g.setColor(selectFontColor);
287: g.drawImage(node.icon, dx, y, this);
288: g.drawString(node.label, dx + DXLEVEL, y+fontAscent);
289: g.setColor(getForeground());
290: } else {
291: g.setColor(getForeground());
292: g.drawImage(node.icon, dx, y, this);
293: g.drawString(node.label, dx + DXLEVEL, y+fontAscent);
294: }
1.7 ylafon 295:
1.8 ylafon 296: fatherIndex = ((Integer) indexStack.peek()).intValue();
297: if( fatherIndex != -1) { // draw fancy lines
298: int fi = fatherIndex - topItem;
299: g.drawLine(dx - HGAP/2 , y + fontHeight/2,
300: dx - DXLEVEL + HGAP/2, y + fontHeight/2);
1.7 ylafon 301:
1.8 ylafon 302: if(node.handler.isDirectory(this, node)) {
303: g.drawRect(dx - DXLEVEL + HGAP/2 -2,
304: y + fontHeight/2 - 2,
305: 4, 4);
306: }
307: g.drawLine(dx-DXLEVEL + HGAP/2, y + fontHeight/2,
308: dx-DXLEVEL + HGAP/2, (fi+1)*fontHeight - 1);
309: }
310: visibleItemCount++;
311: } else { // draw the lines for invisible nodes.
312: fatherIndex = ((Integer)indexStack.peek()).intValue();
313: if(fatherIndex != -1) {
314: int fi = fatherIndex - topItem;
315: if((fi+1)*fontHeight -1 < myHeight)
316: g.drawLine(dx - DXLEVEL + HGAP/2, myHeight-1,
317: dx - DXLEVEL + HGAP/2, (fi+1)*fontHeight-1);
318: }
319: }
320: // hscroll
321: if (hierarchyChanged) {
322: dx = (node.level * DXLEVEL);
323: labelwidth = g.getFontMetrics().stringWidth(node.label);
324: maxwidth = Math.max(maxwidth, dx + DXLEVEL + labelwidth);
325: }
326: y += fontHeight;
327: }
1.7 ylafon 328:
1.8 ylafon 329: // hscroll
330: if (hierarchyChanged) {
331: for (int i=itemCount; i < items.size(); ++i) {
332: node = (TreeNode) items.elementAt(i);
333: dx = (node.level * DXLEVEL);
334: labelwidth = g.getFontMetrics().stringWidth(node.label);
335: maxwidth = Math.max(maxwidth, dx + DXLEVEL + labelwidth);
336: }
337: }
338: hierarchyChanged = false;
339: updateScrollbars();
1.1 abaird 340: }
1.14 ylafon 341:
1.12 ylafon 342: /**
343: * this should be private. having it protected is a present
344: * for dummy VM that doesn't know that an inner class can access
345: * private method of its parent class
346: */
1.14 ylafon 347:
1.12 ylafon 348: protected TreeNode itemAt(int y) {
1.1 abaird 349: for(int i = topItem; ((i < items.size()) && (y >0)); i++) {
350: if(y < fontHeight) {
351: return (TreeNode) items.elementAt(i);
352: }
353: y -= fontHeight;
354: }
355: return null;
356: }
1.14 ylafon 357:
1.7 ylafon 358: public void update(Graphics pg) {
359: Rectangle r = pg.getClipBounds();
360: Graphics offgc;
361: Image offscreen = null;
362: Dimension d = getSize();
363:
364: // create the offscreen buffer and associated Graphics
365: offscreen = ImageCache.getImage(this, d.width, d.height);
366: offgc = offscreen.getGraphics();
367: if(r != null) {
368: offgc.clipRect(r.x, r.y, r.width, r.height);
369: }
370: // clear the exposed area
371: offgc.setColor(getBackground());
372: offgc.fillRect(0, 0, d.width, d.height);
373: offgc.setColor(getForeground());
374: // do normal redraw
375: paint(offgc);
376: // transfer offscreen to window
377: pg.drawImage(offscreen, 0, 0, this);
1.1 abaird 378:
1.7 ylafon 379: }
1.14 ylafon 380:
1.7 ylafon 381: /**
382: * Inserts new node.
383: *
384: * @param parent the parent node.
385: * @item the abstract object this node refers to. may be null.
386: * @handler the node handler, that will receive notifications for this node
387: * @label the label displayed in the list.
388: * @icon the icon displayed in the list.
389: */
1.1 abaird 390: public void insert(TreeNode parent, Object item, NodeHandler handler,
391: String label, Image icon) {
392: boolean done;
393: int j;
394: if(parent == null) throw new IllegalArgumentException("null parent");
395: if((handler == null) && (label == null)) {
396: throw new IllegalArgumentException("non-null item required");
397: }
1.7 ylafon 398: if(handler == null) {
399: handler = parent.handler;
400: }
1.1 abaird 401: if(label == null) {
402: label = handler.toString();
403: }
404: if(parent.children == TreeNode.NOCHILD) {
405: parent.children = 1;
1.7 ylafon 406: } else {
1.1 abaird 407: parent.children += 1;
408: }
409: done = false;
1.7 ylafon 410: TreeNode node = null;
411:
412: int i = items.indexOf(parent)+parent.children;
413: for (; (i < items.size() &&
414: ((TreeNode) items.elementAt(i)).level > parent.level);
415: i++) {}
416: items.insertElementAt(node=new TreeNode(item, label, handler, icon,
417: parent.level+1), i);
418: // hscroll
419: hierarchyChanged = true;
1.1 abaird 420: }
1.14 ylafon 421:
422:
1.7 ylafon 423: /**
424: * Removes the specified node.
425: * This simply removes a node, without modifying its children if any. USE
426: * WITH CAUTION.
427: * @param node the node to remove
428: */
1.1 abaird 429: public void remove(TreeNode node) {
1.7 ylafon 430: int ind = items.indexOf(node);
431: TreeNode t = null;
432:
433: while (ind>=0) {
434: t = (TreeNode) items.elementAt(ind);
1.10 ylafon 435: if (t.level >= node.level)
1.7 ylafon 436: ind--;
437: else {
438: t.children--;
439: break;
440: }
441: }
1.10 ylafon 442: items.removeElement(node);
1.7 ylafon 443:
1.1 abaird 444: if(node.selected) {
445: unselect(node);
446: }
1.7 ylafon 447: // hscroll
448: hierarchyChanged = true;
1.1 abaird 449: }
1.14 ylafon 450:
1.1 abaird 451: /**
1.7 ylafon 452: * Removes the specified node and its children.
1.5 ylafon 453: * NOTE: if two threads are doing adds and removes,
454: * this can lead to IndexOutOfBound exception.
455: * You will probably have to use locks to get rid of that problem
1.7 ylafon 456: * @param node the node to remove
1.1 abaird 457: */
458: public void removeBranch(TreeNode node) {
459: int ist, iend;
460:
1.7 ylafon 461: ist = items.indexOf(node)+1;
1.1 abaird 462: iend = items.size()-1;
1.7 ylafon 463:
1.1 abaird 464: for(int i = ist; i< iend; i++) {
465: if(((TreeNode)items.elementAt(ist)).level > node.level) {
466: remove((TreeNode)items.elementAt(ist));
467: } else
468: break;
469: }
1.7 ylafon 470: remove(node);
471: // hscroll
472: hierarchyChanged = true;
1.1 abaird 473: }
1.14 ylafon 474:
1.7 ylafon 475: /**
476: * Contracts the representation of the specified node.
477: * removes all the children nodes of 'item'. It is caller's
478: * responsibility to call repaint() afterwards.
479: * @param item the node to contracts
480: */
1.1 abaird 481: public synchronized void collapse(TreeNode item) {
482: TreeNode node = (TreeNode)item;
483: if(node.children != TreeNode.NOCHILD) {
484: node.children = TreeNode.NOCHILD;
485: for(int j = items.indexOf(item)+1; j <items.size(); /*nothing*/) {
486: TreeNode child = (TreeNode)items.elementAt(j);
487: if(child.level > node.level) {
488: items.removeElementAt(j);
489: if(child.selected) {
490: unselect(child);
491: }
492: }
493: else {
1.7 ylafon 494: // hscroll
495: hierarchyChanged = true;
1.1 abaird 496: // last children reached, exit
497: return;
498: }
499: }
500: }
501: }
1.14 ylafon 502:
1.7 ylafon 503: /**
504: * Sets the selection policy.
505: * @param policy: SINGLE or MULTIPLE
506: */
1.1 abaird 507: public void setSelectionPolicy(int policy) {
508: selectionPolicy = policy;
509: }
1.14 ylafon 510:
1.7 ylafon 511: /**
512: * Gets the selection policy.
513: */
1.1 abaird 514: public int getSelectionPolicy() {
515: return selectionPolicy;
516: }
1.14 ylafon 517:
1.7 ylafon 518: /**
519: * Selects the specified node.
520: * Selects the given node. If selectionPolicy is SINGLE any previously
521: * selected node is unselected first. It is caller's responsibility to
522: * call repaint()
523: * @param node the node to select
524: */
1.1 abaird 525: public void select(TreeNode node) {
526: if(node == null) return;
527: if(selectionPolicy == SINGLE) {
528: unselectAll();
529: }
530: selection.addElement(node);
531: node.selected = true;
532: }
1.14 ylafon 533:
1.7 ylafon 534: /**
535: * Unselects the specified node.
536: * It is caller's responsibility to call repaint()
537: * @param node the node to unselect
538: */
1.1 abaird 539: public void unselect(TreeNode node) {
540: if(node == null) return;
541: selection.removeElement(node);
542: node.selected = false;
543: }
1.14 ylafon 544:
1.7 ylafon 545: /**
546: * Unselects all selected items.
547: */
1.1 abaird 548: public void unselectAll() {
549: for(Enumeration e = selection.elements(); e.hasMoreElements(); ) {
550: TreeNode node = (TreeNode)e.nextElement();
551: node.selected = false;
552: }
553: }
1.14 ylafon 554:
1.7 ylafon 555: /**
556: * Returns an Enumeraiton of selected items.
557: */
1.1 abaird 558: public Enumeration selection() {
559: return selection.elements();
560: }
1.14 ylafon 561:
1.1 abaird 562: private void updateScrollbars() {
1.7 ylafon 563: int max = items.size()+1;
564: if(items.size() > visibleItemCount) {
565: vscroll.setMaximum(max);
566: vscroll.setVisibleAmount(visibleItemCount);
567: vscroll.setVisible(true);
568: } else {
569: vscroll.setValue(0);
570: vscroll.setMaximum(max);
571: vscroll.setVisibleAmount(max);
572: if (scrollbarDisplayPolicy == SCROLLBARS_ASNEEDED) {
573: vscroll.setVisible(false);
1.1 abaird 574: }
575: }
1.7 ylafon 576:
577: int myWidth = getSize().width-HMARGIN*2;
578: hscroll.setMaximum(maxwidth);
579: hscroll.setVisibleAmount(myWidth);
580: if (maxwidth > myWidth) {
581: hscroll.setVisible(true);
582: } else {
583: if (scrollbarDisplayPolicy == SCROLLBARS_ASNEEDED) {
584: hscroll.setVisible(false);
585: }
1.1 abaird 586: }
587: }
588:
1.7 ylafon 589: /**
590: * Sets 'a' as vertical Scrollbar.
591: * The Browser becomes an AdjustmentListener of this scrollbar.
592: */
1.1 abaird 593: public void setVerticalScrollbar(Scrollbar a) {
594: vscroll = a;
595: vscroll.addAdjustmentListener(this);
596: vscroll.setMaximum(visibleItemCount);
597: vscroll.setVisibleAmount(visibleItemCount);
598: vscroll.setBlockIncrement(visibleItemCount);
599: }
1.14 ylafon 600:
1.7 ylafon 601: /**
602: * Sets 'a' as horizontal Scrollbar.
603: * The Browser becomes an AdjustmentListener of this scrollbar.
604: */
605: public void setHorizontalScrollbar(Scrollbar a) {
606: hscroll = a;
607: hscroll.addAdjustmentListener(this);
608: int myWidth = getSize().width-HMARGIN*2;
609: hscroll.setMaximum(myWidth);
610: hscroll.setVisibleAmount(myWidth);
611: hscroll.setBlockIncrement(20);
612: }
1.14 ylafon 613:
1.7 ylafon 614: /**
615: * Updates graphical appearance in response to a scroll.
616: */
1.1 abaird 617: public void adjustmentValueChanged(AdjustmentEvent evt) {
1.7 ylafon 618: if (evt.getSource() == vscroll) {
619: topItem = evt.getValue();
620: } else {
621: startx = evt.getValue();
622: }
1.1 abaird 623: repaint();
624: }
1.14 ylafon 625:
1.7 ylafon 626: /**
627: * Returns the parent node of the specified node.
628: * If 'child' is a valid node belonging to the Tree and has a parent node,
629: * returns its parent. Returns null otherwise.
630: * @param child the child node you want to get its parent
631: */
1.1 abaird 632: public TreeNode getParent(TreeNode child) {
633: int n = items.indexOf(child);
634: for(int i = n-1; i >= 0; i--) {
635: TreeNode node = (TreeNode)(items.elementAt(i));
636: if(node.level < child.level) {
637: return node;
638: }
639: }
640: return null;
641: }
1.14 ylafon 642:
1.7 ylafon 643: /**
644: * Gets the node associated to the specified object, or null if any.
645: * @param obj the object related to a node
646: */
647: public TreeNode getNode(Object obj) {
1.1 abaird 648: int imax = items.size();
649: for(int i=0; i < imax; i++) {
1.7 ylafon 650: if(obj.equals(((TreeNode)(items.elementAt(i))).getItem()))
1.1 abaird 651: return (TreeNode)(items.elementAt(i));
652: }
653: return null;
654: }
655: }
1.14 ylafon 656:
1.7 ylafon 657:
Webmaster