source: trunk/gli/src/org/greenstone/gatherer/valuetree/GValueNode.java@ 5672

Last change on this file since 5672 was 5672, checked in by jmt12, 21 years ago

Not only did I rewrite the toString method to require a parameter specifying what sort of string should be returned, RAW, DOM or GREENSTONE, I also fixed a stupid bug when removing child nodes, which has made the MEM a thousand times more stable (OK so its probably closer to 5. Perhaps 2, yes 2 times more stable)

  • Property svn:keywords set to Author Date Id Revision
File size: 13.0 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.valuetree;
38
39/**
40 * Title: The Gatherer<br>
41 * Description: The Gatherer: a tool for gathering and enriching digital collections.<br>
42 * Copyright: Copyright (c) 2001<br>
43 * Company: The University of Waikato<br>
44 * First Coded: 20/06/02
45 * Revised:<br>
46 * @author John Thompson, Greenstone Digital Libraries
47 * @version 2.1
48 */
49
50import java.util.*;
51import javax.swing.tree.*;
52import org.greenstone.gatherer.Gatherer;
53import org.greenstone.gatherer.msm.MSMUtils;
54import org.greenstone.gatherer.util.Codec;
55import org.greenstone.gatherer.util.StaticStrings;
56import org.greenstone.gatherer.util.Utility;
57import org.w3c.dom.*;
58
59/** This class is instantiated using a metadata element. From this parent element, which refers to a specific Element in the mds DOM model, the AssignedValues child is used as the root of a tree data-structure encompassing all of the nodes within the AssignedValues tree. This class also provide methods for adding, updating and removing nodes within this tree, as well as implementing all of the methods necessary for this node to be used as the basis of a tree model.
60 */
61public class GValueNode
62 extends DefaultMutableTreeNode {
63
64 static final public int DOM = 0;
65 static final public int GREENSTONE = 1;
66 static final public int TEXT = 2;
67
68 private String element_name = null;
69 private String default_value = null;
70
71 public GValueNode(Element element) {
72 this.children = null;
73 this.userObject = element;
74 this.default_value = null;
75 }
76
77 public GValueNode(String element_name, String default_value) {
78 this.element_name = element_name;
79 this.default_value = default_value;
80 }
81
82 /** Compares two GValueNodes for ordering by using the String.compareTo method.
83 * @param sibling The <strong>Object</strong> representing the GValueNode we are comparing ourselves to.
84 * @return An <i>int</i> indicating the ordering. The value is less than zero if we are before the parameter object, zero if we are equal and greater than zero if we preceed sibling.
85 */
86 public int compareTo(Object sibling) {
87 return toString().compareTo(sibling.toString());
88 }
89
90 /** Determine if this tree node contains a child with a matching value.
91 * @param value The value we are attempting to match, as a <strong>String</strong>.
92 * @return <i>true</i> if there is a matching child node, <i>false</i> otherwise.
93 */
94 public boolean containsValue(String value) {
95 if(default_value != null) {
96 return false;
97 }
98 return getValue(value) != null;
99 }
100
101 /** Returns an enumeration of the child nodes.
102 * @return An <strong>Enumeration</strong> containing the child nodes.
103 */
104 public Enumeration children() {
105 if(default_value != null) {
106 return null;
107 }
108 if(children == null) {
109 map();
110 }
111 return children.elements();
112 }
113 public boolean equals(Object other) {
114 return compareTo(other) == 0;
115 }
116
117 public GValueNode get(int index) {
118 GValueNode result = null;
119 if(children != null) {
120 result = (GValueNode) children.get(index);
121 }
122 return result;
123 }
124
125 public String getAlias() {
126 // Attempt to retrieve a child node named Alias
127 Element element = (Element) userObject;
128 for(Node pos_node = element.getFirstChild(); pos_node != null; pos_node = pos_node.getNextSibling()) {
129 // And if we find such a node
130 if(pos_node.getNodeName().equals("Alias")) {
131 // Retrieve its text node
132 for(Node pos_text = pos_node.getFirstChild(); pos_text != null; pos_text = pos_text.getNextSibling()) {
133 // When we find the node return its value
134 if(pos_text.getNodeName().equals("#text")) {
135 return pos_text.getNodeValue();
136 }
137 }
138 }
139 }
140 return "";
141 }
142
143 public String getAlias(String index) {
144 return index;
145 }
146
147 /** Returns <I>true</I> if the reciever allows children. */
148 public boolean getAllowsChildren() {
149 return true;
150 }
151
152 /** Returns the child <I>TreeNode</I> at index <I>childIndex</I>.*/
153 public TreeNode getChildAt(int index) {
154 if(default_value != null) {
155 return this;
156 }
157 if(children == null) {
158 map();
159 }
160 return (GValueNode) children.get(index);
161 }
162
163 /** Returns the number of children <I>TreeNode</I>s the reciever contains. */
164 public int getChildCount() {
165 int size = 0;
166 if(default_value != null) {
167 size = 0;
168 }
169 if(children == null) {
170 map();
171 }
172 return children.size();
173 }
174
175 public Element getElement() {
176 return (Element) userObject;
177 }
178
179 /** Return the path to this node within the value tree model.
180 * @return A <strong>String</strong> representing the path, ie "Titles\Modern\The Green Mile"
181 */
182 public String getFullPath(boolean as_text) {
183 if(default_value != null) {
184 return default_value;
185 }
186 StringBuffer path = new StringBuffer(toString());
187 GValueNode node = (GValueNode) getParent();
188 while(node != null && !node.getElement().getNodeName().equalsIgnoreCase("AssignedValues")) {
189 path.insert(0, StaticStrings.ESCAPE_STR + StaticStrings.ESCAPE_STR);
190 path.insert(0, node.toString());
191 node = (GValueNode) node.getParent();
192 }
193 if(as_text) {
194 return Codec.transform(path.toString(), Codec.GREENSTONE_TO_TEXT);
195 }
196 else {
197 return path.toString();
198 }
199 }
200
201 /** Returns the index of <I>node</I> in the recievers children. If the
202 * reciever does not contain <I>node</I>, <I>-1</I> will be returned. */
203 public int getIndex(TreeNode node) {
204 if(default_value != null) {
205 return 0;
206 }
207 if(children == null) {
208 map();
209 }
210 return children.indexOf(node);
211 }
212
213 public String getMetadataElementName() {
214 if(default_value != null) {
215 return element_name;
216 }
217 GValueNode node = this;
218 while(node != null && !node.getElement().getNodeName().equalsIgnoreCase("AssignedValues")) {
219 node = (GValueNode)node.getParent();
220 }
221 if(node != null) {
222 return node.getElement().getAttribute("element");
223 }
224 return null;
225 }
226
227 public GValueNode getValue(String value) {
228 ///ystem.err.println("GValueNode.getValue(" + value + ")");
229 if(default_value != null) {
230 return this;
231 }
232 if(children == null) {
233 map();
234 }
235 for(int i = 0; i < children.size(); i++) {
236 GValueNode child = (GValueNode) children.get(i);
237 ///ystem.err.println("Comparing value and '" + child.toString(GValueNode.DOM));
238 if(child.toString(GValueNode.DOM).equalsIgnoreCase(value)) {
239 return child;
240 }
241 }
242 return null;
243 }
244
245 /** Adds <I>child</I> to the receiever at <I>index</I>. <I>child</I> will
246 * be messaged with setParent().
247 */
248 public void insert(MutableTreeNode child, int index) {
249 if(default_value != null) {
250 return;
251 }
252 if(index >= children.size()) {
253 // Append to children.
254 children.add(child);
255 // And to document
256 getElement().appendChild(((GValueNode)child).getElement());
257 }
258 else {
259 GValueNode sibling = (GValueNode) children.get(index);
260 // Insert in children
261 children.add(index, child);
262 // And in document
263 getElement().insertBefore(((GValueNode)child).getElement(), sibling.getElement());
264 }
265 child.setParent(this);
266 }
267
268 /** Returns <I>true</I> if the reciever is a leaf. */
269 public boolean isLeaf() {
270 if(default_value != null || getChildCount() > 0) {
271 return false;
272 }
273 return true;
274 }
275
276 /** Ensure that the children nodes of this tree are instantiated, and record the initial mappings for legacy sake.
277 * @param mapping A <strong>HashMap</strong> into which to write the initial mappings.
278 * @param prefix The prefix to use for indexes, as a <strong>String</strong>.
279 */
280 public void map(HashMap mapping, String prefix) {
281 if(default_value != null) {
282 return;
283 }
284 children = new Vector();
285 if(prefix.length() > 0) {
286 prefix = prefix + ".";
287 }
288 int i = 1;
289 for(Node node = getElement().getFirstChild(); node != null; node = node.getNextSibling()) {
290 if(node.getNodeName().equals("Subject")) {
291 GValueNode child = new GValueNode((Element)node);
292 child.setParent(this);
293 children.add(child);
294 String index = prefix + i;
295 mapping.put(index, child);
296 child.map(mapping, index);
297 i++;
298 }
299 }
300 }
301
302 public void setAlias(String alias) {
303 setNodeValue("Alias", alias);
304 }
305
306 /** Resets the user object of the reciever to <I>object</I>. */
307 public void setUserObject(Object object) {
308 // Can't ever change Elements from here. Have to use editor. */
309 }
310
311 public void setValue(String value) {
312 setNodeValue("Value", value);
313 }
314
315 public int size() {
316 int size = 0;
317 if(children != null) {
318 size = children.size();
319 }
320 return size;
321 }
322
323 /** Returns a <I>String</I> representation of the reciever. If this
324 * happens to be the AssignedValues 'root' then we do something slightly
325 * different, otherwise we return the value of the <I>#Text</I> child of
326 * the <I>Value</I> of this <I>Subject</I> node!
327 */
328 public String toString() {
329 return toString(GValueNode.TEXT);
330 }
331
332 public String toString(int decode_type) {
333 if(default_value != null) {
334 return default_value;
335 }
336 Element element = getElement();
337 String name = element.getNodeName();
338 String result = null;
339 if(name.equals("Subject")) {
340 result = MSMUtils.getValue(element);
341 switch(decode_type) {
342 case GValueNode.GREENSTONE:
343 // We want this as greenstone format
344 ///ystem.err.print(result);
345 result = Codec.transform(result, Codec.DOM_TO_GREENSTONE);
346 ///ystem.err.println(" -> D2G decode -> " + result);
347 break;
348 case GValueNode.TEXT:
349 ///ystem.err.print(result);
350 result = Codec.transform(result, Codec.DOM_TO_TEXT);
351 ///ystem.err.println(" -> D2T decode -> " + result);
352 break;
353 default:
354 ///ystem.err.println(result + " -> nothing to do.");
355 }
356 }
357 else if(name.equals("AssignedValues")) {
358 result = getMetadataElementName();
359 }
360 return result;
361 }
362
363 private void map() {
364 children = new Vector();
365 for(Node node = getElement().getFirstChild(); node != null; node = node.getNextSibling()) {
366 if(node.getNodeName().equals("Subject")) {
367 GValueNode child = new GValueNode((Element)node);
368 child.setParent(this);
369 children.add(child);
370 }
371 }
372 }
373
374 /** Removes the child at index from the receiver. */
375 public void remove(int index) {
376 remove((MutableTreeNode)getChildAt(index));
377 }
378
379 /** Removes node from the receiver. */
380 public void remove(MutableTreeNode node) {
381 children.remove(node);
382 node.setParent(null);
383 // Remove from DOM
384 Element child_element = ((GValueNode)node).getElement();
385 Node parent_node = child_element.getParentNode();
386 parent_node.removeChild(child_element);
387 }
388
389 /** Removes the receiver from its parent. */
390 public void removeFromParent() {
391 if(parent != null) {
392 parent.remove(this);
393 }
394 }
395
396 private void setNodeValue(String name, String value) {
397 boolean found = false;
398 // Attempt to retrieve a child node named name
399 Element element = (Element) userObject;
400 for(Node pos_node = element.getFirstChild(); pos_node != null; pos_node = pos_node.getNextSibling()) {
401 // And if we find such a node
402 if(pos_node.getNodeName().equals(name)) {
403 // And the new value is non-null, retrieve its text node and change it.
404 if(value != null) {
405 for(Node pos_text = pos_node.getFirstChild(); pos_text != null; pos_text = pos_text.getNextSibling()) {
406 // When we find the node...
407 if(pos_text.getNodeName().equals("#text")) {
408 pos_text.setNodeValue(value);
409 }
410 }
411 }
412 // Otherwise remove the node altogether
413 else {
414 element.removeChild(pos_node);
415 }
416 found = true;
417 }
418 }
419 // Otherwise if no such node exists add it.
420 if(!found && value != null) {
421 Document document = element.getOwnerDocument();
422 Node new_node = document.createElementNS("", name);
423 element.appendChild(new_node);
424 Node new_text = document.createTextNode(value);
425 new_node.appendChild(new_text);
426 new_text = null;
427 new_node = null;
428 }
429 // Done.
430 element = null;
431 return;
432 }
433}
Note: See TracBrowser for help on using the repository browser.