001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.webapp.admin;
019:
020: import java.io.Serializable;
021: import java.util.HashMap;
022:
023: /**
024: * <p>The overall data structure representing a <em>tree control</em>
025: * that can be rendered by the <code>TreeControlTag</code> custom tag.
026: * Each node of the tree is represented by an instance of
027: * <code>TreeControlNode</code>.</p>
028: *
029: * @author Jazmin Jonson
030: * @author Craig R. McClanahan
031: * @version $Revision: 516448 $ $Date: 2007-03-09 17:25:47 +0100 (Fri, 09 Mar 2007) $
032: */
033:
034: public class TreeControl implements Serializable {
035: private static final long serialVersionUID = 1;
036:
037: // ----------------------------------------------------------- Constructors
038:
039: /**
040: * Construct a new instance with no predefined root node.
041: */
042: public TreeControl() {
043:
044: super ();
045: setRoot(null);
046:
047: }
048:
049: /**
050: * Construct a new instance with the specified root node.
051: *
052: * @param root The new root node
053: */
054: public TreeControl(TreeControlNode root) {
055:
056: super ();
057: setRoot(root);
058:
059: }
060:
061: // ----------------------------------------------------- Instance Variables
062:
063: /**
064: * The collection of nodes that represent this tree, keyed by name.
065: */
066: protected HashMap registry = new HashMap();
067:
068: /**
069: * The most recently selected node.
070: */
071: protected TreeControlNode selected = null;
072:
073: // ------------------------------------------------------------- Properties
074:
075: /**
076: * The root node of the entire tree.
077: */
078: protected TreeControlNode root = null;
079:
080: public TreeControlNode getRoot() {
081: return (this .root);
082: }
083:
084: protected void setRoot(TreeControlNode root) {
085: if (this .root != null)
086: removeNode(this .root);
087: if (root != null)
088: addNode(root);
089: root.setLast(true);
090: this .root = root;
091: }
092:
093: /**
094: * The current displayable "width" of this tree (that is, the maximum
095: * depth of the visible part of the tree).
096: */
097: public int getWidth() {
098:
099: if (root == null)
100: return (0);
101: else
102: return (getWidth(root));
103:
104: }
105:
106: // --------------------------------------------------------- Public Methods
107:
108: /**
109: * Find and return the <code>TreeControlNode</code> for the specified
110: * node name, if it exists; otherwise, return <code>null</code>.
111: *
112: * @param name Name of the <code>TreeControlNode</code> to be returned
113: */
114: public TreeControlNode findNode(String name) {
115:
116: synchronized (registry) {
117: return ((TreeControlNode) registry.get(name));
118: }
119:
120: }
121:
122: /**
123: * Mark the specified node as the one-and-only currently selected one,
124: * deselecting any previous node that was so marked.
125: *
126: * @param node Name of the node to mark as selected, or <code>null</code>
127: * if there should be no currently selected node
128: */
129: public void selectNode(String name) {
130:
131: if (selected != null) {
132: selected.setSelected(false);
133: selected = null;
134: }
135: selected = findNode(name);
136: if (selected != null)
137: selected.setSelected(true);
138:
139: }
140:
141: // -------------------------------------------------------- Package Methods
142:
143: /**
144: * Register the specified node in our registry of the complete tree.
145: *
146: * @param node The <code>TreeControlNode</code> to be registered
147: *
148: * @exception IllegalArgumentException if the name of this node
149: * is not unique
150: */
151: void addNode(TreeControlNode node) throws IllegalArgumentException {
152:
153: synchronized (registry) {
154: String name = node.getName();
155: if (registry.containsKey(name)) {
156: // throw new IllegalArgumentException("Name '" + name +
157: // "' is not unique");
158: }
159: node.setTree(this );
160: registry.put(name, node);
161: }
162:
163: }
164:
165: /**
166: * Calculate the width of the subtree below the specified node.
167: *
168: * @param node The node for which to calculate the width
169: */
170: int getWidth(TreeControlNode node) {
171:
172: int width = node.getWidth();
173: if (!node.isExpanded())
174: return (width);
175: TreeControlNode children[] = node.findChildren();
176: for (int i = 0; i < children.length; i++) {
177: int current = getWidth(children[i]);
178: if (current > width)
179: width = current;
180: }
181: return (width);
182:
183: }
184:
185: /**
186: * Deregister the specified node, as well as all child nodes of this
187: * node, from our registry of the complete tree. If this node is not
188: * present, no action is taken.
189: *
190: * @param node The <code>TreeControlNode</code> to be deregistered
191: */
192: public void removeNode(TreeControlNode node) {
193:
194: synchronized (registry) {
195: TreeControlNode children[] = node.findChildren();
196: for (int i = 0; i < children.length; i++)
197: removeNode(children[i]);
198: TreeControlNode parent = node.getParent();
199: if (parent != null) {
200: parent.removeChild(node);
201: }
202: node.setParent(null);
203: node.setTree(null);
204: if (node == this.root) {
205: this.root = null;
206: }
207: registry.remove(node.getName());
208: }
209:
210: }
211:
212: }
|