Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / jigsaw / src / org / w3c / tools / widgets / TreeBrowser.java
diff --git a/JMCR-Stable/real-world application/jigsaw/src/org/w3c/tools/widgets/TreeBrowser.java b/JMCR-Stable/real-world application/jigsaw/src/org/w3c/tools/widgets/TreeBrowser.java
new file mode 100644 (file)
index 0000000..7d0627b
--- /dev/null
@@ -0,0 +1,658 @@
+// TreeBrowser.java\r
+// $Id: TreeBrowser.java,v 1.1 2010/06/15 12:20:38 smhuang Exp $ */\r
+// Authors: Jean-Michel.Leon@sophia.inria.fr, \r
+//          Yves.Lafon@w3.org : \r
+//          - Lines, insert/remove, awt 1.1 version\r
+//          Thierry.Kormann@sophia.inria.fr\r
+//          - Insert debug, horizontal scrollbar, javadoc, \r
+//            selection graphic customization, scrollbar policy, \r
+//            lightweight version.\r
+\r
+package org.w3c.tools.widgets ;\r
+\r
+import java.awt.Canvas;\r
+import java.awt.Color;\r
+import java.awt.Component;\r
+import java.awt.Dimension;\r
+import java.awt.FontMetrics;\r
+import java.awt.Graphics;\r
+import java.awt.Image;\r
+import java.awt.Rectangle;\r
+import java.awt.Scrollbar;\r
+\r
+import java.awt.event.AdjustmentEvent;\r
+import java.awt.event.AdjustmentListener;\r
+import java.awt.event.MouseAdapter;\r
+import java.awt.event.MouseEvent;\r
+\r
+import java.util.Enumeration;\r
+import java.util.EventObject;\r
+import java.util.Stack;\r
+import java.util.Vector;\r
+\r
+/**\r
+ * The TreeBrowser class.\r
+ *\r
+ * This class is a generic framework to browser any hierachical structure.\r
+ *\r
+ * <p>Genericity is obtained through the use of 'handlers': the TreeBrowser\r
+ * itself does not perform any action in response to user events, but simply\r
+ * forward them as <b>notifications</b> to <b>handlers</b>. Each item inserted\r
+ * may have its own handler, but handlers may also (this is the most common\r
+ * case) be shared between handlers.\r
+ *\r
+ * <p>Any item added in the Tree is displayed with an icon and a label. When a\r
+ * handler receive a notification on a node, it may change this node, to modify\r
+ * or update its appearance.\r
+ *\r
+ * @author Jean-Michel.Leon@sophia.inria.fr\r
+ * @author Yves.Lafon@w3.org\r
+ * @author Thierry.Kormann@sophia.inria.fr \r
+ */\r
+public class TreeBrowser extends Canvas implements AdjustmentListener {\r
+\r
+    /** \r
+     * Specifies that the horizontal/vertical scrollbars should always be shown\r
+     * regardless of the respective sizes of the TreeBrowser.  \r
+     */\r
+    public static final int SCROLLBARS_ALWAYS   = 0; \r
+    /** \r
+     * Specifies that horizontal/vertical scrollbars should be shown only when\r
+     * the size of the nodes exceeds the size of the TreeBrowser in the\r
+     * horizontal/vertical dimension.  \r
+     */\r
+    public static final int SCROLLBARS_ASNEEDED = 1;\r
+    /** \r
+     * This policy that lets just one node selected at the same time. \r
+     */\r
+    public static final int SINGLE = 0;\r
+    /** \r
+     * The policy that enables a multiple selection of nodes. \r
+     */\r
+    public static final int MULTIPLE = 1;\r
+\r
+    static final int HMARGIN = 5;\r
+    static final int VMARGIN = 5;\r
+    static final int HGAP = 10;\r
+    static final int DXLEVEL = HGAP*2;\r
+\r
+    /**\r
+     * The inner mouse listener in charge of all the node expansion\r
+     * selection and execution\r
+     */\r
+    private class BrowserMouseListener extends MouseAdapter {\r
+       \r
+        private void clickAt(TreeNode node, MouseEvent me) {\r
+           if(node == null) \r
+               return;\r
+           int x = me.getX() - HMARGIN;\r
+           if(node.handler == null)\r
+               return;\r
+           //  node.handler.notifyExpand(this, node);\r
+           if((x >= node.level*DXLEVEL) &&\r
+              (x <= node.level*DXLEVEL + DXLEVEL)) {\r
+               // click on expand/collapse button\r
+               if(node.children != TreeNode.NOCHILD) {\r
+                   node.handler.notifyCollapse(TreeBrowser.this, node);\r
+               }\r
+               else {\r
+                   node.handler.notifyExpand(TreeBrowser.this, node);\r
+               }\r
+           }\r
+           else if(x > node.level*DXLEVEL + HGAP) {\r
+               // item selection\r
+               node.handler.notifySelect(TreeBrowser.this, node);\r
+           }\r
+       }\r
+       \r
+       /**\r
+        * Handles events and send notifications ot handlers.\r
+        * is sent, depending on the node's current state.<br>\r
+        * on MOUSE_DOWN on a label, a <b>Select</b> notificaiton is sent.<br>\r
+        * on DOUBLE_CLICK on a label, an <b>Execute</b> notification is sent.\r
+        */\r
+        public void mousePressed(MouseEvent me) {\r
+           int y = me.getY() - VMARGIN;\r
+           if(me.getClickCount() == 1) {\r
+               clickAt(itemAt(y), me);\r
+           }\r
+       }\r
+       \r
+        public void mouseClicked(MouseEvent me) {\r
+           if(me.getClickCount() > 1) {\r
+               int y = me.getY() - VMARGIN;\r
+               TreeNode node = itemAt(y);\r
+               if((node != null) && (node.handler != null)) {\r
+                   node.handler.notifyExecute(TreeBrowser.this, node);\r
+               }\r
+           }\r
+       }\r
+    }\r
+\r
+    private Scrollbar vscroll;\r
+    private Scrollbar hscroll;\r
+    private int maxwidth = 0;\r
+    private int startx = 0;\r
+    private Color selectColor = new Color(0, 0, 128);\r
+    private Color selectFontColor = Color.white;\r
+    private int scrollbarDisplayPolicy = SCROLLBARS_ASNEEDED;\r
+    private boolean hierarchyChanged = true;\r
+\r
+    protected Vector items;\r
+    protected Vector selection;\r
+    protected int topItem = 0;\r
+    protected int visibleItemCount = 20;\r
+    protected int selectionPolicy = SINGLE;\r
+    protected int fontHeight;\r
+\r
+   /**\r
+    * Builds a new browser instance\r
+    *\r
+    * @param root the root node for this hierarchy\r
+    * @param label the label that should be displayed for this item\r
+    * @param handler the handler for this node\r
+    * @param icon the icon that must be displayed for this item\r
+    */    \r
+    public TreeBrowser(Object root, String label,\r
+                      NodeHandler handler, Image icon) {\r
+       this();\r
+       initialize(root, label, handler, icon);\r
+    }\r
+\r
+    protected TreeBrowser() {\r
+       selection = new Vector(1, 1);\r
+       items = new Vector();\r
+       topItem = 0;\r
+       addMouseListener(new BrowserMouseListener());\r
+    }\r
+\r
+    protected void initialize(Object item,String label,\r
+                             NodeHandler handler, Image icon) {\r
+       items.addElement(new TreeNode(item,label, handler, icon, 0));\r
+    }\r
+\r
+    public Dimension getPreferredSize() {\r
+       return new Dimension(200, 400);\r
+    }\r
+\r
+    /**\r
+     * Sets the color of a selected node to the specified color.\r
+     * @param color the color used to paint a selected node\r
+     */\r
+    public void setSelectionFontColor(Color color) {\r
+       this.selectFontColor = color;\r
+    }\r
+\r
+    /**\r
+     * Sets the background color of a selected node to the specified color.\r
+     * @param color the color used to paint the background of a selected node\r
+     */\r
+    public void setSelectionBackgroudColor(Color color) {\r
+       this.selectColor = color;\r
+    }\r
+\r
+    /**\r
+     * Sets the scrollbars display policy to the specified policy. The default\r
+     * is SCROLLBARS_ALWAYS\r
+     * @param scrollbarDisplayPolicy SCROLLBARS_NEVER | SCROLLBARS_ASNEEDED |\r
+     * SCROLLBARS_ALWAYS \r
+     */\r
+    public void setScrollbarDisplayPolicy(int scrollbarDisplayPolicy) {\r
+       this.scrollbarDisplayPolicy = scrollbarDisplayPolicy;\r
+       hierarchyChanged = false;\r
+    }\r
+\r
+    /**\r
+     * repaints the View.\r
+     */\r
+    public void paint(Graphics g) {\r
+       fontHeight = g.getFontMetrics().getHeight();\r
+       int fontAscent = g.getFontMetrics().getAscent();\r
+       int itemCount = items.size();\r
+       \r
+       Dimension dim = getSize();\r
+       int myHeight = dim.height-VMARGIN*2;\r
+       int myWidth = dim.width-HMARGIN*2;\r
+       \r
+       g.clipRect(HMARGIN, VMARGIN, myWidth, myHeight);\r
+       g.translate(HMARGIN, VMARGIN);\r
+       \r
+       int y = 0;\r
+       int dx, fatherIndex;\r
+       int level;\r
+       \r
+       Stack indexStack = new Stack();\r
+       Graphics bg = g.create();\r
+       bg.setColor(selectColor);\r
+       g.setFont(getFont());\r
+       visibleItemCount = 0;\r
+       TreeNode node;\r
+       level = -1;\r
+       \r
+       int labelwidth;\r
+       if (hierarchyChanged) {\r
+           maxwidth = 0;\r
+       }\r
+       \r
+       // we push the indexes of the inner levels to speed up things\r
+       for(int i = 0; i < topItem; i++) {\r
+           node = (TreeNode) items.elementAt(i);\r
+           // hscroll\r
+           if (hierarchyChanged) {\r
+               dx = node.level * DXLEVEL;\r
+               labelwidth = g.getFontMetrics().stringWidth(node.label);\r
+               maxwidth = Math.max(maxwidth, dx + DXLEVEL + labelwidth);\r
+           }\r
+           \r
+           if(node.level > level) {\r
+               indexStack.push(new Integer(i-1));\r
+               level = node.level;\r
+           }\r
+           if(node.level < level) {\r
+               for(int j=node.level; j<level; j++)\r
+                   indexStack.pop();\r
+               level = node.level;\r
+           }\r
+       }\r
+       \r
+       int nitems = myHeight/fontHeight;\r
+       int ditems = itemCount - topItem;\r
+       if (ditems < nitems) {\r
+           topItem = Math.max(0, topItem-(nitems-ditems));\r
+       }\r
+       if (myWidth >= maxwidth) {\r
+          startx = 0;\r
+       } else if (startx+myWidth > maxwidth) {\r
+          startx = (maxwidth - myWidth);\r
+       }\r
+\r
+       for(int i = topItem; i < itemCount ; i++) {\r
+          node = (TreeNode) items.elementAt(i);\r
+          if(node.level > level) {\r
+              indexStack.push(new Integer(i-1));\r
+              level = node.level;\r
+          }\r
+          if(node.level < level) {\r
+              for(int j=node.level; j<level; j++)\r
+                  indexStack.pop();\r
+              level = node.level;\r
+          }\r
+           \r
+          dx = (node.level * DXLEVEL)-startx;\r
+          if(y <= myHeight) {\r
+              if(node.selected) {\r
+                  bg.fillRect(dx, y-1,\r
+                              Math.max(myWidth-1, maxwidth-1), fontHeight);\r
+                  g.setColor(selectFontColor);\r
+                  g.drawImage(node.icon, dx, y, this);\r
+                  g.drawString(node.label, dx + DXLEVEL, y+fontAscent);\r
+                  g.setColor(getForeground());\r
+              } else {\r
+                  g.setColor(getForeground());\r
+                  g.drawImage(node.icon, dx, y, this);\r
+                  g.drawString(node.label, dx + DXLEVEL, y+fontAscent);\r
+              }\r
+               \r
+              fatherIndex = ((Integer) indexStack.peek()).intValue();\r
+              if( fatherIndex != -1) { // draw fancy lines\r
+                  int fi = fatherIndex - topItem;\r
+                  g.drawLine(dx - HGAP/2 , y + fontHeight/2,\r
+                             dx - DXLEVEL + HGAP/2, y + fontHeight/2);\r
+                   \r
+                  if(node.handler.isDirectory(this, node)) {\r
+                      g.drawRect(dx - DXLEVEL + HGAP/2 -2,\r
+                                 y + fontHeight/2 - 2,\r
+                                 4, 4);\r
+                  }\r
+                  g.drawLine(dx-DXLEVEL + HGAP/2, y + fontHeight/2, \r
+                             dx-DXLEVEL + HGAP/2, (fi+1)*fontHeight - 1);\r
+              }\r
+              visibleItemCount++;\r
+          } else { // draw the lines for invisible nodes.\r
+              fatherIndex = ((Integer)indexStack.peek()).intValue();\r
+              if(fatherIndex != -1) {\r
+                  int fi = fatherIndex - topItem;\r
+                  if((fi+1)*fontHeight -1 < myHeight)\r
+                      g.drawLine(dx - DXLEVEL + HGAP/2, myHeight-1,\r
+                                 dx - DXLEVEL + HGAP/2, (fi+1)*fontHeight-1);\r
+              }\r
+          }\r
+          // hscroll\r
+          if (hierarchyChanged) {\r
+              dx = (node.level * DXLEVEL);\r
+              labelwidth = g.getFontMetrics().stringWidth(node.label);\r
+              maxwidth = Math.max(maxwidth, dx + DXLEVEL + labelwidth);\r
+          }\r
+          y += fontHeight;\r
+       }\r
+       \r
+       // hscroll\r
+       if (hierarchyChanged) {\r
+          for (int i=itemCount; i < items.size(); ++i) {\r
+              node = (TreeNode) items.elementAt(i);\r
+              dx = (node.level * DXLEVEL);\r
+              labelwidth = g.getFontMetrics().stringWidth(node.label);\r
+              maxwidth = Math.max(maxwidth, dx + DXLEVEL + labelwidth);\r
+          }\r
+       }\r
+       hierarchyChanged = false;\r
+       updateScrollbars();\r
+    }\r
+\r
+    /**\r
+     * this should be private. having it protected is a present\r
+     * for dummy VM that doesn't know that an inner class can access\r
+     * private method of its parent class\r
+     */\r
+\r
+    protected TreeNode itemAt(int y) {\r
+       for(int i = topItem; ((i < items.size()) && (y >0)); i++) {\r
+           if(y < fontHeight) {\r
+               return (TreeNode) items.elementAt(i);\r
+           }\r
+           y -= fontHeight;\r
+       }\r
+       return null;\r
+    }\r
+\r
+    public void update(Graphics pg) {\r
+        Rectangle r = pg.getClipBounds();\r
+        Graphics offgc;\r
+        Image offscreen = null;\r
+        Dimension d = getSize();\r
+       \r
+        // create the offscreen buffer and associated Graphics\r
+        offscreen = ImageCache.getImage(this, d.width, d.height);\r
+        offgc = offscreen.getGraphics();\r
+        if(r != null) {\r
+            offgc.clipRect(r.x, r.y, r.width, r.height);\r
+        }\r
+        // clear the exposed area\r
+        offgc.setColor(getBackground());\r
+        offgc.fillRect(0, 0, d.width, d.height);\r
+        offgc.setColor(getForeground());\r
+        // do normal redraw\r
+        paint(offgc);\r
+        // transfer offscreen to window\r
+        pg.drawImage(offscreen, 0, 0, this);\r
+\r
+    }\r
+\r
+    /**\r
+     * Inserts new node.\r
+     *\r
+     * @param parent the parent node.\r
+     * @item the abstract object this node refers to. may be null.\r
+     * @handler the node handler, that will receive notifications for this node\r
+     * @label the label displayed in the list.\r
+     * @icon the icon displayed in the list.\r
+     */    \r
+    public void insert(TreeNode parent, Object item, NodeHandler handler,\r
+                      String label, Image icon) {\r
+       boolean done;\r
+       int j;\r
+       if(parent == null) throw new IllegalArgumentException("null parent");\r
+       if((handler == null) && (label == null)) {\r
+           throw new IllegalArgumentException("non-null item required");\r
+       }\r
+       if(handler == null) {\r
+           handler = parent.handler;\r
+       }\r
+       if(label == null) {\r
+           label = handler.toString();\r
+       }\r
+       if(parent.children == TreeNode.NOCHILD) {\r
+           parent.children = 1;\r
+       } else {\r
+           parent.children += 1;\r
+       }\r
+       done = false;\r
+       TreeNode node = null;\r
+\r
+       int i = items.indexOf(parent)+parent.children;\r
+       for (; (i < items.size() && \r
+               ((TreeNode) items.elementAt(i)).level > parent.level); \r
+           i++) {}\r
+       items.insertElementAt(node=new TreeNode(item, label, handler, icon,\r
+                                               parent.level+1), i);\r
+       // hscroll\r
+       hierarchyChanged = true;\r
+       return;\r
+    }\r
+\r
+   \r
+    /**\r
+     * Removes the specified node.\r
+     * This simply removes a node, without modifying its children if any. USE\r
+     * WITH CAUTION.\r
+     * @param node the node to remove\r
+     */\r
+    public void remove(TreeNode node) {\r
+       int ind = items.indexOf(node);\r
+       TreeNode t = null;\r
+\r
+       while (ind>=0) {\r
+           t = (TreeNode) items.elementAt(ind);\r
+           if (t.level >= node.level)\r
+               ind--;\r
+           else {\r
+               t.children--;\r
+               break;\r
+           }\r
+       }\r
+       items.removeElement(node);\r
+       \r
+       if(node.selected) {\r
+           unselect(node);\r
+       }\r
+       // hscroll\r
+       hierarchyChanged = true;\r
+    }\r
+\r
+    /**\r
+     * Removes the specified node and its children.\r
+     * NOTE: if two threads are doing adds and removes,\r
+     * this can lead to IndexOutOfBound exception.\r
+     * You will probably have to use locks to get rid of that problem\r
+     * @param node the node to remove\r
+     */\r
+    public void removeBranch(TreeNode node) {\r
+       int ist, iend;\r
+       \r
+       ist  = items.indexOf(node)+1;\r
+       iend = items.size()-1;\r
+       \r
+       for(int i = ist; i< iend; i++) {\r
+           if(((TreeNode)items.elementAt(ist)).level > node.level) {\r
+               remove((TreeNode)items.elementAt(ist));\r
+           } else\r
+               break;\r
+       }\r
+       remove(node);\r
+       // hscroll\r
+       hierarchyChanged = true;\r
+    }\r
+\r
+    /**\r
+     * Contracts the representation of the specified node.\r
+     * removes all the children nodes of 'item'. It is caller's\r
+     * responsibility to call repaint() afterwards.\r
+     * @param item the node to contracts\r
+     */\r
+    public synchronized void collapse(TreeNode item) {\r
+       TreeNode node = (TreeNode)item;\r
+       if(node.children != TreeNode.NOCHILD) {\r
+           node.children = TreeNode.NOCHILD;\r
+           for(int j = items.indexOf(item)+1; j <items.size(); /*nothing*/) {\r
+               TreeNode child = (TreeNode)items.elementAt(j);\r
+               if(child.level > node.level) {\r
+                   items.removeElementAt(j);\r
+                   if(child.selected) {\r
+                       unselect(child);\r
+                   }\r
+               }\r
+               else {\r
+                   // hscroll\r
+                   hierarchyChanged = true;\r
+                   // last children reached, exit\r
+                   return;\r
+               }\r
+           }\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Sets the selection policy.\r
+     * @param policy: SINGLE or MULTIPLE\r
+     */    \r
+    public void setSelectionPolicy(int policy) {\r
+       selectionPolicy = policy;\r
+    }\r
+\r
+    /**\r
+     * Gets the selection policy.\r
+     */\r
+    public int getSelectionPolicy() {\r
+       return selectionPolicy;\r
+    }\r
+\r
+    /**\r
+     * Selects the specified node.\r
+     * Selects the given node. If selectionPolicy is SINGLE any previously\r
+     * selected node is unselected first.  It is caller's responsibility to\r
+     * call repaint() \r
+     * @param node the node to select\r
+     */\r
+    public void select(TreeNode node) {\r
+       if(node == null) return;\r
+       if(selectionPolicy == SINGLE) {\r
+           unselectAll();\r
+       }\r
+       selection.addElement(node);\r
+       node.selected = true;\r
+    }\r
+\r
+    /**\r
+     * Unselects the specified node.\r
+     * It is caller's responsibility to call repaint()\r
+     * @param node the node to unselect\r
+     */  \r
+    public void unselect(TreeNode node) {\r
+       if(node == null) return;\r
+       selection.removeElement(node);\r
+       node.selected = false;\r
+    }\r
+\r
+    /**\r
+     * Unselects all selected items.\r
+     */    \r
+    public void unselectAll() {\r
+       for(Enumeration e = selection.elements(); e.hasMoreElements(); ) {\r
+           TreeNode node = (TreeNode)e.nextElement();\r
+           node.selected = false;\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Returns an Enumeraiton of selected items.\r
+     */\r
+    public Enumeration selection() {\r
+       return selection.elements();\r
+    }\r
+\r
+    private void updateScrollbars() {\r
+       int max = items.size()+1;\r
+        if(items.size() > visibleItemCount) {\r
+           vscroll.setMaximum(max);\r
+           vscroll.setVisibleAmount(visibleItemCount);\r
+           vscroll.setVisible(true);\r
+        } else {\r
+           vscroll.setValue(0);\r
+           vscroll.setMaximum(max);\r
+           vscroll.setVisibleAmount(max);\r
+           if (scrollbarDisplayPolicy == SCROLLBARS_ASNEEDED) {\r
+               vscroll.setVisible(false);\r
+           }\r
+       }\r
+\r
+       int myWidth = getSize().width-HMARGIN*2;\r
+       hscroll.setMaximum(maxwidth);\r
+       hscroll.setVisibleAmount(myWidth);\r
+       if (maxwidth > myWidth) {\r
+           hscroll.setVisible(true);\r
+       } else {\r
+           if (scrollbarDisplayPolicy == SCROLLBARS_ASNEEDED) {\r
+               hscroll.setVisible(false);\r
+           }\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Sets 'a' as vertical Scrollbar.\r
+     * The Browser becomes an AdjustmentListener of this scrollbar.\r
+     */\r
+    public void setVerticalScrollbar(Scrollbar a) {\r
+       vscroll = a;\r
+       vscroll.addAdjustmentListener(this);\r
+       vscroll.setMaximum(visibleItemCount);\r
+       vscroll.setVisibleAmount(visibleItemCount);\r
+       vscroll.setBlockIncrement(visibleItemCount);\r
+    }\r
+\r
+    /**\r
+     * Sets 'a' as horizontal Scrollbar.\r
+     * The Browser becomes an AdjustmentListener of this scrollbar.\r
+     */\r
+    public void setHorizontalScrollbar(Scrollbar a) {\r
+       hscroll = a;\r
+       hscroll.addAdjustmentListener(this);\r
+       int myWidth = getSize().width-HMARGIN*2;\r
+       hscroll.setMaximum(myWidth);\r
+       hscroll.setVisibleAmount(myWidth);\r
+       hscroll.setBlockIncrement(20);\r
+    }\r
+\r
+    /**\r
+     * Updates graphical appearance in response to a scroll.\r
+     */    \r
+    public void adjustmentValueChanged(AdjustmentEvent evt) {\r
+       if (evt.getSource() == vscroll) {\r
+           topItem = evt.getValue();\r
+       } else {\r
+           startx = evt.getValue();\r
+       }\r
+       repaint();\r
+    }\r
+\r
+    /**\r
+     * Returns the parent node of the specified node.\r
+     * If 'child' is a valid node belonging to the Tree and has a parent node,\r
+     * returns its parent. Returns null otherwise.\r
+     * @param child the child node you want to get its parent\r
+     */\r
+    public TreeNode getParent(TreeNode child) {\r
+       int n = items.indexOf(child);\r
+       for(int i = n-1; i >= 0; i--) {\r
+           TreeNode node = (TreeNode)(items.elementAt(i));\r
+           if(node.level < child.level) {\r
+               return node;\r
+           }\r
+       }\r
+       return null;\r
+    }\r
+\r
+    /**\r
+     * Gets the node associated to the specified object, or null if any.\r
+     * @param obj the object related to a node\r
+     */\r
+    public TreeNode getNode(Object obj) {\r
+       int imax = items.size();\r
+       for(int i=0; i < imax; i++) {\r
+           if(obj.equals(((TreeNode)(items.elementAt(i))).getItem())) \r
+               return (TreeNode)(items.elementAt(i));\r
+       }\r
+       return null;\r
+    }\r
+}\r
+\r
+\r