jford       2004/06/29 20:09:15

  Added:       applications/pam/src/java/org/apache/webapp/admin
                        TreeControlTag.java TreeControlNode.java
                        TreeControl.java
  Log:
  Added tree control menu to PAM browser
  
  Revision  Changes    Path
  1.1                  
jakarta-jetspeed-2/applications/pam/src/java/org/apache/webapp/admin/TreeControlTag.java
  
  Index: TreeControlTag.java
  ===================================================================
  /*
   * Copyright 2001,2004 The Apache Software Foundation.
   * 
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   * 
   *      http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  
  package org.apache.webapp.admin;
  
  
  import java.io.IOException;
  import java.net.URLEncoder;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.jsp.JspException;
  import javax.servlet.jsp.JspWriter;
  import javax.servlet.jsp.PageContext;
  import javax.servlet.jsp.tagext.TagSupport;
  
  
  /**
   * <p>JSP custom tag that renders a tree control represented by the
   * <code>TreeControl</code> and <code>TreeControlNode</code> classes.
   * This tag has the following user-settable attributes:</p>
   * <ul>
   * <li><strong>action</strong> - Hyperlink to which expand/contract actions
   *     should be sent, with a string "<code>${node}</code> marking where
   *     the node name of the affected node should be included.</li>
   * <li><strong>images</strong> - Name of the directory containing the images
   *     for our icons, relative to the page including this tag.  If not
   *     specified, defaults to "images".</li>
   * <li><strong>scope</strong> - Attribute scope in which the <code>tree</code>
   *     attribute is to be found (page, request, session, application).  If
   *     not specified, the attribute is searched for in all scopes.</li>
   * <li><strong>style</strong> - CSS style <code>class</code> to be applied
   *     to be applied to the entire rendered output of the tree control.
   *     If not specified, no style class is applied.</li>
   * <li><strong>styleSelected</strong> - CSS style <code>class</code> to be
   *     applied to the text of any element that is currently selected.  If not
   *     specified, no additional style class is applied.</li>
   * <li><strong>styleUnselected</strong> - CSS style <code>class</code> to be
   *     applied to the text of any element that is not currently selected.
   *     If not specified, no additional style class is applied.</li>
   * <li><strong>tree</strong> - Attribute name under which the
   *     <code>TreeControl</code> bean of the tree we are rendering
   *     is stored, in the scope specified by the <code>scope</code>
   *     attribute.  This attribute is required.</li>
   * </ul>
   *
   * <strong>FIXME</strong> - Internationalize the exception messages!
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2004/06/30 03:09:15 $
   */
  
  public class TreeControlTag extends TagSupport {
  
  
      /**
       * The default directory name for icon images.
       */
      static final String DEFAULT_IMAGES = "images";
  
  
      /**
       * The names of tree state images that we need.
       */
      static final String IMAGE_HANDLE_DOWN_LAST =    "handledownlast.gif";
      static final String IMAGE_HANDLE_DOWN_MIDDLE =  "handledownmiddle.gif";
      static final String IMAGE_HANDLE_RIGHT_LAST =   "handlerightlast.gif";
      static final String IMAGE_HANDLE_RIGHT_MIDDLE = "handlerightmiddle.gif";
      static final String IMAGE_LINE_LAST =           "linelastnode.gif";
      static final String IMAGE_LINE_MIDDLE =         "linemiddlenode.gif";
      static final String IMAGE_LINE_VERTICAL =       "linevertical.gif";
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * The hyperlink to be used for submitting requests to expand and
       * contract tree nodes.  The placeholder "<code>${name}</code>" will
       * be replaced by the <code>name</code> property of the current
       * tree node.
       */
      protected String action = null;
  
      public String getAction() {
          return (this.action);
      }
  
      public void setAction(String action) {
          this.action = action;
      }
  
  
      /**
       * The name of the directory containing the images for our icons,
       * relative to the page including this tag.
       */
      protected String images = DEFAULT_IMAGES;
  
      public String getImages() {
          return (this.images);
      }
  
      public void setImages(String images) {
          this.images = images;
      }
  
  
      /**
       * The name of the scope in which to search for the <code>tree</code>
       * attribute.  Must be "page", "request", "session", or "application"
       * (or <code>null</code> for an ascending-visibility search).
       */
      protected String scope = null;
  
      public String getScope() {
          return (this.scope);
      }
  
      public void setScope(String scope) {
          if (!"page".equals(scope) &&
              !"request".equals(scope) &&
              !"session".equals(scope) &&
              !"application".equals(scope))
              throw new IllegalArgumentException("Invalid scope '" +
                                                 scope + "'");
          this.scope = scope;
      }
  
  
      /**
       * The CSS style <code>class</code> to be applied to the entire tree.
       */
      protected String style = null;
  
      public String getStyle() {
          return (this.style);
      }
  
      public void setStyle(String style) {
          this.style = style;
      }
  
  
      /**
       * The CSS style <code>class</code> to be applied to the text
       * of selected nodes.
       */
      protected String styleSelected = null;
  
      public String getStyleSelected() {
          return (this.styleSelected);
      }
  
      public void setStyleSelected(String styleSelected) {
          this.styleSelected = styleSelected;
      }
  
  
      /**
       * The CSS style <code>class</code> to be applied to the text
       * of unselected nodes.
       */
      protected String styleUnselected = null;
  
      public String getStyleUnselected() {
          return (this.styleUnselected);
      }
  
      public void setStyleUnselected(String styleUnselected) {
          this.styleUnselected = styleUnselected;
      }
  
  
      /**
       * The name of the attribute (in the specified scope) under which our
       * <code>TreeControl</code> instance is stored.
       */
      protected String tree = null;
  
      public String getTree() {
          return (this.tree);
      }
  
      public void setTree(String tree) {
          this.tree = tree;
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Render this tree control.
       *
       * @exception JspException if a processing error occurs
       */
      public int doEndTag() throws JspException {
  
          TreeControl treeControl = getTreeControl();
          JspWriter out = pageContext.getOut();
          try {
              out.print
                  ("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\"");
              if (style != null) {
                  out.print(" class=\"");
                  out.print(style);
                  out.print("\"");
              }
              out.println(">");
              int level = 0;
              TreeControlNode node = treeControl.getRoot();
              render(out, node, level, treeControl.getWidth(), true);
              out.println("</table>");
          } catch (IOException e) {
              throw new JspException(e);
          }
  
          return (EVAL_PAGE);
  
      }
  
  
      /**
       * Release all state information set by this tag.
       */
      public void release() {
  
          this.action = null;
          this.images = DEFAULT_IMAGES;
          this.scope = null;
          this.style = null;
          this.styleSelected = null;
          this.styleUnselected = null;
          this.tree = null;
  
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * Return the <code>TreeControl</code> instance for the tree control that
       * we are rendering.
       *
       * @exception JspException if no TreeControl instance can be found
       */
      protected TreeControl getTreeControl() throws JspException {
  
          Object treeControl = null;
          if (scope == null)
              treeControl = pageContext.findAttribute(tree);
          else if ("page".equals(scope))
              treeControl =
                  pageContext.getAttribute(tree, PageContext.PAGE_SCOPE);
          else if ("request".equals(scope))
              treeControl =
                  pageContext.getAttribute(tree, PageContext.REQUEST_SCOPE);
          else if ("session".equals(scope))
              treeControl =
                  pageContext.getAttribute(tree, PageContext.SESSION_SCOPE);
          else if ("application".equals(scope))
              treeControl =
                  pageContext.getAttribute(tree, PageContext.APPLICATION_SCOPE);
          if (treeControl == null)
              throw new JspException("Cannot find tree control attribute '" +
                                     tree + "'");
          else if (!(treeControl instanceof TreeControl))
              throw new JspException("Invalid tree control attribute '" +
                                     tree + "'");
          else
              return ((TreeControl) treeControl);
  
      }
  
  
      /**
       * Render the specified node, as controlled by the specified parameters.
       *
       * @param out The <code>JspWriter</code> to which we are writing
       * @param node The <code>TreeControlNode</code> we are currently
       *  rendering
       * @param level The indentation level of this node in the tree
       * @param width Total displayable width of the tree
       * @param last Is this the last node in a list?
       *
       * @exception IOException if an input/output error occurs
       */
      protected void render(JspWriter out, TreeControlNode node,
                            int level, int width, boolean last)
          throws IOException {
  
          HttpServletResponse response =
              (HttpServletResponse) pageContext.getResponse();
      
          // if the node is root node and the label value is
          // null, then do not render root node in the tree.
          
          if ("ROOT-NODE".equalsIgnoreCase(node.getName()) &&
          (node.getLabel() == null)) {
              // Render the children of this node
              TreeControlNode children[] = node.findChildren();
              int lastIndex = children.length - 1;
              int newLevel = level + 1;
              for (int i = 0; i < children.length; i++) {
                  render(out, children[i], newLevel, width, i == lastIndex);
              }
              return;
          }
          
          // Render the beginning of this node
          out.println("  <tr valign=\"middle\">");
  
          // Create the appropriate number of indents
          for (int i = 0; i < level; i++) {
              int levels = level - i;
              TreeControlNode parent = node;
              for (int j = 1; j <= levels; j++)
                  parent = parent.getParent();
              if (parent.isLast())
                  out.print("    <td></td>");
              else {
                  out.print("    <td><img src=\"");
                  out.print(images);
                  out.print("/");
                  out.print(IMAGE_LINE_VERTICAL);
                  out.print("\" alt=\"\" border=\"0\"></td>");
              }
              out.println();
          }
  
          // Render the tree state image for this node
  
          // HACK to take into account special characters like = and &
          // in the node name, could remove this code if encode URL
          // and later request.getParameter() could deal with = and &
          // character in parameter values. 
          String encodedNodeName = URLEncoder.encode(node.getName());
  
          String action = replace(getAction(), "${name}", encodedNodeName);
  
          
          String updateTreeAction =
              replace(getAction(), "tree=${name}", "select=" + encodedNodeName);
          updateTreeAction =
              ((HttpServletResponse) pageContext.getResponse()).
              encodeURL(updateTreeAction);
  
          out.print("    <td>");
          if ((action != null) && !node.isLeaf()) {
              out.print("<a href=\"");
              out.print(response.encodeURL(action));
              out.print("\">");
          }
          out.print("<img src=\"");
          out.print(images);
          out.print("/");
          if (node.isLeaf()) {
              if (node.isLast())
                  out.print(IMAGE_LINE_LAST);
              else
                  out.print(IMAGE_LINE_MIDDLE);
              out.print("\" alt=\"");
          } else if (node.isExpanded()) {
              if (node.isLast())
                  out.print(IMAGE_HANDLE_DOWN_LAST);
              else
                  out.print(IMAGE_HANDLE_DOWN_MIDDLE);
              out.print("\" alt=\"close node");
          } else {
              if (node.isLast())
                  out.print(IMAGE_HANDLE_RIGHT_LAST);
              else
                  out.print(IMAGE_HANDLE_RIGHT_MIDDLE);
              out.print("\" alt=\"expand node");
          }
          out.print("\" border=\"0\">");
          if ((action != null) && !node.isLeaf())
              out.print("</a>");
          out.println("</td>");
  
          // Calculate the hyperlink for this node (if any)
          String hyperlink = null;
          if (node.getAction() != null)
              hyperlink = ((HttpServletResponse) pageContext.getResponse()).
                  encodeURL(node.getAction());
  
          // Render the icon for this node (if any)
          out.print("    <td colspan=\"");
          out.print(width - level + 1);
          out.print("\">");
          if (node.getIcon() != null) {
              if (hyperlink != null) {
                  out.print("<a href=\"");
                  out.print(hyperlink);
                  out.print("\"");
                  String target = node.getTarget();
                  if(target != null) {
                      out.print(" target=\"");
                      out.print(target);
                      out.print("\"");
                  }
                  // to refresh the tree in the same 'self' frame
                  out.print(" onclick=\"");
                  out.print("self.location.href='" + updateTreeAction + "'");
                  out.print("\"");
                  out.print(">");
              }
              out.print("<img src=\"");
              out.print(images);
              out.print("/");
              out.print(node.getIcon());
              out.print("\" alt=\"");
              out.print("\" border=\"0\">");
              if (hyperlink != null)
                  out.print("</a>");
          }
  
          // Render the label for this node (if any)
  
          if (node.getLabel() != null) {
              String labelStyle = null;
              if (node.isSelected() && (styleSelected != null))
                  labelStyle = styleSelected;
              else if (!node.isSelected() && (styleUnselected != null))
                  labelStyle = styleUnselected;
              if (hyperlink != null) {
                  // Note the leading space so that the text has some space
                  // between it and any preceding images
                  out.print(" <a href=\"");
                  out.print(hyperlink);
                  out.print("\"");
                  String target = node.getTarget();
                  if(target != null) {
                      out.print(" target=\"");
                      out.print(target);
                      out.print("\"");
                  }
                  if (labelStyle != null) {
                      out.print(" class=\"");
                      out.print(labelStyle);
                      out.print("\"");
                  }
                  // to refresh the tree in the same 'self' frame
                  out.print(" onclick=\"");
                  out.print("self.location.href='" + updateTreeAction + "'");
                  out.print("\"");
                  out.print(">");
              } else if (labelStyle != null) {
                  out.print("<span class=\"");
                  out.print(labelStyle);
                  out.print("\">");
              }
              out.print(node.getLabel());
              if (hyperlink != null)
                  out.print("</a>");
              else if (labelStyle != null)
                  out.print("</span>");
          }
          out.println("</td>");
  
          // Render the end of this node
          out.println("  </tr>");
  
          // Render the children of this node
          if (node.isExpanded()) {
              TreeControlNode children[] = node.findChildren();
              int lastIndex = children.length - 1;
              int newLevel = level + 1;
              for (int i = 0; i < children.length; i++) {
                  render(out, children[i], newLevel, width, i == lastIndex);
              }
          }
  
      }
  
  
      /**
       * Replace any occurrence of the specified placeholder in the specified
       * template string with the specified replacement value.
       *
       * @param template Pattern string possibly containing the placeholder
       * @param placeholder Placeholder expression to be replaced
       * @param value Replacement value for the placeholder
       */
      protected String replace(String template, String placeholder,
                               String value) {
  
          if (template == null)
              return (null);
          if ((placeholder == null) || (value == null))
              return (template);
          while (true) {
              int index = template.indexOf(placeholder);
              if (index < 0)
                  break;
              StringBuffer temp = new StringBuffer(template.substring(0, index));
              temp.append(value);
              temp.append(template.substring(index + placeholder.length()));
              template = temp.toString();
          }
          return (template);
  
      }
  
  
  }
  
  
  
  1.1                  
jakarta-jetspeed-2/applications/pam/src/java/org/apache/webapp/admin/TreeControlNode.java
  
  Index: TreeControlNode.java
  ===================================================================
  /*
   * Copyright 2001,2004 The Apache Software Foundation.
   * 
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   * 
   *      http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  
  package org.apache.webapp.admin;
  
  
  import java.io.Serializable;
  import java.util.ArrayList;
  
  
  /**
   * <p>An individual node of a tree control represented by an instance of
   * <code>TreeControl</code>, and rendered by an instance of
   * <code>TreeControlTag</code>.</p>
   *
   * @author Jazmin Jonson
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2004/06/30 03:09:15 $
   */
  
  public class TreeControlNode implements Serializable {
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Construct a new TreeControlNode with the specified parameters.
       *
       * @param name Internal name of this node (must be unique within
       *  the entire tree)
       * @param icon Pathname of the image file for the icon to be displayed
       *  when this node is visible, relative to the image directory
       *  for our images
       * @param label The label that will be displayed to the user if
       *  this node is visible
       * @param action The hyperlink to be selected if the user
       *  selects this node, or <code>null</code> if this node's label should
       *  not be a hyperlink
       * @param target The window target in which the <code>action</code>
       *  hyperlink's results will be displayed, or <code>null</code> for
       *  the current window
       * @param expanded Should this node be expanded?
       */
      public TreeControlNode(String name,
                             String icon, String label,
                             String action, String target,
                             boolean expanded, String domain) {
  
          super();
          this.name = name;
          this.icon = icon;
          this.label = label;
          this.action = action;
          this.target = target;
          this.expanded = expanded;
          this.domain = domain;
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The set of child <code>TreeControlNodes</code> for this node, in the
       * order that they should be displayed.
       */
      protected ArrayList children = new ArrayList();
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * The hyperlink to which control will be directed if this node
       * is selected by the user.
       */
      protected String action = null;
  
      public String getAction() {
          return (this.action);
      }
  
      /**
       * The domain of this node.
       */
      protected String domain = null;
  
      public String getDomain() {
          return (this.domain);
      }
  
      /**
       * Is this node currently expanded?
       */
      protected boolean expanded = false;
  
      public boolean isExpanded() {
          return (this.expanded);
      }
  
      public void setExpanded(boolean expanded) {
          this.expanded = expanded;
      }
  
  
      /**
       * The pathname to the icon file displayed when this node is visible,
       * relative to the image directory for our images.
       */
      protected String icon = null;
  
      public String getIcon() {
          return (this.icon);
      }
  
  
      /**
       * The label that will be displayed when this node is visible.
       */
      protected String label = null;
  
      public String getLabel() {
          return (this.label);
      }
  
  
      /**
       * Is this the last node in the set of children for our parent node?
       */
      protected boolean last = false;
  
      public boolean isLast() {
          return (this.last);
      }
  
      void setLast(boolean last) {
          this.last = last;
      }
  
  
      /**
       * Is this a "leaf" node (i.e. one with no children)?
       */
      public boolean isLeaf() {
          synchronized (children) {
              return (children.size() < 1);
          }
      }
  
  
      /**
       * The unique (within the entire tree) name of this node.
       */
      protected String name = null;
  
      public String getName() {
          return (this.name);
      }
  
  
      /**
       * The parent node of this node, or <code>null</code> if this
       * is the root node.
       */
      protected TreeControlNode parent = null;
  
      public TreeControlNode getParent() {
          return (this.parent);
      }
  
      void setParent(TreeControlNode parent) {
          this.parent = parent;
          if (parent == null)
              width = 1;
          else
              width = parent.getWidth() + 1;
      }
  
  
      /**
       * Is this node currently selected?
       */
      protected boolean selected = false;
  
      public boolean isSelected() {
          return (this.selected);
      }
  
      public void setSelected(boolean selected) {
          this.selected = selected;
      }
  
  
      /**
       * The window target for the hyperlink identified by the
       * <code>action</code> property, if this node is selected
       * by the user.
       */
      protected String target = null;
  
      public String getTarget() {
          return (this.target);
      }
  
  
      /**
       * The <code>TreeControl</code> instance representing the
       * entire tree.
       */
      protected TreeControl tree = null;
  
      public TreeControl getTree() {
          return (this.tree);
      }
  
      void setTree(TreeControl tree) {
          this.tree = tree;
      }
  
  
      /**
       * The display width necessary to display this item (if it is visible).
       * If this item is not visible, the calculated width will be that of our
       * most immediately visible parent.
       */
      protected int width = 0;
  
      public int getWidth() {
          return (this.width);
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Add a new child node to the end of the list.
       *
       * @param child The new child node
       *
       * @exception IllegalArgumentException if the name of the new child
       *  node is not unique
       */
      public void addChild(TreeControlNode child)
          throws IllegalArgumentException {
  
          tree.addNode(child);
          child.setParent(this);
          synchronized (children) {
              int n = children.size();
              if (n > 0) {
                  TreeControlNode node = (TreeControlNode) children.get(n - 1);
                  node.setLast(false);
              }
              child.setLast(true);
              children.add(child);
          }
  
      }
  
  
      /**
       * Add a new child node at the specified position in the child list.
       *
       * @param offset Zero-relative offset at which the new node
       *  should be inserted
       * @param child The new child node
       *
       * @exception IllegalArgumentException if the name of the new child
       *  node is not unique
       */
      public void addChild(int offset, TreeControlNode child)
          throws IllegalArgumentException {
  
          tree.addNode(child);
          child.setParent(this);
          synchronized (children) {
              children.add(offset, child);
          }
  
      }
  
  
      /**
       * Return the set of child nodes for this node.
       */
      public TreeControlNode[] findChildren() {
  
          synchronized (children) {
              TreeControlNode results[] = new TreeControlNode[children.size()];
              return ((TreeControlNode[]) children.toArray(results));
          }
  
      }
  
  
      /**
       * Remove this node from the tree.
       */
      public void remove() {
  
          if (tree != null) {
              tree.removeNode(this);
          }
  
      }
  
  
      /**
       * Remove the child node (and all children of that child) at the
       * specified position in the child list.
       *
       * @param offset Zero-relative offset at which the existing
       *  node should be removed
       */
      public void removeChild(int offset) {
  
          synchronized (children) {
              TreeControlNode child =
                  (TreeControlNode) children.get(offset);
              tree.removeNode(child);
              child.setParent(null);
              children.remove(offset);
          }
  
      }
  
  
      // -------------------------------------------------------- Package Methods
  
  
      /**
       * Remove the specified child node.  It is assumed that all of the
       * children of this child node have already been removed.
       *
       * @param child Child node to be removed
       */
      void removeChild(TreeControlNode child) {
  
          if (child == null) {
              return;
          }
          synchronized (children) {
              int n = children.size();
              for (int i = 0; i < n; i++) {
                  if (child == (TreeControlNode) children.get(i)) {
                      children.remove(i);
                      return;
                  }
              }
          }
  
      }
  
  
  }
  
  
  
  1.1                  
jakarta-jetspeed-2/applications/pam/src/java/org/apache/webapp/admin/TreeControl.java
  
  Index: TreeControl.java
  ===================================================================
  /*
   * Copyright 2001,2004 The Apache Software Foundation.
   * 
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   * 
   *      http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  
  package org.apache.webapp.admin;
  
  
  import java.io.Serializable;
  import java.util.HashMap;
  
  
  /**
   * <p>The overall data structure representing a <em>tree control</em>
   * that can be rendered by the <code>TreeControlTag</code> custom tag.
   * Each node of the tree is represented by an instance of
   * <code>TreeControlNode</code>.</p>
   *
   * @author Jazmin Jonson
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2004/06/30 03:09:15 $
   */
  
  public class TreeControl implements Serializable {
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Construct a new instance with no predefined root node.
       */
      public TreeControl() {
  
          super();
          setRoot(null);
  
      }
  
  
      /**
       * Construct a new instance with the specified root node.
       *
       * @param root The new root node
       */
      public TreeControl(TreeControlNode root) {
  
          super();
          setRoot(root);
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The collection of nodes that represent this tree, keyed by name.
       */
      protected HashMap registry = new HashMap();
  
  
      /**
       * The most recently selected node.
       */
      protected TreeControlNode selected = null;
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * The root node of the entire tree.
       */
      protected TreeControlNode root = null;
  
      public TreeControlNode getRoot() {
          return (this.root);
      }
  
      protected void setRoot(TreeControlNode root) {
          if (this.root != null)
              removeNode(this.root);
          if (root != null)
              addNode(root);
          root.setLast(true);
          this.root = root;
      }
  
  
      /**
       * The current displayable "width" of this tree (that is, the maximum
       * depth of the visible part of the tree).
       */
      public int getWidth() {
  
          if (root == null)
              return (0);
          else
              return (getWidth(root));
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Find and return the <code>TreeControlNode</code> for the specified
       * node name, if it exists; otherwise, return <code>null</code>.
       *
       * @param name Name of the <code>TreeControlNode</code> to be returned
       */
      public TreeControlNode findNode(String name) {
  
          synchronized (registry) {
              return ((TreeControlNode) registry.get(name));
          }
  
      }
  
  
      /**
       * Mark the specified node as the one-and-only currently selected one,
       * deselecting any previous node that was so marked.
       *
       * @param node Name of the node to mark as selected, or <code>null</code>
       *  if there should be no currently selected node
       */
      public void selectNode(String name) {
  
          if (selected != null) {
              selected.setSelected(false);
              selected = null;
          }
          selected = findNode(name);
          if (selected != null)
              selected.setSelected(true);
  
      }
  
  
      // -------------------------------------------------------- Package Methods
  
  
      /**
       * Register the specified node in our registry of the complete tree.
       *
       * @param node The <code>TreeControlNode</code> to be registered
       *
       * @exception IllegalArgumentException if the name of this node
       *  is not unique
       */
      void addNode(TreeControlNode node) throws IllegalArgumentException {
  
          synchronized (registry) {
              String name = node.getName();
              if (registry.containsKey(name))
                  throw new IllegalArgumentException("Name '" + name +
                                                     "' is not unique");
              node.setTree(this);
              registry.put(name, node);
          }
  
      }
  
  
      /**
       * Calculate the width of the subtree below the specified node.
       *
       * @param node The node for which to calculate the width
       */
      int getWidth(TreeControlNode node) {
  
          int width = node.getWidth();
          if (!node.isExpanded())
              return (width);
          TreeControlNode children[] = node.findChildren();
          for (int i = 0; i < children.length; i++) {
              int current = getWidth(children[i]);
              if (current > width)
                  width = current;
          }
          return (width);
  
      }
  
  
      /**
       * Deregister the specified node, as well as all child nodes of this
       * node, from our registry of the complete tree.  If this node is not
       * present, no action is taken.
       *
       * @param node The <code>TreeControlNode</code> to be deregistered
       */
      void removeNode(TreeControlNode node) {
  
          synchronized (registry) {
              TreeControlNode children[] = node.findChildren();
              for (int i = 0; i < children.length; i++)
                  removeNode(children[i]);
              TreeControlNode parent = node.getParent();
              if (parent != null) {
                  parent.removeChild(node);
              }
              node.setParent(null);
              node.setTree(null);
              if (node == this.root) {
                  this.root = null;
              }
              registry.remove(node.getName());
          }
  
      }
  
  
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to