Source code: com/virtuosotechnologies/lib/basiccommand/builder/AbstractBranchBuilderNode.java
1 /*
2 ================================================================================
3
4 FILE: AbstractBranchBuilderNode.java
5
6 PROJECT:
7
8 Virtuoso Utilities
9
10 CONTENTS:
11
12 A skeletal implementation for builder nodes with children.
13
14 PROGRAMMERS:
15
16 Daniel Azuma (DA) <dazuma@kagi.com>
17
18 COPYRIGHT:
19
20 Copyright (C) 2003 Daniel Azuma (dazuma@kagi.com)
21
22 This program is free software; you can redistribute it and/or
23 modify it under the terms of the GNU General Public License as
24 published by the Free Software Foundation; either version 2
25 of the License, or (at your option) any later version.
26
27 This program is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public
33 License along with this program; if not, write to
34 Free Software Foundation, Inc.
35 59 Temple Place, Suite 330
36 Boston, MA 02111-1307 USA
37
38 ================================================================================
39 */
40
41
42 package com.virtuosotechnologies.lib.basiccommand.builder;
43
44
45 import java.util.List;
46 import java.util.ArrayList;
47 import java.util.Collections;
48 import java.util.Iterator;
49
50 import com.virtuosotechnologies.lib.command.CommandNode;
51 import com.virtuosotechnologies.lib.command.CommandNodeListener;
52 import com.virtuosotechnologies.lib.command.ChildAddedEvent;
53 import com.virtuosotechnologies.lib.command.ChildRemovedEvent;
54 import com.virtuosotechnologies.lib.command.AllChildrenRemovedEvent;
55
56
57 /**
58 * A skeletal implementation for builder nodes with children. Provides
59 * accessors for children as well as position finding. Subclasses need
60 * to implement createChildNode() to create child nodes corresponding
61 * to child CommandNodes. Subclasses also need to implement the
62 * add/set/removeElements methods, as well as getCardinality().
63 */
64 public abstract class AbstractBranchBuilderNode
65 extends AbstractBuilderNode
66 implements
67 CommandNodeListener
68 {
69 private List children_;
70
71
72 /**
73 * Used only by AbstractBuilderNode
74 */
75 final void internalAddChild(
76 AbstractBuilderNode node)
77 {
78 children_.add(node);
79 }
80
81
82 /**
83 * Used only by AbstractBuilderNode
84 */
85 final void internalAddChild(
86 int index,
87 AbstractBuilderNode node)
88 {
89 children_.add(index, node);
90 }
91
92
93 /**
94 * Constructor
95 */
96 protected AbstractBranchBuilderNode(
97 CommandNode commandNode,
98 AbstractBranchBuilderNode parent,
99 int index)
100 {
101 super(commandNode, parent, index);
102 children_ = new ArrayList();
103 commandNode.addNodeListener(this);
104 }
105
106
107 /**
108 * Build children. Call this from the constructor of nodes that
109 * can have children. Assumes that the node has no children to start off.
110 */
111 protected final void buildChildren()
112 {
113 CommandNode cn = getCommandNode();
114 int numChildren = cn.getNumChildren();
115 for (int i=0; i<numChildren; ++i)
116 {
117 CommandNode child = cn.getNthChild(i);
118 createChildNode(child, END_POSITION);
119 }
120 }
121
122
123 /**
124 * Get the starting position of a particular child
125 */
126 protected final int getPosition(
127 AbstractBuilderNode child)
128 {
129 int ret = 0;
130 for (Iterator iter = children_.iterator(); iter.hasNext(); )
131 {
132 AbstractBuilderNode node = (AbstractBuilderNode)iter.next();
133 if (node == child)
134 {
135 return ret;
136 }
137 else if (node != null)
138 {
139 ret += node.getCardinality();
140 }
141 }
142 return END_POSITION;
143 }
144
145
146 /**
147 * Get the starting position at a particular index
148 */
149 protected final int getPosition(
150 int index)
151 {
152 if (index == END_POSITION)
153 {
154 return END_POSITION;
155 }
156 int ret = 0;
157 for (int i=0; i<index; ++i)
158 {
159 AbstractBuilderNode node = (AbstractBuilderNode)children_.get(i);
160 if (node != null)
161 {
162 ret += node.getCardinality();
163 }
164 }
165 return ret;
166 }
167
168
169 /**
170 * Get a child given an index
171 */
172 protected final AbstractBuilderNode getChild(
173 int index)
174 {
175 return (AbstractBuilderNode)children_.get(index);
176 }
177
178
179 /**
180 * Get a child given a CommandNode
181 */
182 protected final AbstractBuilderNode getChild(
183 CommandNode cn)
184 {
185 for (int i=0; i<children_.size(); ++i)
186 {
187 AbstractBuilderNode node = (AbstractBuilderNode)children_.get(i);
188 if (node != null && node.getCommandNode() == cn)
189 {
190 return node;
191 }
192 }
193 return null;
194 }
195
196
197 /**
198 * Get number of children
199 */
200 protected final int getNumChildren()
201 {
202 return children_.size();
203 }
204
205
206 /**
207 * Get an unmodifiable view of the list of children
208 */
209 protected final List getChildren()
210 {
211 return Collections.unmodifiableList(children_);
212 }
213
214
215 /**
216 * Helper method that removes elements within the specified
217 * child's area of influence (position and cardinality)
218 */
219 protected final void removeChildElements(
220 AbstractBuilderNode child)
221 {
222 if (children_.size() > 0)
223 {
224 int pos = getPosition(child);
225 if (pos != END_POSITION)
226 {
227 int num = child.getCardinality();
228 for (int i=0; i<num; ++i)
229 {
230 removeElementAt(pos);
231 }
232 }
233 }
234 }
235
236
237 /**
238 * Create a child node. Return null if no child is to be created.
239 */
240 protected abstract AbstractBuilderNode createChildNode(
241 CommandNode cn,
242 int index);
243
244
245 /**
246 * Override this to insert a element at a position.
247 */
248 protected abstract void addElementAt(
249 int pos,
250 Object element);
251
252
253 /**
254 * Override this to set the element at a position. Default
255 * implementation calls removeElementAt followed by addElementAt.
256 */
257 protected void setElementAt(
258 int pos,
259 Object element)
260 {
261 removeElementAt(pos);
262 addElementAt(pos, element);
263 }
264
265
266 /**
267 * Override this to remove an indexed element.
268 */
269 protected abstract void removeElementAt(
270 int pos);
271
272
273 /**
274 * Override this to remove all child elements.
275 */
276 protected abstract void removeAllElements();
277
278
279 /**
280 * Child added.
281 * Default method creates a child node, which may result in elements
282 * being added.
283 */
284 public void childAdded(
285 ChildAddedEvent ev)
286 {
287 createChildNode(ev.getChildNode(), ev.getChildIndex());
288 }
289
290
291 /**
292 * Child removed.
293 * Default method removes the child node and removes the elements
294 * within the child's area of influence.
295 */
296 public void childRemoved(
297 ChildRemovedEvent ev)
298 {
299 int index = ev.getChildIndex();
300 AbstractBuilderNode child = (AbstractBuilderNode)children_.get(index);
301 if (child != null)
302 {
303 removeChildElements(child);
304 }
305 children_.remove(index);
306 }
307
308
309 /**
310 * All children removed.
311 * Default method removes all children and all elements under this node.
312 */
313 public void allChildrenRemoved(
314 AllChildrenRemovedEvent ev)
315 {
316 removeAllElements();
317 children_.clear();
318 }
319 }