home *** CD-ROM | disk | FTP | other *** search
/ Symantec Visual Cafe for Java 2.5 / symantec-visual-cafe-2.5-database-dev-edition.iso / VCafe / Source.bin / TreeView.java < prev    next >
Encoding:
Java Source  |  1998-09-14  |  61.3 KB  |  2,217 lines

  1. package symantec.itools.awt;
  2.  
  3.  
  4. import java.awt.BorderLayout;
  5. import java.awt.Color;
  6. import java.awt.SystemColor;
  7. import java.awt.Dimension;
  8. import java.awt.Event;
  9. import java.awt.FontMetrics;
  10. import java.awt.Font;
  11. import java.awt.Graphics;
  12. import java.awt.Image;
  13. import java.awt.LayoutManager;
  14. import java.awt.Scrollbar;
  15. import java.awt.Panel;
  16. import java.awt.Rectangle;
  17. import java.awt.ItemSelectable;
  18. import java.awt.AWTEventMulticaster;
  19. import java.awt.event.ItemEvent;
  20. import java.awt.event.ItemListener;
  21. import java.awt.event.KeyEvent;
  22. import java.awt.event.KeyAdapter;
  23. import java.awt.event.MouseEvent;
  24. import java.awt.event.MouseAdapter;
  25. import java.awt.event.FocusEvent;
  26. import java.awt.event.FocusAdapter;
  27. import java.awt.event.AdjustmentEvent;
  28. import java.awt.event.AdjustmentListener;
  29. import java.awt.event.ActionEvent;
  30. import java.awt.event.ActionListener;
  31. import java.util.Vector;
  32. import java.beans.PropertyVetoException;
  33. import java.beans.PropertyChangeListener;
  34. import java.beans.VetoableChangeListener;
  35. import java.beans.PropertyChangeEvent;
  36. import java.util.ResourceBundle;
  37.  
  38.  
  39. //    01/15/97    RKM    Changed drawTree to make certain g1 has a font, before calling getFontMetrics on it
  40. //    01/15/07    RKM    Added invalidate to setTreeStructure
  41. //    01/29/97    TWB    Integrated changes from Windows and RKM's changes
  42. //     01/29/97    TWB    Integrated changes from Macintosh
  43. //  02/05/97    MSH Changed so that draws from first visible node
  44. //  02/27/97    MSH Merged change to add SEL_CHANGED
  45. //  04/02/97    TNM Draw all vertical lines
  46. //  04/14/97    RKM Changed bogus invalidates to repaint
  47. //                RKM    Changed hard coded sbVWidth to use preferredSize.width
  48. //                RKM Changed getTreeStructure so it actually returned a representation of what was in the treeview
  49. //                RKM    Rearranged a lot of stuff to get this to work
  50. //                RKM Changed g1.drawRect in drawTree to not overlap the scrollbar
  51. //                RKM Changed parseTreeStructure to not force a root node
  52. //  05/02/97    RKM Add arg to addSibling so caller could control whether the sible was added as the last sibling or not
  53. //                RKM    Changed insert to call addSibling with false when handling NEXT
  54. //                RKM    Kept addSibling with two params for compatibility
  55. //    05/31/97    RKM    Updated to support Java 1.1
  56. //                    Made properties bound & constrained
  57. //                    Removed get/setBackground & get/setForeground overrides, getter did nothing but call the super
  58. //                    and setters were calling repaint, no one else does this
  59. //                    Deprecated foreground and background hilite colors, used system colors instead
  60. //                    Deprecated SEL_CHANGED, replaced by ItemSelectable interface
  61. //                    Hid scrollbar on creation, to avoid ugly redraw problems
  62. //                    Changed to triggered redraw
  63. //                    NOTE: SystemColor seems to be broken on Mac
  64. //  06/01/97    RKM    Changed symantec.beans references to java.beans
  65. //  05/13/97    TNM Added horizontal scrollbar
  66. //  05/15/97    TNM Check for vendor to corect scrollbar problem
  67. //  06/09/97    CAR Modified check for vendor to include java.version 1.1.x
  68. //  06/19/97    TNM Merging changes
  69. //  07/25/97    CAR marked fields transient as needed will have to re-test after event handling code is changed
  70. //  08/14/97    RKM Changed hiliteColor to be consistent when on Mac
  71. //  08/20/97    LAB Changed protection of triggerRedraw to public from protected to allow the node
  72. //                    to trigger redraws.  Addresses Mac Bug #4372.  Changed privates to protecteds.
  73. //                    Reorganized the code in correspondence to the GoodBean Spec.  Deleted null
  74. //                    methods that had been deprecated.  Made some package level functions public.
  75. //                    Separated the internals of event hadling into protected handle<event> methods
  76. //                    to facilitate overriding.  Updated the InvalidTreeNodeException class to take
  77. //                    a message string for more detailed exceptions.  Fixed findLastPreSpace to handle
  78. //                    being passed null strings, or strings with no lenght (Addresses Mac Bug #4005).
  79. //                    Added clear method (Addresses Mac Bug #7369).  Fixed so selection is only set
  80. //                    if a single or double click occurs on a node, or if selected node was made
  81. //                    invisible by node collapse.  deprecated preferredSize and minimumSize in favor
  82. //                    of getPreferredSize and getMiniumumSize.  Made getPreferredSize calculate
  83. //                    the size TreeView should be based on the parts of the TreeView that are visible.
  84. //                    Added newTreeNode function to allow interception of the creation of nodes (Addresses
  85. //                    Win Bug #4174).  Took out isDesignTime code in paint that caused looping paints
  86. //                    (i.e. flickering) at design time.  Added paintTree(TreeNode, boolean) that
  87. //                    allows tree to be output with indenting (Win Bug #13095).  Fixed append to
  88. //                    make sure the node to append didn't already exist in the tree (Win Bug #13050).
  89. //                    Updated javadoc on append, insert, remove, removeSelected, etc. (Win Bug #12663).
  90. //  08/22/97    LAB    Call resetVector() before sending Action events so internal state is reset
  91. //                    (Addresses Win Bug #12666).  redraw now only calls resetVector if needed.
  92. //  08/26/97    CAR added null and zero length parameter checks to setTreeStructure
  93. //  08/28/97    CAR fixed bug re: horizontal scrolling not working
  94. //  08/28/97    RKM Added isFocusTraversable override (Yep, you can tab to this one)
  95. //  08/29/97    CAR modified getPreferredSize and getMinimumSize
  96. //  09/24/97    RKM Properly set isSun1_1 for Apple MRJ 2.0
  97. //                    Set isSun1_1 same as MutliList did (changed to static)
  98. //  10/04/97    LAB    Added ItemEvent firing when a node is expaned or collapsed.  Added
  99. //                    NODE_TOGGLED, NODE_EXPANDED, and NODE_COLLAPSED constants to support this.
  100. //  12/09/97    DS  Added check for a null itemListener in handleMousePressed
  101. //  12/19/97    DS  Added more checks for a null itemListener in handleMousePressed
  102. //  02/09/98    DS  Added support for hiding/showing nodes (TreeNode.setHidden(boolean)
  103. //                  Added support for deslecting a node (setSelectedNode(Tree Node)
  104.  
  105.  
  106. /**
  107.  * Creates an "outline view" of text headings and, optionally, images.
  108.  * The headings are arranged in a hierarchical fashion, and can be
  109.  * expanded to show their sub-headings or collapsed, hiding their
  110.  * sub-headings.
  111.  * <p>
  112.  * A TreeView is typically used to display information that is organized in a
  113.  * hierarchical fashion like an index or table of contents.
  114.  * <p>
  115.  * A TreeNode object is used for each heading.
  116.  * @see TreeNode
  117.  */
  118. public class TreeView extends Panel implements ItemSelectable
  119. {
  120.     // constants for insertion
  121.     /**
  122.      * Constant indicating that the new node is to be a child
  123.      * of the existing node.
  124.      * @see #insert
  125.      */
  126.     public static final int CHILD   = 0;
  127.     /**
  128.      * Constant indicating that the new node is to be the next
  129.      * sibling of the existing node.
  130.      * @see #insert
  131.      */
  132.     public static final int NEXT    = CHILD + 1;
  133.     /**
  134.      * Constant indicating that the new node is to be the last
  135.      * sibling of the existing node.
  136.      * @see #insert
  137.      */
  138.     public static final int LAST    = CHILD + 2;
  139.     /**
  140.      * Constand used to describe ItemEvents sent when a node is toggled.
  141.      * @see #NODE_EXPANDED
  142.      * @see #NODE_COLLAPSED
  143.      */
  144.     public static final int NODE_TOGGLED = 2001;
  145.     /**
  146.      * Constand used to detail that the node referenced in a NODE_TOGGLED ItemEvent has been expanded.
  147.      * @see #NODE_TOGGLED
  148.      * @see #NODE_COLLAPSED
  149.      */
  150.     public static final int NODE_EXPANDED = 2002;
  151.     /**
  152.      * Constand used to detail that the node referenced in a NODE_TOGGLED ItemEvent has been collapsed.
  153.      * @see #NODE_TOGGLED
  154.      * @see #NODE_EXPANDED
  155.      */
  156.     public static final int NODE_COLLAPSED = 2003;
  157.     /**
  158.      * @deprecated As of JDK version 1.1,
  159.      * replaced by ItemSelectable interface.
  160.      * @see java.awt.ItemSelectable
  161.      */
  162.     public static final int SEL_CHANGED = 1006; //selection changed event
  163.  
  164.     //
  165.     // Constructors
  166.     //
  167.  
  168.     /**
  169.      * Constructs an empty TreeView.
  170.      */
  171.     public TreeView()
  172.     {
  173.         super.setLayout(null);
  174.  
  175.         verticalScrollBar = new Scrollbar(Scrollbar.VERTICAL);
  176.         verticalScrollBar.hide();
  177.         add(verticalScrollBar);
  178.  
  179.         horizontalScrollBar = new Scrollbar(Scrollbar.HORIZONTAL);
  180.         horizontalScrollBar.hide();
  181.         add(horizontalScrollBar);
  182.  
  183.         needResetVector = true;
  184.     }
  185.  
  186.     /**
  187.      * Constructs a TreeView with the given node.
  188.      *
  189.      * @param head the root node of the constructed tree
  190.      */
  191.     public TreeView(TreeNode head)
  192.     {
  193.         this();
  194.         selectedNode = rootNode = head;
  195.         count = 1;
  196.     }
  197.  
  198.     //
  199.     // Properties
  200.     //
  201.  
  202.     /**
  203.      * Initializes the TreeView from a string array.
  204.      * There is one string for each node in the array. That string
  205.      * contains the text of the node indented with same number of
  206.      * leading spaces as the depth of that node in the tree.
  207.      * @param s the string array used for initialization.
  208.      * If null, the tree will be cleared.
  209.      * @see #getTreeStructure
  210.      */
  211.     public void setTreeStructure(String s[])
  212.     {
  213.         if (s == null || s.length == 0)
  214.         {
  215.             clear();
  216.             return;
  217.         }
  218.  
  219.         rootNode = selectedNode = null;
  220.         try
  221.         {
  222.             parseTreeStructure(s);
  223.         }
  224.         catch(InvalidTreeNodeException e)
  225.         {
  226.             System.err.println(e);
  227.         }
  228.  
  229.         triggerRedraw();
  230.  
  231.         invalidate();
  232.     }
  233.  
  234.     /**
  235.      * Gets a string array that reflects the current TreeView's contents.
  236.      * There is one string for each node in the array. That string
  237.      * contains the text of the node indented with same number of
  238.      * leading spaces as the depth of that node in the tree.
  239.      * @return the string array that reflects the TreeView's contents
  240.      * @see #setTreeStructure
  241.      */
  242.     public String[] getTreeStructure()
  243.     {
  244.         //Create a vector representing current tree structure
  245.         if (rootNode==null) return null;
  246.         Vector nodesVector = new Vector(count);
  247.         rootNode.depth = 0;
  248.         vectorize(rootNode, false, false, nodesVector);
  249.  
  250.         //Convert this to a String[]
  251.         int numNodes = nodesVector.size();
  252.         String[] treeStructure = new String[numNodes];
  253.         for (int i = 0;i < numNodes;i++)
  254.         {
  255.             TreeNode thisNode = (TreeNode)nodesVector.elementAt(i);
  256.  
  257.             //Add appropriate number of blanks
  258.             String treeString = "";
  259.             for (int numBlanks = 0;numBlanks < thisNode.depth;numBlanks++)
  260.                 treeString += ' ';
  261.  
  262.             //Add tree
  263.             treeString += thisNode.text;
  264.  
  265.             //Put string into array
  266.             treeStructure[i] = treeString;
  267.         }
  268.  
  269.         return treeStructure;
  270.     }
  271.  
  272.     //
  273.     // Deprecated Properties
  274.     //
  275.  
  276.     /**
  277.      * @deprecated As of JDK version 1.1,
  278.      * replaced by use of SystemColors.textHighlightText.
  279.      */
  280.     public Color getFgHilite()
  281.     {
  282.         return SystemColor.textHighlightText;
  283.     }
  284.  
  285.     /**
  286.      * @deprecated As of JDK version 1.1,
  287.      * replaced by use of SystemColors.textHighlight.
  288.      */
  289.     public Color getBgHilite()
  290.     {
  291.         return SystemColor.textHighlight;
  292.     }
  293.  
  294.     //
  295.     // ItemSelectable interface
  296.     //
  297.  
  298.     /**
  299.      * Returns the selected items or null if no items are selected.
  300.      * <p>
  301.      * This is a standard method of the ItemSelectable interface.
  302.      */
  303.     public Object[] getSelectedObjects()
  304.     {
  305.         if (selectedNode == null)
  306.             return null;
  307.  
  308.         TreeNode[] selectedObjects = new TreeNode[1];
  309.         selectedObjects[0] = selectedNode;
  310.  
  311.         return selectedObjects;
  312.     }
  313.  
  314.     //
  315.     // Methods
  316.     //
  317.  
  318.     // Insert a new node relative to a node in the tree.
  319.     // position = CHILD inserts the new node as a child of the node
  320.     // position = NEXT inserts the new node as the next sibling
  321.     // position = LAST inserts the new node as the last sibling
  322.     /**
  323.      * Inserts a new node relative to an existing node in the tree.
  324.      * @param newNode the new node to insert into the tree
  325.      * @param relativeNode the existing node used for a position reference
  326.      * @param position where to insert the new node relative to relativeNode.
  327.      * Legal values are CHILD, NEXT and LAST.
  328.      * @see #CHILD
  329.      * @see #NEXT
  330.      * @see #LAST
  331.      * @see #append
  332.     */
  333.     public void insert(TreeNode newNode, TreeNode relativeNode, int position)
  334.     {
  335.         if (newNode == null || relativeNode == null)
  336.             return;
  337.  
  338.         if (exists(relativeNode)==false)
  339.             return;
  340.  
  341.         switch (position)
  342.         {
  343.             case CHILD:
  344.                 addChild(newNode, relativeNode);
  345.                 break;
  346.  
  347.             case NEXT:
  348.                 addSibling(newNode, relativeNode, false);
  349.                 break;
  350.  
  351.             case LAST:
  352.                 addSibling(newNode, relativeNode, true);
  353.                 break;
  354.  
  355.             default:
  356.                 // invalid position
  357.                 return;
  358.         }
  359.     }
  360.  
  361.     /**
  362.      * Clears the tree structure and redraws.
  363.      */
  364.     public void clear()
  365.     {
  366.         rootNode = selectedNode = null;
  367.         count = 0;
  368.         v = new Vector();
  369.         e = new Vector();
  370.         triggerRedraw();
  371.  
  372.         invalidate();
  373.     }
  374.  
  375.     /**
  376.      * Returns the "root" node.
  377.      * The root node is the first top-level node in the tree hierarchy.
  378.      * All other nodes are either children or siblings of that one.
  379.      * @return the root tree node
  380.      */
  381.     public TreeNode getRootNode()
  382.     {
  383.         return rootNode;
  384.     }
  385.  
  386.     /**
  387.      * Returns the total number of nodes in the tree.
  388.      */
  389.     public int getCount()
  390.     {
  391.         return count;
  392.     }
  393.  
  394.     /**
  395.      * Returns the total number of viewable nodes in the tree.
  396.      * A node is viewable if all of its parents are expanded.
  397.      */
  398.     public int getViewCount()
  399.     {
  400.         return viewCount;
  401.     }
  402.  
  403.     /**
  404.      * Determines if the given node is viewable.
  405.      * A node is viewable if all of its parents are expanded.
  406.      * @param node the node to check
  407.      * @return true if the node is visible, false if it is not
  408.      * @see #viewable(java.lang.String)
  409.      */
  410.     boolean viewable(TreeNode node)
  411.     {
  412.         for (int i=0; i<viewCount; i++)
  413.         {
  414.             if (node == v.elementAt(i))
  415.             {
  416.                 return true;
  417.             }
  418.         }
  419.  
  420.         return false;
  421.     }
  422.  
  423.     /**
  424.      * Determines if the node with the given text is viewable.
  425.      * A node is viewable if all of its parents are expanded.
  426.      * @param s the node text to find
  427.      * @return true if the node is visible, false if it is not
  428.      * @see #viewable(TreeNode)
  429.      */
  430.     boolean viewable(String s)
  431.     {
  432.         if (s==null)
  433.         {
  434.             return false;
  435.         }
  436.  
  437.         for (int i=0; i<viewCount; i++)
  438.         {
  439.             TreeNode tn = (TreeNode)v.elementAt(i);
  440.  
  441.             if (tn.text != null)
  442.             {
  443.                 if (s.equals(tn.text))
  444.                 {
  445.                     return true;
  446.                 }
  447.             }
  448.         }
  449.  
  450.         return false;
  451.     }
  452.  
  453.     /**
  454.      * Determines if the given node is in the TreeView.
  455.      * @param node the node to check
  456.      * @return true if the node is in the TreeView, false if it is not
  457.      * @see #exists(java.lang.String)
  458.      */
  459.     public boolean exists(TreeNode node)
  460.     {
  461.         recount();
  462.  
  463.         for (int i=0; i<count; i++)
  464.         {
  465.             if (node == e.elementAt(i))
  466.             {
  467.                 return true;
  468.             }
  469.         }
  470.  
  471.         return false;
  472.     }
  473.  
  474.     /**
  475.      * Determines if the node with the given text is in the TreeView.
  476.      * @param s the node text to find
  477.      * @return true if the node is in the TreeView, false if it is not
  478.      * @see #exists(symantec.itools.awt.TreeNode)
  479.      */
  480.     public boolean exists(String s)
  481.     {
  482.         recount();
  483.  
  484.         if (s==null)
  485.         {
  486.             return false;
  487.         }
  488.  
  489.         for (int i=0; i<count; i++)
  490.         {
  491.             TreeNode tn = (TreeNode)e.elementAt(i);
  492.  
  493.             if (tn.text != null)
  494.             {
  495.                 if (s.equals(tn.text))
  496.                 {
  497.                     return true;
  498.                 }
  499.             }
  500.         }
  501.  
  502.         return false;
  503.     }
  504.  
  505.     /**
  506.      * Adds a new node at root level. If there is no root node, the given
  507.      * node is made the root node. If there is a root node, the given node
  508.      * is made a sibling of the root node.
  509.      * @param newNode the new node to add
  510.      * Does not redraw the component.  Allows you to call repeatedly without
  511.      * causing the component to flicker while nodes are manipulated.  After all
  512.      * manipulation is done, repaint the tree.
  513.      * @see #insert
  514.      */
  515.     public void append(TreeNode newNode)
  516.     {
  517.         if (rootNode == null)
  518.         {
  519.             rootNode = newNode;
  520.             selectedNode = rootNode;
  521.             count = 1;
  522.             redrawTriggered = true;
  523.         }
  524.         else
  525.         {
  526.             recount();
  527.             if (e.contains(newNode))
  528.                 System.err.println(new InvalidTreeNodeException("append: " + errors.getString("NodeAlreadyExists")));
  529.             else
  530.                 addSibling(newNode, rootNode, true);
  531.         }
  532.     }
  533.  
  534.     /**
  535.      * Adds the specified child node to the specified parent node
  536.      * @param newNode the node to add as a child
  537.      * @param relativeNode the node to add the child to.
  538.      * Does not redraw the component.  Allows you to call repeatedly without
  539.      * causing the component to flicker while nodes are manipulated.  After all
  540.      * manipulation is done, repaint the tree.
  541.      */
  542.     public void addChild(TreeNode newNode, TreeNode relativeNode)
  543.     {
  544.         if (relativeNode.child == null)
  545.         {
  546.             relativeNode.child = newNode;
  547.             newNode.parent = relativeNode;
  548.             count++;
  549.             redrawTriggered = true;
  550.         }
  551.         else
  552.         {
  553.             addSibling(newNode, relativeNode.child, true);
  554.         }
  555.  
  556.         relativeNode.numberOfChildren++;
  557.     }
  558.  
  559.     /**
  560.      * Adds the specified node as a sibling to the specified node
  561.      * @param newNode the node to add as a sibling
  562.      * @param siblingNode a sibling node to the new node.
  563.      * Does not redraw the component.  Allows you to call repeatedly without
  564.      * causing the component to flicker while nodes are manipulated.  After all
  565.      * manipulation is done, repaint the tree.
  566.      * @see #addSibling(TreeNode newNode, TreeNode siblingNode, boolean asLastSibling)
  567.      */
  568.     public void addSibling(TreeNode newNode, TreeNode siblingNode)
  569.     {
  570.         addSibling(newNode,siblingNode,true);
  571.     }
  572.  
  573.     /**
  574.      * Adds the specified node as a sibling to the specified node
  575.      * @param newNode the node to add as a sibling
  576.      * @param siblingNode a sibling node to the new node.
  577.      * @param asLastSibling if true, then add the new node as the last (bottommost)
  578.      * sibling node to the specified sibling node.
  579.      * Does not redraw the component.  Allows you to call repeatedly without
  580.      * causing the component to flicker while nodes are manipulated.  After all
  581.      * manipulation is done, repaint the tree.
  582.      * @see #addSibling(TreeNode newNode, TreeNode siblingNode)
  583.      */
  584.     public void addSibling(TreeNode newNode, TreeNode siblingNode, boolean asLastSibling)
  585.     {
  586.         if (asLastSibling)
  587.         {
  588.             //Find last sibling
  589.             TreeNode tempNode = siblingNode;
  590.             while (tempNode.sibling != null)
  591.                 tempNode = tempNode.sibling;
  592.  
  593.             tempNode.sibling = newNode;
  594.         }
  595.         else
  596.         {
  597.             //Insert the newNode below the siblingNode
  598.             newNode.sibling = siblingNode.sibling;
  599.  
  600.             siblingNode.sibling = newNode;
  601.         }
  602.  
  603.         //Set the parent of the new node to the parent of the sibling
  604.         newNode.parent = siblingNode.parent;
  605.  
  606.         count++;
  607.         redrawTriggered = true;
  608.     }
  609.  
  610.     /**
  611.      * Removes the node with the given text from the TreeView.
  612.      * @param s the node text to find
  613.      * @return the TreeNode removed from this TreeView or null if not found
  614.      * Does not redraw the component.  Allows you to call repeatedly without
  615.      * causing the component to flicker while nodes are manipulated.  After all
  616.      * manipulation is done, repaint the tree.
  617.      * @see #remove(symantec.itools.awt.TreeNode)
  618.      * @see #removeSelected
  619.      */
  620.     public TreeNode remove(String s)
  621.     {
  622.         recount();
  623.  
  624.         for (int i=0; i<count; i++)
  625.         {
  626.             TreeNode tn = (TreeNode)e.elementAt(i);
  627.  
  628.             if (tn.text != null)
  629.             {
  630.                 if (s.equals(tn.text))
  631.                 {
  632.                     remove(tn);
  633.                     redrawTriggered = true;
  634.                     return tn;
  635.                 }
  636.             }
  637.         }
  638.  
  639.         return null;
  640.     }
  641.  
  642.     /**
  643.      * Removes the currently selected node from the TreeView.
  644.      * Does not redraw the component.  Allows you to call repeatedly without
  645.      * causing the component to flicker while nodes are manipulated.  After all
  646.      * manipulation is done, repaint the tree.
  647.      * @see #remove(symantec.itools.awt.TreeNode)
  648.      * @see #remove(java.lang.String)
  649.      */
  650.     public void removeSelected()
  651.     {
  652.         if (selectedNode != null)
  653.         {
  654.             remove(selectedNode);
  655.         }
  656.     }
  657.  
  658.     /**
  659.      * Removes the given node from the TreeView.
  660.      * @param node the node to remove
  661.      * @return the TreeNode removed from this TreeView or null if not found
  662.      * Does not redraw the component.  Allows you to call repeatedly without
  663.      * causing the component to flicker while nodes are manipulated.  After all
  664.      * manipulation is done, repaint the tree.
  665.      * @see #remove(java.lang.String)
  666.      * @see #removeSelected
  667.      */
  668.     public void remove(TreeNode node)
  669.     {
  670.         if (!exists(node))
  671.         {
  672.             return;
  673.         }
  674.  
  675.         if (node == selectedNode)
  676.         {
  677.             int index = v.indexOf(selectedNode);
  678.  
  679.             if (index == -1)
  680.             {    //not viewable
  681.                 index = e.indexOf(selectedNode);
  682.             }
  683.  
  684.             if (index > viewCount-1)
  685.             {
  686.                 index = viewCount-1;
  687.             }
  688.  
  689.             if (index>0)
  690.             {
  691.                 setSelectedNode((TreeNode)v.elementAt(index-1));
  692.             }
  693.             else if (viewCount>1)
  694.             {
  695.                 setSelectedNode((TreeNode)v.elementAt(1));
  696.             }
  697.         }
  698.  
  699.         // remove node and its decendents
  700.         if (node.parent != null)
  701.         {
  702.             if (node.parent.child == node)
  703.             {
  704.                 if (node.sibling != null)
  705.                 {
  706.                     node.parent.child = node.sibling;
  707.                 }
  708.                 else
  709.                 {
  710.                     node.parent.child = null;
  711.                     node.parent.collapse();
  712.                 }
  713.             }
  714.             else
  715.             {
  716.                 TreeNode tn=node.parent.child;
  717.  
  718.                 while (tn.sibling != node)
  719.                 {
  720.                     tn = tn.sibling;
  721.                 }
  722.  
  723.                 if (node.sibling != null)
  724.                 {
  725.                     tn.sibling = node.sibling;
  726.                 }
  727.                 else
  728.                 {
  729.                     tn.sibling = null;
  730.                 }
  731.             }
  732.         }
  733.         else
  734.         {
  735.             if (node == rootNode)
  736.             {
  737.                 if (node.sibling == null)
  738.                 {
  739.                     rootNode=null;
  740.                 }
  741.                 else
  742.                 {
  743.                     rootNode=node.sibling;
  744.                 }
  745.             }
  746.             else
  747.             {
  748.                 TreeNode tn = rootNode;
  749.  
  750.                 while (tn.sibling != node)
  751.                 {
  752.                     tn = tn.sibling;
  753.                 }
  754.  
  755.                 if (node.sibling != null)
  756.                 {
  757.                     tn.sibling = node.sibling;
  758.                 }
  759.                 else
  760.                 {
  761.                     tn.sibling = null;
  762.                 }
  763.             }
  764.         }
  765.  
  766.         recount();
  767.         redrawTriggered = true;
  768.     }
  769.  
  770.     /**
  771.      * Print out the text of each node in the TreeView beginning with
  772.      * the given node.
  773.      * The nodes are printed out one per line with no indenting.
  774.      * @param node the first node to print
  775.      */
  776.     public void printTree(TreeNode node)
  777.     {
  778.         printTree(node, false);
  779.     }
  780.  
  781.     /**
  782.      * Print out the text of each node in the TreeView beginning with
  783.      * the given node.
  784.      * The nodes are printed out one per line with no indenting.
  785.      * @param node the first node to print
  786.      * @param isIndented, if true, nodes will have hierarchical indenting,
  787.      * if false, all nodes will pe printed at the same level.
  788.      */
  789.     public void printTree(TreeNode node, boolean isIndented)
  790.     {
  791.         if (node == null)
  792.         {
  793.             return;
  794.         }
  795.         String padding = new String();
  796.         if (isIndented)
  797.         {
  798.             for (int i = 0; i < node.depth; i++)
  799.                 padding = "  " + padding;
  800.         }
  801.  
  802.         System.out.println(padding + node.text);
  803.         printTree(node.child, isIndented);
  804.         printTree(node.sibling, isIndented);
  805.     }
  806.  
  807.     /**
  808.      * Gets the currently selected node.
  809.      * @return the currently selected node, or null if none selected
  810.      */
  811.     public TreeNode getSelectedNode()
  812.     {
  813.         return selectedNode;
  814.     }
  815.  
  816.     /**
  817.      * Gets the text of the currently selected node.
  818.      * @return the text of the currently selected node or null if no node
  819.      * is selected
  820.      */
  821.     public String getSelectedText()
  822.     {
  823.         if (selectedNode == null)
  824.             return null;
  825.  
  826.         return selectedNode.getText();
  827.     }
  828.  
  829.     // -----------------------------------------
  830.     // --------- graphics related methods ------
  831.     // -----------------------------------------
  832.     /**
  833.      * Handles redrawing of this component on the screen.
  834.      * This is a standard Java AWT method which gets called by the Java
  835.      * AWT (repaint()) to handle repainting this component on the screen.
  836.      * The graphics context clipping region is set to the bounding rectangle
  837.      * of this component and its [0,0] coordinate is this component's
  838.      * top-left corner.
  839.      * Typically this method paints the background color to clear the
  840.      * component's drawing space, sets graphics context to be the foreground
  841.      * color, and then calls paint() to draw the component.
  842.      *
  843.      * It is overridden here to reduce flicker by eliminating the uneeded
  844.      * clearing of the background.
  845.      *
  846.      * @param g the graphics context
  847.      * @see java.awt.Component#repaint
  848.      * @see #paint
  849.      */
  850.     public void update (Graphics g)
  851.     {
  852.         //(eliminates background draw to reduce flicker)
  853.         paint(g);
  854.     }
  855.  
  856.     /**
  857.      * Paints this component using the given graphics context.
  858.      * This is a standard Java AWT method which typically gets called
  859.      * by the AWT to handle painting this component. It paints this component
  860.      * using the given graphics context. The graphics context clipping region
  861.      * is set to the bounding rectangle of this component and its [0,0]
  862.      * coordinate is this component's top-left corner.
  863.      *
  864.      * @param g the graphics context used for painting
  865.      * @see java.awt.Component#repaint
  866.      * @see #update
  867.      */
  868.     public void paint (Graphics g)
  869.     {
  870.         Dimension d = size();
  871.  
  872.         if (redrawTriggered || (d.width != viewWidth) || (d.height != viewHeight))
  873.         {
  874.             // redraw needed, or size has changed
  875.             redraw(g);
  876.         }
  877.  
  878.         g.translate(-sbHPosition, 0);
  879.         g.clearRect(sbHPosition,0,d.width-sbVWidth,d.height-sbHHeight);
  880.         if (sbVShow && sbHShow)
  881.         {
  882.             g.setColor(Color.lightGray);
  883.             g.fillRect(sbHPosition+d.width-sbVWidth, d.height-sbHHeight, sbVWidth, sbHHeight);
  884.         }
  885.         g.clipRect(sbHPosition,0,d.width-sbVWidth,d.height-sbHHeight);
  886.         g.drawImage(im1, 0, 0, this);
  887.         g.setColor(Color.black);
  888.         g.drawRect(sbHPosition,0, d.width-sbVWidth-1, d.height-sbHHeight-1);
  889.  
  890.     }
  891.  
  892.     /**
  893.      * Lays out the vertical scrollbar as needed, then draws the TreeView into
  894.      * an offscreen image. This is used for cleaner refresh.
  895.      */
  896.     public void redraw()
  897.     {
  898.         //For backward compatibality. Do not allow to call only redraw() without recalculation.
  899.         triggerRedraw();
  900.     }
  901.     
  902.     public void repaint(boolean f)
  903.     {
  904.         if(f)
  905.         {
  906.             needResetVector = true;
  907.         }
  908.         
  909.         triggerRedraw();
  910.     }
  911.  
  912.     /**
  913.      * Lays out the vertical scrollbar as needed, then draws the TreeView into
  914.      * an offscreen image. This is used for cleaner refresh.
  915.      * @param g the graphics object use for drawing
  916.      */
  917.     public void redraw(Graphics g)
  918.     {
  919.         Dimension d = size();
  920.  
  921.         redrawTriggered = false;
  922.  
  923.         if(needResetVector)
  924.             resetVector();
  925.         else
  926.             needResetVector = true;
  927.  
  928.         newWidth = compWidth(g);
  929.  
  930.         int inRectCount = ((d.height - sbHHeight) / cellSize);
  931.         
  932.         if (viewCount > inRectCount)
  933.         {
  934.               // need the vertical scrollbar
  935.             sbVShow  = true;
  936.             sbVWidth = verticalScrollBar.preferredSize().width;
  937.         }
  938.         else
  939.         {
  940.               sbVShow     = false;
  941.             sbVWidth    = 0;
  942.             sbVPosition = 0;
  943.         }
  944.  
  945.         if (newWidth > (d.width - sbVWidth))
  946.         {
  947.             // need the horizontal scrollbar
  948.             sbHShow = true;
  949.             sbHHeight = horizontalScrollBar.preferredSize().height;
  950.         }
  951.         else
  952.         {
  953.             sbHShow     = false;
  954.             sbHHeight   = 0;
  955.             sbHPosition = 0;
  956.         }
  957.  
  958.         drawTree();
  959.  
  960.         if (sbVShow)
  961.         {
  962.             verticalScrollBar.reshape(d.width-sbVWidth,0,sbVWidth,d.height-sbHHeight);
  963.             verticalScrollBar.setValues(sbVPosition, inRectCount, 0, viewCount-(isSun1_1?0:inRectCount));
  964.             verticalScrollBar.setPageIncrement(inRectCount-1);
  965.             verticalScrollBar.show();
  966.         }
  967.         else
  968.         {
  969.             verticalScrollBar.hide();
  970.         }
  971.  
  972.         if (sbHShow)
  973.         {
  974.             horizontalScrollBar.reshape(0,d.height-sbHHeight,d.width-sbVWidth,sbHHeight);
  975.             horizontalScrollBar.setValues(sbHPosition, d.width-sbVWidth, 0, sbHSize-(isSun1_1?0:(d.width-sbVWidth)));
  976.             horizontalScrollBar.setPageIncrement(d.width-sbVWidth);
  977.             horizontalScrollBar.setLineIncrement(sbHLineIncrement);
  978.             horizontalScrollBar.show();
  979.         }
  980.         else
  981.         {
  982.             horizontalScrollBar.hide();
  983.         }
  984.     }
  985.  
  986.     /**
  987.      * Draws the TreeView into an offscreen image. This is used for cleaner refresh.
  988.      */
  989.     public void drawTree()
  990.     {
  991.         Dimension d = size();
  992.  
  993.         if(needResetVector)
  994.             resetVector();
  995.  
  996.         if ((d.width != viewWidth) || (d.height != viewHeight) || (g1 == null) || (sbHSize != newWidth))
  997.         {
  998.             // size has changed, must resize image
  999.             im1 = createImage(Math.max(sbHSize=newWidth, d.width), d.height);
  1000.             
  1001.             if (g1 != null)
  1002.             {
  1003.                 g1.dispose();
  1004.             }
  1005.             
  1006.             g1         = im1.getGraphics();
  1007.             viewWidth  = d.width;
  1008.             viewHeight = d.height;
  1009.         }
  1010.  
  1011.         Font f = getFont();  //unix version might not provide a default font
  1012.  
  1013.         //Make certain there is a font
  1014.         if (f == null)
  1015.         {
  1016.             f = new Font("Serif", Font.PLAIN, 13);
  1017.             g1.setFont(f);
  1018.             setFont(f);
  1019.         }
  1020.  
  1021.         //Make certain the graphics object has a font (Mac doesn't seem to)
  1022.         if (g1.getFont() == null)
  1023.             g1.setFont(f);
  1024.  
  1025.         fm = g1.getFontMetrics();
  1026.         g1.setColor(getBackground());
  1027.         g1.fillRect(0, 0, im1.getWidth(this), d.height);// clear image
  1028.  
  1029.         //do drawing for each visible node
  1030.         int lastOne = sbVPosition + viewHeight / cellSize + 1;
  1031.  
  1032.         if (lastOne > viewCount)
  1033.         {
  1034.             lastOne = viewCount;
  1035.         }
  1036.  
  1037.         TreeNode outerNode = null;
  1038.         
  1039.         if (!v.isEmpty())
  1040.             outerNode = (TreeNode)v.elementAt(sbVPosition);
  1041.             
  1042.         for (int i = sbVPosition; i < lastOne; i++)
  1043.         {
  1044.             TreeNode node = (TreeNode)v.elementAt(i);
  1045.             int x         = cellSize*(node.depth + 1);
  1046.             int y         = (i - sbVPosition) * cellSize;
  1047.  
  1048.             // draw lines
  1049.             g1.setColor(getForeground());
  1050.  
  1051.             // draw vertical sibling line
  1052.             if (node.sibling != null && node.isASiblingVisible())
  1053.             {
  1054.                 int k = v.indexOf(node.sibling) - i;
  1055.  
  1056.                 if (k > lastOne)
  1057.                 {
  1058.                     k = lastOne;
  1059.                 }
  1060.  
  1061.                 drawDotLine(x - cellSize/2, y + cellSize/2,
  1062.                             x - cellSize/2, y + cellSize/2 +  k*cellSize);
  1063.  
  1064.             }
  1065.             
  1066.             // if sibling is above page, draw up to top of page for this level
  1067.             for (int m = 0; m < i; m++)
  1068.             {
  1069.                 TreeNode sib = (TreeNode)v.elementAt(m);
  1070.  
  1071.                 if ((sib.sibling == node) && (m < sbVPosition))
  1072.                 {
  1073.                     drawDotLine (x - cellSize / 2, 0,
  1074.                                  x - cellSize / 2, y + cellSize / 2);
  1075.                 }
  1076.             }
  1077.  
  1078.             // draw vertical child lines
  1079.             if (node.isExpanded() && node.isAChildVisible())
  1080.             {
  1081.                 drawDotLine(x + cellSize / 2, y + cellSize - 2 ,
  1082.                             x + cellSize / 2, y + cellSize + cellSize / 2);
  1083.             }
  1084.             
  1085.             // draw node horizontal line
  1086.             g1.setColor(getForeground());
  1087.             drawDotLine(x - cellSize / 2, y + cellSize / 2,
  1088.                         x + cellSize / 2, y + cellSize / 2);
  1089.  
  1090.             // draw toggle box
  1091.             drawNodeToggle(node, x, y);
  1092.  
  1093.             // draw node image
  1094.             Image nodeImage = node.getImage();
  1095.  
  1096.             if (nodeImage != null)
  1097.             {
  1098.                 g1.drawImage(nodeImage, x + imageInset, y, this);
  1099.             }
  1100.  
  1101.             // draw node text
  1102.             if (node.text != null)
  1103.             {
  1104.                 drawNodeText(node, y, node == selectedNode, false);
  1105.             }
  1106.  
  1107.             if(outerNode.depth > node.depth)
  1108.                 outerNode = node;
  1109.         }
  1110.  
  1111.         // draw outer vertical lines
  1112.         if (outerNode != null)
  1113.         {
  1114.             while((outerNode = outerNode.parent) != null)
  1115.             {
  1116.                 if (outerNode.sibling != null && outerNode.isASiblingVisible())
  1117.                     drawDotLine (cellSize * (outerNode.depth + 1) - cellSize / 2, 0,
  1118.                                  cellSize * (outerNode.depth + 1) - cellSize / 2, d.height);
  1119.             }
  1120.         }
  1121.         
  1122.         needResetVector = true;
  1123.     }
  1124.  
  1125.     /**
  1126.      * Used to draw the toggle box of an expandable node.
  1127.      * Override to change the look of the toggle box.
  1128.      */
  1129.     protected void drawNodeToggle(TreeNode node, int x, int y)
  1130.     {
  1131.         if(node.isExpandable() && node.isAChildVisible())
  1132.         {
  1133.             g1.setColor(getBackground());
  1134.             g1.fillRect(cellSize * (node.depth) + cellSize / 4, y + clickSize / 2, clickSize, clickSize);
  1135.             g1.setColor(getForeground());
  1136.             g1.drawRect(cellSize * (node.depth) + cellSize / 4, y + clickSize / 2, clickSize, clickSize);
  1137.             
  1138.             // cross hair
  1139.             g1.drawLine(cellSize * (node.depth) + cellSize / 4 + 2,             y + cellSize / 2,
  1140.                         cellSize * (node.depth) + cellSize / 4 + clickSize - 2, y + cellSize / 2);
  1141.  
  1142.             if(!(node.isExpanded()))
  1143.             {
  1144.                 g1.drawLine(cellSize * (node.depth) + cellSize / 2, y + clickSize / 2 + 2,
  1145.                             cellSize * (node.depth) + cellSize / 2, y + clickSize / 2 + clickSize - 2);
  1146.             }
  1147.         }
  1148.     }
  1149.  
  1150.     /**
  1151.      * Returns the recommended dimensions to properly display this component.
  1152.      * This is a standard Java AWT method which gets called to determine
  1153.      * the recommended size of this component.
  1154.      *
  1155.      * @see #getMinimumSize
  1156.      */
  1157.     public synchronized Dimension getPreferredSize()
  1158.     {
  1159.         Dimension p = size();
  1160.         Dimension m = getMinimumSize();
  1161.         return new Dimension(Math.max(p.width, m.width), Math.max(p.height, m.height));
  1162.     }
  1163.  
  1164.     /**
  1165.      * @deprecated
  1166.      * @see #getPreferredSize
  1167.      */
  1168.     public synchronized Dimension preferredSize()
  1169.     {
  1170.         return getPreferredSize();
  1171.     }
  1172.  
  1173.     /**
  1174.      * Returns the minimum dimensions to properly display this component.
  1175.      * This is a standard Java AWT method which gets called to determine
  1176.      * the minimum size of this component.
  1177.      *
  1178.      * @see #getPreferredSize
  1179.      */
  1180.     public synchronized Dimension getMinimumSize()
  1181.     {
  1182.         return new Dimension(20, 40);
  1183.     }
  1184.  
  1185.     /**
  1186.      * @deprecated
  1187.      * @see #getMinimumSize
  1188.      */
  1189.     public synchronized Dimension minimumSize()
  1190.     {
  1191.         return getMinimumSize();
  1192.     }
  1193.  
  1194.     /**
  1195.      * Takes no action.
  1196.      * This is a standard Java AWT method which gets called to specify
  1197.      * which layout manager should be used to layout the components in
  1198.      * standard containers.
  1199.      *
  1200.      * Since layout managers CANNOT BE USED with this container the standard
  1201.      * setLayout has been OVERRIDDEN for this container and does nothing.
  1202.      *
  1203.      * @param lm the layout manager to use to layout this container's components
  1204.      * (IGNORED)
  1205.      * @see java.awt.Container#getLayout
  1206.      **/
  1207.     public void setLayout(LayoutManager lm)
  1208.     {
  1209.     }
  1210.  
  1211.     public boolean isFocusTraversable()
  1212.     {
  1213.         return true;
  1214.     }
  1215.  
  1216.     /**
  1217.      * Tells this component that it has been added to a container.
  1218.      * This is a standard Java AWT method which gets called by the AWT when
  1219.      * this component is added to a container. Typically, it is used to
  1220.      * create this component's peer.
  1221.      *
  1222.      * It has been overridden here to hook-up event listeners.
  1223.      *
  1224.      * @see #removeNotify
  1225.      */
  1226.     public synchronized void addNotify()
  1227.     {
  1228.         super.addNotify();
  1229.         
  1230.         try
  1231.         {
  1232.             errors = ResourceBundle.getBundle("symantec.itools.resources.ErrorsBundle");
  1233.         }
  1234.         catch(Throwable ex)
  1235.         {
  1236.             errors = new symantec.itools.resources.ErrorsBundle();
  1237.         }
  1238.  
  1239.         //Hook up listeners
  1240.         if (mouse == null)
  1241.         {
  1242.             mouse = new Mouse();
  1243.             addMouseListener(mouse);
  1244.         }
  1245.         if (key == null)
  1246.         {
  1247.             key = new Key();
  1248.             addKeyListener(key);
  1249.         }
  1250.         if (adjustment == null)
  1251.         {
  1252.             adjustment = new Adjustment();
  1253.             verticalScrollBar.addAdjustmentListener(adjustment);
  1254.             horizontalScrollBar.addAdjustmentListener(adjustment);
  1255.         }
  1256.         if (focus == null)
  1257.         {
  1258.             focus = new Focus();
  1259.             addFocusListener(focus);
  1260.         }
  1261.  
  1262.     }
  1263.  
  1264.     /**
  1265.      * Tells this component that it is being removed from a container.
  1266.      * This is a standard Java AWT method which gets called by the AWT when
  1267.      * this component is removed from a container. Typically, it is used to
  1268.      * destroy the peers of this component and all its subcomponents.
  1269.      *
  1270.      * It has been overridden here to unhook event listeners.
  1271.      *
  1272.      * @see #addNotify
  1273.      */
  1274.     public synchronized void removeNotify()
  1275.     {
  1276.         //Unhook listeners
  1277.         if (mouse != null)
  1278.         {
  1279.             removeMouseListener(mouse);
  1280.             mouse = null;
  1281.         }
  1282.         if (key != null)
  1283.         {
  1284.             removeKeyListener(key);
  1285.             key = null;
  1286.         }
  1287.         if (adjustment != null)
  1288.         {
  1289.             verticalScrollBar.removeAdjustmentListener(adjustment);
  1290.             horizontalScrollBar.removeAdjustmentListener(adjustment);
  1291.             adjustment = null;
  1292.         }
  1293.         if (focus != null)
  1294.         {
  1295.             removeFocusListener(focus);
  1296.             focus = null;
  1297.         }
  1298.         super.removeNotify();
  1299.     }
  1300.  
  1301.     /**
  1302.      * Triggers redrawing the entire image, even if the size of the component
  1303.      * has not changed.
  1304.      */
  1305.     public void triggerRedraw()
  1306.     {
  1307.         redrawTriggered = true;
  1308.         repaint();
  1309.     }
  1310.  
  1311.     // -----------------------------------------
  1312.     // --------- event related methods ---------
  1313.     // -----------------------------------------
  1314.  
  1315.     /**
  1316.      * Adds the specified action listener to receive action events
  1317.      * from this button.
  1318.      * @param l the action listener
  1319.      */
  1320.     public synchronized void addActionListener(ActionListener l)
  1321.     {
  1322.         actionListener = AWTEventMulticaster.add(actionListener, l);
  1323.     }
  1324.  
  1325.     /**
  1326.      * Removes the specified action listener so it no longer receives
  1327.      * action events from this button.
  1328.      * @param l the action listener
  1329.      */
  1330.     public synchronized void removeActionListener(ActionListener l)
  1331.     {
  1332.         actionListener = AWTEventMulticaster.remove(actionListener, l);
  1333.     }
  1334.  
  1335.     /**
  1336.      * Add a listener to recieve item events when the state of
  1337.      * an item changes.
  1338.      * <p>
  1339.      * This is a standard method of the ItemSelectable interface.
  1340.      * @param l the listener to recieve events
  1341.      * @see ItemEvent
  1342.      */
  1343.     public synchronized void addItemListener(ItemListener l)
  1344.     {
  1345.         itemListener = AWTEventMulticaster.add(itemListener, l);
  1346.     }
  1347.  
  1348.     /**
  1349.      * Removes an item listener.
  1350.      * <p>
  1351.      * This is a standard method of the ItemSelectable interface.
  1352.      * @param l the listener being removed
  1353.      * @see ItemEvent
  1354.      */
  1355.     public synchronized void removeItemListener(ItemListener l)
  1356.     {
  1357.         itemListener = AWTEventMulticaster.remove(itemListener, l);
  1358.     }
  1359.  
  1360.     class Adjustment implements AdjustmentListener, java.io.Serializable
  1361.     {
  1362.         public void adjustmentValueChanged(AdjustmentEvent event)
  1363.         {
  1364.             handleAdjustmentEvent(event);
  1365.         }
  1366.     }
  1367.  
  1368.     class Mouse extends MouseAdapter implements java.io.Serializable
  1369.     {
  1370.         /**
  1371.          * Processes MOUSE_DOWN events.
  1372.          * This is a standard Java AWT method which gets called by the AWT
  1373.          * method handleEvent() in response to receiving a MOUSE_DOWN
  1374.          * event. These events occur when the mouse button is pressed while
  1375.          * inside this component.
  1376.          *
  1377.          * @param event the event
  1378.          * @param x the component-relative horizontal coordinate of the mouse
  1379.          * @param y the component-relative vertical coordinate of the mouse
  1380.          *
  1381.          * @return true if the event was handled
  1382.          *
  1383.          * @see java.awt.Component#mouseUp
  1384.          */
  1385.         public void mousePressed(MouseEvent event)
  1386.         {
  1387.             handleMousePressed(event);
  1388.         }
  1389.  
  1390.         public void mouseReleased(MouseEvent event)
  1391.         {
  1392.             handleMouseReleased(event);
  1393.         }
  1394.     }
  1395.  
  1396.     class Key extends KeyAdapter implements java.io.Serializable
  1397.     {
  1398.         /**
  1399.          * Processes KEY_PRESS and KEY_ACTION events.
  1400.          * This is a standard Java AWT method which gets called by the AWT
  1401.          * method handleEvent() in response to receiving a KEY_PRESS or
  1402.          * KEY_ACTION event. These events occur when this component has the focus
  1403.          * and the user presses a "normal" or an "action" (F1, page up, etc) key.
  1404.          *
  1405.          * @param event the Event
  1406.          * @param key the key that was pressed
  1407.          * @return true if the event was handled
  1408.          * @see java.awt.Component#keyUp
  1409.          * @see #handleEvent
  1410.          */
  1411.         public void keyPressed(KeyEvent event)
  1412.         {
  1413.             handleKeyPressed(event);
  1414.         }
  1415.     }
  1416.  
  1417.     class Focus extends FocusAdapter implements java.io.Serializable
  1418.     {
  1419.         public void focusGained(FocusEvent event)
  1420.         {
  1421.             handleFocusGained(event);
  1422.         }
  1423.  
  1424.         public void focusLost(FocusEvent event)
  1425.         {
  1426.             handleFocusLost(event);
  1427.         }
  1428.     }
  1429.  
  1430.     /**
  1431.      * Handles mouse pressed events.
  1432.      * This function will get called when the component recives a mouse pressed event.
  1433.      * Override to change the way mouse pressed is handled.
  1434.      * @param event the MouseEvent
  1435.      * @see #handleMouseReleased
  1436.      */
  1437.     protected void handleMousePressed(MouseEvent event)
  1438.     {
  1439.         requestFocus();
  1440.  
  1441.         int x = event.getX();
  1442.         int y = event.getY();
  1443.  
  1444.         int index = (y / cellSize) + sbVPosition;
  1445.  
  1446.         //If clicked below the last node
  1447.         if (index > viewCount-1)
  1448.             return;
  1449.  
  1450.         TreeNode oldNode = selectedNode;
  1451.  
  1452.         TreeNode newNode = (TreeNode)v.elementAt(index);
  1453.  
  1454.         int newDepth = newNode.getDepth();
  1455.  
  1456.         // check for toggle box click
  1457.         // todo: make it a bit bigger
  1458.         Rectangle toggleBox = new Rectangle(cellSize*newDepth + cellSize/4,
  1459.                                             (index-sbVPosition)*cellSize + clickSize/2,
  1460.                                             clickSize, clickSize);
  1461.  
  1462.         if (toggleBox.inside(x,y))
  1463.         {
  1464.             newNode.toggle();
  1465.             resetVector();
  1466.             if(!newNode.isExpanded())
  1467.             {
  1468.                 if (!v.contains(selectedNode))
  1469.                     setSelectedNode(newNode);
  1470.             }
  1471.             triggerRedraw();
  1472.             invalidate();
  1473.             sendActionEvent();
  1474.  
  1475.             if(itemListener != null)
  1476.             {
  1477.                 itemListener.itemStateChanged(new ItemEvent(this, NODE_TOGGLED, newNode, newNode.isExpanded ? NODE_EXPANDED : NODE_COLLAPSED));
  1478.             }
  1479.         }
  1480.         else
  1481.         {
  1482.             setSelectedNode(newNode);
  1483.  
  1484.             // check for double click
  1485.             long currentTime = event.getWhen();
  1486.  
  1487.             if ((newNode==oldNode) && ((event.getWhen() - timeMouseDown)<doubleClickResolution))
  1488.             {
  1489.                 newNode.toggle();
  1490.                 resetVector();
  1491.                 triggerRedraw();
  1492.                 invalidate();
  1493.                 sendActionEvent();
  1494.  
  1495.                 if(itemListener != null)
  1496.                 {
  1497.                     itemListener.itemStateChanged(new ItemEvent(this, NODE_TOGGLED, newNode, newNode.isExpanded ? NODE_EXPANDED : NODE_COLLAPSED));
  1498.                 }
  1499.  
  1500.                 return;
  1501.             }
  1502.             else
  1503.             {
  1504.                 //single click action could be added here
  1505.                 timeMouseDown = event.getWhen();
  1506.             }
  1507.  
  1508.         }
  1509.     }
  1510.  
  1511.     /**
  1512.      * Handles mouse released events.
  1513.      * This function will get called when the component recives a mouse released event.
  1514.      * Override to change the way mouse released is handled.
  1515.      * @param event the MouseEvent
  1516.      * @see #handleMousePressed
  1517.      */
  1518.     protected void handleMouseReleased(MouseEvent event)
  1519.     {
  1520.     }
  1521.  
  1522.     /**
  1523.      * Handles adjustment events.
  1524.      * This function will get called when the component recives a adjustment event.
  1525.      * Override to change the way adjustment is handled.
  1526.      * @param event the AdjustmentEvent
  1527.      */
  1528.     protected void handleAdjustmentEvent(AdjustmentEvent event)
  1529.     {
  1530.         if (event.getAdjustable() == verticalScrollBar)
  1531.         {
  1532.             if (sbVPosition != verticalScrollBar.getValue())
  1533.             {
  1534.                 sbVPosition = verticalScrollBar.getValue();
  1535.                 triggerRedraw();
  1536.             }
  1537.         }
  1538.         else
  1539.         if (event.getAdjustable() == horizontalScrollBar)
  1540.         {
  1541.             if (sbHPosition != horizontalScrollBar.getValue())
  1542.             {
  1543.                 sbHPosition = horizontalScrollBar.getValue();
  1544.                 //repaint();
  1545.                 triggerRedraw();
  1546.             }
  1547.         }
  1548.     }
  1549.  
  1550.     /**
  1551.      * Handles key pressed events.
  1552.      * This function will get called when the component recives a key pressed event.
  1553.      * Override to change the way key pressed is handled.
  1554.      * @param event the KeyEvent
  1555.      */
  1556.     protected void handleKeyPressed(KeyEvent event)
  1557.     {
  1558.         int index = v.indexOf(selectedNode);
  1559.  
  1560.         switch (event.getKeyCode())
  1561.         {
  1562.             case KeyEvent.VK_ENTER:    //enter key
  1563.             case 13:
  1564.                 sendActionEvent();
  1565.                 requestFocus();
  1566.                 break;
  1567.             case KeyEvent.VK_LEFT:    //left arrow
  1568.                 if(event.isControlDown())
  1569.                 {
  1570.                     if(sbHPosition > 0)
  1571.                     {
  1572.                         horizontalScrollBar.setValue(Math.max(sbHPosition-=sbHLineIncrement,0));
  1573.                         repaint();
  1574.                     }
  1575.                     break;
  1576.                 }
  1577.                 else
  1578.                 if (selectedNode.isExpanded())
  1579.                 {
  1580.                     selectedNode.toggle();
  1581.  
  1582.                     if(itemListener != null)
  1583.                     {
  1584.                         itemListener.itemStateChanged(new ItemEvent(this, NODE_TOGGLED, selectedNode, selectedNode.isExpanded ? NODE_EXPANDED : NODE_COLLAPSED));
  1585.                         triggerRedraw();
  1586.                     }
  1587.  
  1588.                     break;
  1589.                 }
  1590.  
  1591.                 // else drop through to "UP" with no "break;"
  1592.             case KeyEvent.VK_UP:
  1593.                 if (index > 0)
  1594.                 {
  1595.                     index--;
  1596.                     setSelectedNode((TreeNode)v.elementAt(index));
  1597.                     requestFocus();
  1598.                 }
  1599.                 break;
  1600.             case KeyEvent.VK_RIGHT:
  1601.                 if(event.isControlDown())
  1602.                 {
  1603.                     int max = horizontalScrollBar.getMaximum()-(isSun1_1?size().width-sbVWidth:0);
  1604.                     if(sbHShow && sbHPosition < max)
  1605.                     {
  1606.                         horizontalScrollBar.setValue(Math.min(sbHPosition+=sbHLineIncrement, max));
  1607.                         repaint();
  1608.                     }
  1609.                     break;
  1610.                 }
  1611.                 else
  1612.                 if (selectedNode.isExpandable() && (!selectedNode.isExpanded()))
  1613.                 {
  1614.                     selectedNode.toggle();
  1615.                     sendActionEvent();
  1616.  
  1617.                     if(itemListener != null)
  1618.                     {
  1619.                         itemListener.itemStateChanged(new ItemEvent(this, NODE_TOGGLED, selectedNode, selectedNode.isExpanded ? NODE_EXPANDED : NODE_COLLAPSED));
  1620.                         triggerRedraw();
  1621.                     }
  1622.  
  1623.                     break;
  1624.                 }
  1625.  
  1626.                 if (!selectedNode.isExpandable())
  1627.                 {
  1628.                     break;
  1629.                 }
  1630.                 // else drop thru' to DOWN
  1631.             case KeyEvent.VK_DOWN:
  1632.                 if (index < viewCount-1)
  1633.                 {
  1634.                     index++;
  1635.                     setSelectedNode((TreeNode)v.elementAt(index));
  1636.                     requestFocus();
  1637.                 }
  1638.                 break;
  1639.         }
  1640.     }
  1641.  
  1642.     /**
  1643.      * Handles focus gained events.
  1644.      * This function will get called when the component recives a focus gained event.
  1645.      * Override to change the way focus gained is handled.
  1646.      * @param event the FocusEvent
  1647.      * @see #handleFocusLost
  1648.      */
  1649.     protected void handleFocusGained(FocusEvent event)
  1650.     {
  1651.         hasFocus = true;
  1652.         if (selectedNode != null && v != null)
  1653.             drawNodeText(selectedNode, (v.indexOf(selectedNode) - sbVPosition)*cellSize, true, false);
  1654.     }
  1655.  
  1656.     /**
  1657.      * Handles focus lost events.
  1658.      * This function will get called when the component recives a focus lost event.
  1659.      * Override to change the way focus lost is handled.
  1660.      * @param event the FocusEvent
  1661.      * @see #handleFocusGained
  1662.      */
  1663.     protected void handleFocusLost(FocusEvent event)
  1664.     {
  1665.         hasFocus = false;
  1666.         if (selectedNode != null && v != null)
  1667.             drawNodeText(selectedNode, (v.indexOf(selectedNode) - sbVPosition)*cellSize, true, false);
  1668.     }
  1669.  
  1670.     protected void drawNodeText(TreeNode node, int yPosition, boolean eraseBackground, boolean eraseLines)
  1671.     {
  1672.         if (node == null)
  1673.             return;
  1674.  
  1675.         Color fg, bg;
  1676.         int depth=node.depth;
  1677.         Image nodeImage = node.getImage();
  1678.         int textOffset = ((depth + 1) * (cellSize)) + cellSize + textInset - (nodeImage==null ? 12:0);
  1679.  
  1680.         if (node == selectedNode && hasFocus)
  1681.         {
  1682.             //??RKM?? Temp until these return some good values
  1683.             if (symantec.itools.lang.OS.isMacintosh())
  1684.                 fg = Color.white;
  1685.             else
  1686.                 fg = SystemColor.textHighlightText;
  1687.  
  1688.             if (symantec.itools.lang.OS.isMacintosh())
  1689.                 bg = new Color(0,0,128);
  1690.             else
  1691.                 bg = SystemColor.textHighlight;
  1692.         }
  1693.         else
  1694.         {
  1695.             fg = getForeground();
  1696.             bg = getBackground();
  1697.         }
  1698.  
  1699.         if (eraseBackground)
  1700.         {
  1701.             g1.setColor(bg);
  1702.             g1.fillRect(textOffset-1, yPosition+1, fm.stringWidth(node.text)+4, cellSize-1);
  1703.         }
  1704.  
  1705.         if (node == selectedNode)
  1706.         {
  1707.             g1.setColor(getForeground());
  1708.             g1.drawRect(textOffset-1, yPosition+1, fm.stringWidth(node.text)+3, cellSize-2);
  1709.             repaint(Math.max(0,textOffset-1-sbHPosition), yPosition+1, fm.stringWidth(node.text)+4, cellSize-1);
  1710.         }
  1711.         
  1712.         if (eraseLines)
  1713.         {
  1714.             g1.setColor(getBackground());
  1715.             g1.drawRect(textOffset-1, yPosition+1, fm.stringWidth(node.text)+3, cellSize-2);
  1716.             repaint(Math.max(0,textOffset-1-sbHPosition), yPosition+1, fm.stringWidth(node.text)+4, cellSize-1);
  1717.         }
  1718.         
  1719.         g1.setColor(fg);
  1720.         g1.drawString(node.text, textOffset, yPosition + cellSize - textBaseLine);
  1721.     }
  1722.  
  1723.     /**
  1724.      * Sends an action performed event to any action listeners, as needed.
  1725.      */
  1726.     protected void sendActionEvent()
  1727.     {
  1728.         if (actionListener != null)
  1729.             actionListener.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, new String(selectedNode.getText())));
  1730.     }
  1731.  
  1732.     protected int compWidth(Graphics gg)
  1733.     {
  1734.         int size = 0;
  1735.         int textOffset;
  1736.         TreeNode node;
  1737.  
  1738.            Font f = getFont();  //unix version might not provide a default font
  1739.         //Make certain there is a font
  1740.         if (f == null)
  1741.         {
  1742.             f = new Font("Serif", Font.PLAIN, 13);
  1743.             if(gg != null)
  1744.                    gg.setFont(f);
  1745.             setFont(f);
  1746.         }
  1747.  
  1748.         if(gg == null)
  1749.             fm = null;
  1750.         else
  1751.             fm = gg.getFontMetrics();
  1752.  
  1753.         if(fm == null)
  1754.             fm = getFontMetrics(f);
  1755.  
  1756.         if(fm == null || v == null)
  1757.             size = 100;
  1758.         else
  1759.         {
  1760.             for (int i=0; i < v.size(); i++)
  1761.             {
  1762.                 node = (TreeNode)v.elementAt(i);
  1763.                    textOffset = ((node.depth + 1) * (cellSize)) + cellSize + textInset - (node.getImage()==null ? 12:0);
  1764.                    if (size < (textOffset+fm.stringWidth(node.text)+6))
  1765.                     size = textOffset+fm.stringWidth(node.text)+6;
  1766.             }
  1767.         }
  1768.  
  1769.         return size;
  1770.     }
  1771.  
  1772.     protected void drawDotLine(int x0, int y0, int x1, int y1)
  1773.     {
  1774.        if (y0==y1)
  1775.        {
  1776.             for (int i = x0; i<x1; i+=2)
  1777.             {
  1778.                g1.drawLine(i,y0, i, y1);
  1779.             }
  1780.         }
  1781.         else
  1782.         {
  1783.             for (int i = y0; i<y1; i+=2)
  1784.             {
  1785.                 g1.drawLine(x0, i, x1, i);
  1786.             }
  1787.         }
  1788.     }
  1789.  
  1790.     /**
  1791.      * Handles selecting the given node.
  1792.      * @param node the node to select
  1793.      */
  1794.     protected void changeSelection(TreeNode node)
  1795.     {
  1796.         setSelectedNode(node);
  1797.     }
  1798.     
  1799.     /**
  1800.      * Handles selecting the given node.
  1801.      * @param node the node to select
  1802.      */
  1803.     public void setSelectedNode(TreeNode node)
  1804.     {
  1805.         if(node == null)
  1806.         {
  1807.             if(selectedNode != null)
  1808.             {
  1809.                 drawNodeText(selectedNode, (v.indexOf(selectedNode) - sbVPosition) * cellSize, true, true);
  1810.             
  1811.                 if(itemListener != null)
  1812.                 {
  1813.                     itemListener.itemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED, selectedNode, ItemEvent.DESELECTED));
  1814.                 }
  1815.             
  1816.                 selectedNode = null;
  1817.             }
  1818.             
  1819.             return;
  1820.         }
  1821.         
  1822.         if (node == selectedNode)
  1823.             return;
  1824.  
  1825.         TreeNode oldNode = selectedNode;
  1826.         selectedNode = node;
  1827.                 
  1828.         if(oldNode != null)
  1829.         {
  1830.             drawNodeText(oldNode, (v.indexOf(oldNode) - sbVPosition)*cellSize, true, false);
  1831.         }
  1832.         
  1833.         drawNodeText(node, (v.indexOf(node) - sbVPosition)*cellSize, true, false);
  1834.         
  1835.         // send select event
  1836.  
  1837.         int index = v.indexOf(selectedNode);
  1838.  
  1839.         if (itemListener != null)
  1840.         {
  1841.             if(oldNode != null)
  1842.             {   
  1843.                 itemListener.itemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED, oldNode, ItemEvent.DESELECTED));
  1844.             }
  1845.             
  1846.             itemListener.itemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED, selectedNode, ItemEvent.SELECTED));
  1847.         }
  1848.  
  1849.         if (index < sbVPosition)
  1850.         { //scroll up
  1851.             sbVPosition--;
  1852.             verticalScrollBar.setValue(sbVPosition);
  1853.             triggerRedraw();
  1854.             return;
  1855.         }
  1856.  
  1857.         if (index >= sbVPosition + (viewHeight-cellSize/2)/cellSize)
  1858.         {
  1859.             sbVPosition++;
  1860.             verticalScrollBar.setValue(sbVPosition);
  1861.             triggerRedraw();
  1862.             return;
  1863.         }
  1864.  
  1865.         repaint();
  1866.     }
  1867.  
  1868.     /**
  1869.      * Generates a new tree node.
  1870.      * Override if you want to return your own instantiation of a TreeNode subclas.
  1871.      * @param text the node text
  1872.      * @param treeView a reference to the parent TreeView (usually "this").
  1873.      * @return a new TreeNode
  1874.      */
  1875.     protected TreeNode newTreeNode(String text, TreeView treeView)
  1876.     {
  1877.         return new TreeNode(text, treeView);
  1878.     }
  1879.  
  1880.     protected void parseTreeStructure(String tempStructure[]) throws InvalidTreeNodeException
  1881.     {
  1882.         for(int i = 0; i < tempStructure.length; i++)
  1883.         {
  1884.             String entry = tempStructure[i];
  1885.             int indentLevel = findLastPreSpace(entry)/*+1*/;
  1886.  
  1887.             if (indentLevel == -1)
  1888.                 throw new InvalidTreeNodeException("parseTreeStructure: " + errors.getString("EmptyStrings"));
  1889.  
  1890.             TreeNode node = newTreeNode(entry.trim(), this);
  1891.             node.setDepth(indentLevel);
  1892.  
  1893.             if (rootNode == null)
  1894.             {
  1895.                 if (indentLevel != 0)
  1896.                     throw new InvalidTreeNodeException("parseTreeStructure: " + errors.getString("NoRootLevelNode"));
  1897.  
  1898.                 append(node);
  1899.             }
  1900.             else
  1901.             {
  1902.                 TreeNode currentNode = rootNode;
  1903.                 while(currentNode.sibling != null)
  1904.                     currentNode = currentNode.sibling;
  1905.  
  1906.                 for(int j = 1; j < indentLevel; j++)
  1907.                 {
  1908.                     int numberOfChildren = currentNode.numberOfChildren;
  1909.                     TreeNode tempNode = null;
  1910.  
  1911.                     if (numberOfChildren > 0)
  1912.                     {
  1913.                         tempNode = currentNode.child;
  1914.  
  1915.                         while(tempNode.sibling != null)
  1916.                             tempNode = tempNode.sibling;
  1917.                     }
  1918.  
  1919.                     if (tempNode != null)
  1920.                         currentNode = tempNode;
  1921.                     else
  1922.                         break;
  1923.                 }
  1924.  
  1925.                 int diff = indentLevel - currentNode.getDepth();
  1926.  
  1927.                 if (diff > 1)
  1928.                     throw new InvalidTreeNodeException("parseTreeStructure: " + errors.getString("NoParent") + entry.trim());
  1929.  
  1930.                 if (diff == 1)
  1931.                     insert(node, currentNode, CHILD);
  1932.                 else
  1933.                     insert(node, currentNode, NEXT);
  1934.             }
  1935.         }
  1936.     }
  1937.  
  1938.     protected void recount()
  1939.     {
  1940.         count = 0;
  1941.         e = new Vector();
  1942.  
  1943.         if (rootNode != null)
  1944.         {
  1945.             rootNode.depth=0;
  1946.             traverse(rootNode);
  1947.         }
  1948.     }
  1949.  
  1950.     protected void traverse(TreeNode node)
  1951.     {
  1952.         count++;
  1953.         
  1954.         if(!node.isHidden())
  1955.         {
  1956.             e.addElement(node);
  1957.             
  1958.             if (node.child != null)
  1959.             {
  1960.                 node.child.depth = node.depth+1;
  1961.                 traverse(node.child);
  1962.             }        
  1963.         }
  1964.         
  1965.         if (node.sibling != null)
  1966.         {
  1967.             node.sibling.depth = node.depth;
  1968.             traverse(node.sibling);
  1969.         }
  1970.     }
  1971.  
  1972.     protected void resetVector()
  1973.     {
  1974.         // Traverses tree to put nodes into vector v
  1975.         // for internal processing. Depths of nodes are set,
  1976.         // and viewCount and viewWidest is set.
  1977.         v = new Vector(count);
  1978.         viewWidest = 30;
  1979.  
  1980.         if (count < 1)
  1981.         {
  1982.             viewCount = 0;
  1983.             return;
  1984.         }
  1985.  
  1986.         rootNode.depth = 0;
  1987.         vectorize(rootNode, true, true, v);
  1988.         viewCount = v.size();
  1989.  
  1990.         needResetVector = false;
  1991.     }
  1992.  
  1993.     protected void vectorize(TreeNode node, boolean respectExpanded, boolean repectHidden, Vector nodeVector)
  1994.     {
  1995.         if(node == null)
  1996.         {
  1997.             return;
  1998.         }
  1999.         
  2000.         if(!repectHidden || !node.isHidden())
  2001.         {            
  2002.             nodeVector.addElement(node);
  2003.  
  2004.             if((!respectExpanded && node.child != null) || node.isExpanded())
  2005.             {
  2006.                 node.child.depth = node.depth + 1;
  2007.                 vectorize(node.child, respectExpanded, repectHidden, nodeVector);
  2008.             }
  2009.         }
  2010.         
  2011.         if (node.sibling != null)
  2012.         {
  2013.             node.sibling.depth = node.depth;
  2014.             vectorize(node.sibling, respectExpanded, repectHidden, nodeVector);
  2015.         }
  2016.     }
  2017.  
  2018.     protected void debugVector()
  2019.     {
  2020.         int vSize = v.size();
  2021.  
  2022.         for (int i=0; i<count; i++)
  2023.         {
  2024.             TreeNode node = (TreeNode) v.elementAt(i);
  2025.             System.out.println(node.text);
  2026.         }
  2027.     }
  2028.  
  2029.     protected int findLastPreSpace(String s)
  2030.     {
  2031.         if(s != null && s.length() > 0)
  2032.         {
  2033.             int length;
  2034.  
  2035.             length = s.length();
  2036.  
  2037.             if(s.charAt(0) != ' ' && s.charAt(0) != '\t')
  2038.             {
  2039.                 return 0;
  2040.             }
  2041.  
  2042.             for(int i = 1; i < length; i++)
  2043.             {
  2044.                 if(s.charAt(i) != ' ' && s.charAt(i) != '\t')
  2045.                 {
  2046.                     return i;
  2047.                 }
  2048.             }
  2049.         }
  2050.         return -1;
  2051.     }
  2052.  
  2053.  
  2054.     int        sbVPosition                = 0;    // hold value of vertical scrollbar
  2055.     int        sbVWidth;                           // width of vertical scrollbar
  2056.     int        sbHPosition                = 0;    // hold value of horizontal scrollbar
  2057.     int        sbHHeight                = 0;    // height of horizontal scrollbar
  2058.     long    sbVTimer                = -1;    // time of last vert scrollbar event
  2059.     int        cellSize                   = 16;   // size of node image
  2060.     int        clickSize               = 8;    // size of mouse toggle (plus or minus)
  2061.     int        imageInset                = 3;    // left margin of node image
  2062.     int        textInset               = 6;    // left margin for text
  2063.     int        textBaseLine            = 3;    // position of font baseline from bottom of cell
  2064.     int        doubleClickResolution    = 333;    // double-click speed in milliseconds
  2065.  
  2066.     /**
  2067.      * root node of tree
  2068.      */
  2069.     protected TreeNode rootNode;
  2070.     /**
  2071.      * highlighted node
  2072.      */
  2073.     protected TreeNode selectedNode;
  2074.     /**
  2075.      * first node in window
  2076.      */
  2077.     protected TreeNode topVisibleNode;
  2078.     /**
  2079.      * The vertical scrollbar.
  2080.      */
  2081.     protected Scrollbar    verticalScrollBar;
  2082.     /**
  2083.      * show or hide vertical scrollbar
  2084.      */
  2085.     protected boolean sbVShow = false;
  2086.     /**
  2087.      * Number of nodes in the tree.
  2088.      */
  2089.     protected int count = 0;
  2090.     /**
  2091.      * Number of viewable nodes in the tree.
  2092.      * A node is viewable if all of its parents are expanded.
  2093.      */
  2094.     protected int    viewCount = 0;
  2095.     /**
  2096.      * The horizontal scrollbar
  2097.      */
  2098.     protected Scrollbar horizontalScrollBar;
  2099.     /**
  2100.      * size of horizontal scrollbar
  2101.      */
  2102.     protected int sbHSize;
  2103.     /**
  2104.      * for horizontal scrollbar
  2105.      */
  2106.     protected int newWidth = 0;
  2107.     /**
  2108.      * show or hide horizontal scrollbar
  2109.      */
  2110.        protected boolean sbHShow = false;
  2111.        /**
  2112.         * Keeps track of if drawTree needs to call resetVector or not.
  2113.         */
  2114.        protected boolean needResetVector;
  2115.  
  2116.     protected int sbHLineIncrement = 4;
  2117.        /**
  2118.         * pixel size of tree display
  2119.         */
  2120.     protected int viewHeight = 300;
  2121.        /**
  2122.         * pixel size of tree display
  2123.         */
  2124.     protected int viewWidth  = 300;
  2125.        /**
  2126.         * widest item displayable (for horz scroll)
  2127.         */
  2128.     protected int viewWidest = 0 ;
  2129.     /**
  2130.      * The this component's key event listener.
  2131.      */
  2132.     protected Key key = null;
  2133.     /**
  2134.      * The this component's mouse event listener.
  2135.      */
  2136.     protected Mouse mouse = null;
  2137.     /**
  2138.      * The this component's adjustment event listener.
  2139.      */
  2140.     protected Adjustment adjustment = null;
  2141.     /**
  2142.      * The action listener to keep track of listeners for our action event.
  2143.      */
  2144.     protected ActionListener actionListener = null;
  2145.     /**
  2146.      * The action listener to keep track of listeners for our item event.
  2147.      */
  2148.     protected ItemListener itemListener = null;
  2149.     /**
  2150.      * The this component's focus event listener.
  2151.      */
  2152.     protected Focus focus = null;
  2153.     /**
  2154.      * v is vector of viewable nodes
  2155.      */
  2156.     protected Vector v;
  2157.     /**
  2158.      * e is vector of existing nodes
  2159.      */
  2160.     protected Vector e;
  2161.     /**
  2162.      * Flag indicating repaint() shoud redraw the entire image even
  2163.      * if the component size has not changed.
  2164.      */
  2165.     transient protected boolean redrawTriggered = false;
  2166.     transient boolean hasFocus = false;
  2167.        /**
  2168.         * current font metrics
  2169.         */
  2170.     transient protected FontMetrics fm;
  2171.        /**
  2172.         * save time of last mouse down (for double click)
  2173.         */
  2174.     transient long timeMouseDown;
  2175.     /**
  2176.      * Offscreen Image used for buffering the painting process.
  2177.      */
  2178.     transient protected Image im1;
  2179.     /**
  2180.      * Offscreen graphics context used for buffering the painting process.
  2181.      */
  2182.     transient protected Graphics g1 = null;
  2183.     /**
  2184.      * Checks for scrollbars that have different max value.
  2185.      */
  2186.     static protected boolean isSun1_1;
  2187.  
  2188.     transient protected ResourceBundle errors;
  2189.  
  2190.     static
  2191.     {
  2192.         //Calc it once
  2193.         String vendor = System.getProperty("java.vendor");
  2194.         String version = System.getProperty("java.version");
  2195.  
  2196.         isSun1_1 = ((vendor.startsWith("Sun Microsystems Inc.") ||
  2197.                     (vendor.startsWith("Apple"))                ||
  2198.                     (vendor.startsWith("Symantec Corporation")) ||
  2199.                     (vendor.startsWith("Netscape"))) &&
  2200.                      ((version.startsWith("11")) ||
  2201.                     (version.startsWith("1.1"))));
  2202.     }
  2203. }
  2204.  
  2205. class InvalidTreeNodeException extends Exception
  2206. {
  2207.     public InvalidTreeNodeException()
  2208.     {
  2209.         super();
  2210.     }
  2211.  
  2212.     public InvalidTreeNodeException(String message)
  2213.     {
  2214.         super(message);
  2215.     }
  2216. }
  2217.