1 /*
2 * $Source$
3 * $Revision$
4 *
5 * Copyright (C) 2001 Myles Chippendale
6 *
7 * Part of Melati (http://melati.org), a framework for the rapid
8 * development of clean, maintainable web applications.
9 *
10 * Melati is free software; Permission is granted to copy, distribute
11 * and/or modify this software under the terms either:
12 *
13 * a) the GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the License, or (at your option)
15 * any later version,
16 *
17 * or
18 *
19 * b) any version of the Melati Software License, as published
20 * at http://melati.org
21 *
22 * You should have received a copy of the GNU General Public License and
23 * the Melati Software License along with this program;
24 * if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26 * GNU General Public License and visit http://melati.org to obtain the
27 * Melati Software License.
28 *
29 * Feel free to contact the Developers of Melati (http://melati.org),
30 * if you would like to work out a different arrangement than the options
31 * outlined here. It is our intention to allow Melati to be used by as
32 * wide an audience as possible.
33 *
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
38 *
39 * Contact details for copyright holder:
40 *
41 * Myles Chippendale <MylesC At paneris.org>
42 */
43
44 package org.melati.util;
45
46 import java.util.Vector;
47 import org.melati.poem.Treeable;
48
49 /**
50 * A {@link Tree} node.
51 *
52 * @author MylesC At paneris.org
53 *
54 */
55 public class TreeNode {
56 private Treeable data;
57 int depth;
58 protected TreeNode parent = null;
59 private TreeNode[] children = null;
60 private boolean checkedForChildren = false;
61
62 /**
63 * Constructor.
64 * @param n the Treeable object
65 * @param d the depth of this node
66 */
67 public TreeNode(Treeable n, int d) {
68 data = n;
69 depth = d;
70 }
71
72 /**
73 * @return whether this is a root node
74 */
75 public boolean isRoot() {
76 return (parent == null);
77 }
78
79 /**
80 * @return whether this is a terminal node
81 */
82 public boolean isLeaf() {
83 return (getChildren() == null);
84 }
85
86 /**
87 * @return the depth in the tree
88 */
89 public int getDepth() {
90 return depth;
91 }
92
93 /**
94 * @return the Treeable data object this wraps
95 */
96 public Treeable getData() {
97 return data;
98 }
99
100 /**
101 * @return theis nodes parent, null if this is a root node
102 */
103 public TreeNode getParent() {
104 return parent;
105 }
106
107 /**
108 * @return the name unique within the Tree
109 */
110 public String getUniqueName() {
111 int code = hashCode();
112 String name = "";
113 if (code < 0) {
114 code = -code;
115 name = "Z";
116 }
117 return name + Integer.toString(code, java.lang.Character.MAX_RADIX);
118 }
119
120 /**
121 * @return the descendants of this node, maybe an empty Array
122 */
123 public synchronized TreeNode[] getChildren() {
124 if (checkedForChildren)
125 return children;
126
127 Treeable[] kids = data.getChildren();
128 if (kids == null || kids.length == 0)
129 children = null;
130 else {
131 children = augment(kids, depth + 1);
132 for (int i = 0; i<children.length; i++)
133 children[i].parent = this;
134 }
135 checkedForChildren = true;
136
137 return children;
138 }
139
140 /**
141 * Retrieve an Array of TreeNodes which is the shortest path from
142 * this node to its root.
143 *
144 * @param includeNode whether to include this node in the path
145 * @param reverse if true returns a path from root to this
146 * @return an Array of TreeNodes
147 */
148 public TreeNode[] getNodeToRootPath(boolean includeNode, boolean reverse) {
149 Vector<TreeNode> path = new Vector<TreeNode>();
150 if (includeNode)
151 path.addElement(this);
152
153 TreeNode current = this;
154
155 while (!current.isRoot()) {
156 current = current.parent;
157 if (reverse)
158 path.insertElementAt(current, 0);
159 else
160 path.addElement(current);
161 }
162
163 TreeNode[] result = new TreeNode[path.size()];
164 return (TreeNode[])path.toArray(result);
165 }
166
167 /**
168 * @return the path to this node's root excluding this node
169 */
170 public TreeNode[] getPathToRoot() {
171 return getNodeToRootPath(false, false);
172 }
173
174 /**
175 * @return the path from this node's root excluding this node
176 */
177 public TreeNode[] getPathFromRoot() {
178 return getNodeToRootPath(false, true);
179 }
180
181 /**
182 * Create a new Array of TreeNodes specifying a new depth.
183 * @param nodes the nodes to copy
184 * @param depth the new depth
185 * @return a new Array of TreeNodes with the new depth
186 */
187 public static TreeNode[] augment(Treeable[] nodes, int depth) {
188 TreeNode[] t = new TreeNode[nodes.length];
189 for (int i=0; i<nodes.length; i++) {
190 t[i] = new TreeNode(nodes[i], depth);
191 }
192 return t;
193 }
194 }
195
196
197
198
199
200