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 | */
|
---|
37 |
|
---|
38 |
|
---|
39 |
|
---|
40 |
|
---|
41 |
|
---|
42 |
|
---|
43 | package org.greenstone.gatherer.valuetree;
|
---|
44 | /**
|
---|
45 | * Title: The Gatherer<br>
|
---|
46 | * Description: The Gatherer: a tool for gathering and enriching digital collections.<br>
|
---|
47 | * Copyright: Copyright (c) 2001<br>
|
---|
48 | * Company: The University of Waikato<br>
|
---|
49 | * First Coded: 20/06/02
|
---|
50 | * Revised:<br>
|
---|
51 | * @author John Thompson, Greenstone Digital Libraries
|
---|
52 | * @version 2.1
|
---|
53 | */
|
---|
54 | import java.util.Collections;
|
---|
55 | import java.util.Enumeration;
|
---|
56 | import java.util.HashMap;
|
---|
57 | import java.util.Hashtable;
|
---|
58 | import java.util.Vector;
|
---|
59 | import javax.swing.tree.DefaultMutableTreeNode;
|
---|
60 | import javax.swing.tree.TreeNode;
|
---|
61 | import javax.swing.tree.TreePath;
|
---|
62 | import javax.swing.tree.MutableTreeNode;
|
---|
63 | import org.greenstone.gatherer.Gatherer;
|
---|
64 | import org.greenstone.gatherer.msm.ElementWrapper;
|
---|
65 | import org.greenstone.gatherer.msm.MSMUtils;
|
---|
66 | import org.greenstone.gatherer.util.Utility;
|
---|
67 | import org.w3c.dom.Document;
|
---|
68 | import org.w3c.dom.Element;
|
---|
69 | import org.w3c.dom.Node;
|
---|
70 | import org.w3c.dom.NodeList;
|
---|
71 | /** 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.
|
---|
72 | */
|
---|
73 | public class GValueNode
|
---|
74 | extends DefaultMutableTreeNode {
|
---|
75 | private String element_name = null;
|
---|
76 | private String default_value = null;
|
---|
77 | public GValueNode(Element element) {
|
---|
78 | this.children = null;
|
---|
79 | this.userObject = element;
|
---|
80 | this.default_value = null;
|
---|
81 | }
|
---|
82 |
|
---|
83 | public GValueNode(String element_name, String default_value) {
|
---|
84 | this.element_name = element_name;
|
---|
85 | this.default_value = default_value;
|
---|
86 | }
|
---|
87 | /** Compares two GValueNodes for ordering by using the String.compareTo method.
|
---|
88 | * @param sibling The <strong>Object</strong> representing the GValueNode we are comparing ourselves to.
|
---|
89 | * @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.
|
---|
90 | */
|
---|
91 | public int compareTo(Object sibling) {
|
---|
92 | return toString().compareTo(sibling.toString());
|
---|
93 | }
|
---|
94 | /** Determine if this tree node contains a child with a matching value.
|
---|
95 | * @param value The value we are attempting to match, as a <strong>String</strong>.
|
---|
96 | * @return <i>true</i> if there is a matching child node, <i>false</i> otherwise.
|
---|
97 | */
|
---|
98 | public boolean containsValue(String value) {
|
---|
99 | if(default_value != null) {
|
---|
100 | return false;
|
---|
101 | }
|
---|
102 | return getValue(value) != null;
|
---|
103 | }
|
---|
104 | /** Returns an enumeration of the child nodes.
|
---|
105 | * @return An <strong>Enumeration</strong> containing the child nodes.
|
---|
106 | */
|
---|
107 | public Enumeration children() {
|
---|
108 | if(default_value != null) {
|
---|
109 | return null;
|
---|
110 | }
|
---|
111 | if(children == null) {
|
---|
112 | map();
|
---|
113 | }
|
---|
114 | return children.elements();
|
---|
115 | }
|
---|
116 | public boolean equals(Object other) {
|
---|
117 | return compareTo(other) == 0;
|
---|
118 | }
|
---|
119 |
|
---|
120 | public GValueNode get(int index) {
|
---|
121 | GValueNode result = null;
|
---|
122 | if(children != null) {
|
---|
123 | result = (GValueNode) children.get(index);
|
---|
124 | }
|
---|
125 | return result;
|
---|
126 | }
|
---|
127 |
|
---|
128 | public String getAlias() {
|
---|
129 | // Attempt to retrieve a child node named Alias
|
---|
130 | Element element = (Element) userObject;
|
---|
131 | for(Node pos_node = element.getFirstChild(); pos_node != null; pos_node = pos_node.getNextSibling()) {
|
---|
132 | // And if we find such a node
|
---|
133 | if(pos_node.getNodeName().equals("Alias")) {
|
---|
134 | // Retrieve its text node
|
---|
135 | for(Node pos_text = pos_node.getFirstChild(); pos_text != null; pos_text = pos_text.getNextSibling()) {
|
---|
136 | // When we find the node return its value
|
---|
137 | if(pos_text.getNodeName().equals("#text")) {
|
---|
138 | return pos_text.getNodeValue();
|
---|
139 | }
|
---|
140 | }
|
---|
141 | }
|
---|
142 | }
|
---|
143 | return "";
|
---|
144 | }
|
---|
145 |
|
---|
146 | public String getAlias(String index) {
|
---|
147 | return index;
|
---|
148 | }
|
---|
149 |
|
---|
150 | /** Returns <I>true</I> if the reciever allows children. */
|
---|
151 | public boolean getAllowsChildren() {
|
---|
152 | return true;
|
---|
153 | }
|
---|
154 |
|
---|
155 | /** Returns the child <I>TreeNode</I> at index <I>childIndex</I>.*/
|
---|
156 | public TreeNode getChildAt(int index) {
|
---|
157 | GValueNode result = null;
|
---|
158 | if(default_value != null) {
|
---|
159 | return this;
|
---|
160 | }
|
---|
161 | else {
|
---|
162 | if(children == null) {
|
---|
163 | map();
|
---|
164 | }
|
---|
165 | for(int i = 0; index >= 0 && i < children.size(); i++) {
|
---|
166 | GValueNode child = (GValueNode) children.get(i);
|
---|
167 | if(child.getEnabled()) {
|
---|
168 | result = child;
|
---|
169 | index--;
|
---|
170 | }
|
---|
171 | }
|
---|
172 | }
|
---|
173 | return result;
|
---|
174 | }
|
---|
175 | /** Returns the number of children <I>TreeNode</I>s the reciever contains. */
|
---|
176 | public int getChildCount() {
|
---|
177 | int size = 0;
|
---|
178 | if(default_value != null) {
|
---|
179 | size = 0;
|
---|
180 | }
|
---|
181 | else {
|
---|
182 | if(children == null) {
|
---|
183 | map();
|
---|
184 | }
|
---|
185 | for(int i = 0; i < children.size(); i++) {
|
---|
186 | GValueNode child = (GValueNode) children.get(i);
|
---|
187 | if(child.getEnabled()) {
|
---|
188 | size++;
|
---|
189 | }
|
---|
190 | }
|
---|
191 | }
|
---|
192 | return size;
|
---|
193 | }
|
---|
194 | public Element getElement() {
|
---|
195 | return (Element) userObject;
|
---|
196 | }
|
---|
197 | public boolean getEnabled() {
|
---|
198 | return !(((Element)userObject).getAttribute("enabled").equals("false"));
|
---|
199 | }
|
---|
200 |
|
---|
201 | /** Return the path to this node within the value tree model.
|
---|
202 | * @return A <strong>String</strong> representing the path, ie "Titles\Modern\The Green Mile"
|
---|
203 | */
|
---|
204 | public String getFullPath() {
|
---|
205 | if(default_value != null) {
|
---|
206 | return default_value;
|
---|
207 | }
|
---|
208 | StringBuffer path = new StringBuffer(toString());
|
---|
209 | GValueNode node = (GValueNode) getParent();
|
---|
210 | while(node != null && !node.getElement().getNodeName().equalsIgnoreCase("AssignedValues")) {
|
---|
211 | path.insert(0, "\\");
|
---|
212 | path.insert(0, node.toString());
|
---|
213 | node = (GValueNode) node.getParent();
|
---|
214 | }
|
---|
215 | return path.toString();
|
---|
216 | }
|
---|
217 |
|
---|
218 | /** Returns the index of <I>node</I> in the recievers children. If the
|
---|
219 | * reciever does not contain <I>node</I>, <I>-1</I> will be returned. */
|
---|
220 | public int getIndex(TreeNode node) {
|
---|
221 | if(default_value != null) {
|
---|
222 | return 0;
|
---|
223 | }
|
---|
224 | if(children == null) {
|
---|
225 | map();
|
---|
226 | }
|
---|
227 | return children.indexOf(node);
|
---|
228 | }
|
---|
229 |
|
---|
230 | public String getMetadataElementName() {
|
---|
231 | if(default_value != null) {
|
---|
232 | return element_name;
|
---|
233 | }
|
---|
234 | GValueNode node = this;
|
---|
235 | while(node != null && !node.getElement().getNodeName().equalsIgnoreCase("AssignedValues")) {
|
---|
236 | node = (GValueNode)node.getParent();
|
---|
237 | }
|
---|
238 | if(node != null) {
|
---|
239 | return node.getElement().getAttribute("element");
|
---|
240 | }
|
---|
241 | return null;
|
---|
242 | }
|
---|
243 |
|
---|
244 | public GValueNode getValue(String value) {
|
---|
245 | if(default_value != null) {
|
---|
246 | return this;
|
---|
247 | }
|
---|
248 | if(children == null) {
|
---|
249 | map();
|
---|
250 | }
|
---|
251 | GValueNode result = null;
|
---|
252 | for(int i = 0; result == null && i < children.size(); i++) {
|
---|
253 | Object child = children.get(i);
|
---|
254 | if(child.toString().equals(value)) {
|
---|
255 | result = (GValueNode) child;
|
---|
256 | }
|
---|
257 | }
|
---|
258 | return result;
|
---|
259 | }
|
---|
260 |
|
---|
261 | /** Adds <I>child</I> to the receiever at <I>index</I>. <I>child</I> will
|
---|
262 | * be messaged with setParent().
|
---|
263 | */
|
---|
264 | public void insert(MutableTreeNode child, int index) {
|
---|
265 | if(default_value != null) {
|
---|
266 | return;
|
---|
267 | }
|
---|
268 | if(index >= children.size()) {
|
---|
269 | // Append to children.
|
---|
270 | children.add(child);
|
---|
271 | // And to document
|
---|
272 | getElement().appendChild(((GValueNode)child).getElement());
|
---|
273 | }
|
---|
274 | else {
|
---|
275 | GValueNode sibling = (GValueNode) children.get(index);
|
---|
276 | // Insert in children
|
---|
277 | children.add(index, child);
|
---|
278 | // And in document
|
---|
279 | getElement().insertBefore(((GValueNode)child).getElement(), sibling.getElement());
|
---|
280 | }
|
---|
281 | child.setParent(this);
|
---|
282 | }
|
---|
283 | /** Returns <I>true</I> if the reciever is a leaf. */
|
---|
284 | public boolean isLeaf() {
|
---|
285 | if(default_value != null || getChildCount() > 0) {
|
---|
286 | return false;
|
---|
287 | }
|
---|
288 | return true;
|
---|
289 | }
|
---|
290 |
|
---|
291 | /** Ensure that the children nodes of this tree are instantiated, and record the initial mappings for legacy sake.
|
---|
292 | * @param mapping A <strong>HashMap</strong> into which to write the initial mappings.
|
---|
293 | * @param prefix The prefix to use for indexes, as a <strong>String</strong>.
|
---|
294 | */
|
---|
295 | public void map(HashMap mapping, String prefix) {
|
---|
296 | if(default_value != null) {
|
---|
297 | return;
|
---|
298 | }
|
---|
299 | children = new Vector();
|
---|
300 | if(prefix.length() > 0) {
|
---|
301 | prefix = prefix + ".";
|
---|
302 | }
|
---|
303 | int i = 1;
|
---|
304 | for(Node node = getElement().getFirstChild(); node != null; node = node.getNextSibling()) {
|
---|
305 | if(node.getNodeName().equals("Subject")) {
|
---|
306 | GValueNode child = new GValueNode((Element)node);
|
---|
307 | child.setParent(this);
|
---|
308 | children.add(child);
|
---|
309 | String index = prefix + i;
|
---|
310 | mapping.put(index, child);
|
---|
311 | child.map(mapping, index);
|
---|
312 | i++;
|
---|
313 | }
|
---|
314 | }
|
---|
315 | }
|
---|
316 |
|
---|
317 | /** Removes the child at <I>index</I> from the reciever. */
|
---|
318 | public void remove(int index) {
|
---|
319 | // Can't ever remove Elements from here. Have to use editor. */
|
---|
320 | }
|
---|
321 |
|
---|
322 | /** Removes <I>node</I> from the reciever. <I>setParent</I> will be
|
---|
323 | * messaged on node.
|
---|
324 | */
|
---|
325 | public void remove(MutableTreeNode node) {
|
---|
326 | // Can't ever remove Elements from here. Have to use editor. */
|
---|
327 | }
|
---|
328 |
|
---|
329 | /** Removes the reciever from its parent. */
|
---|
330 | public void removeFromParent() {
|
---|
331 | // Can't ever remove Elements from here. Have to use editor. */
|
---|
332 | }
|
---|
333 |
|
---|
334 | public void setAlias(String alias) {
|
---|
335 | setNodeValue("Alias", alias);
|
---|
336 | }
|
---|
337 |
|
---|
338 | public void setEnabled(boolean state) {
|
---|
339 | Element element = (Element) userObject;
|
---|
340 | if(state) {
|
---|
341 | element.setAttribute("enabled", "true");
|
---|
342 | }
|
---|
343 | else {
|
---|
344 | element.setAttribute("enabled", "false");
|
---|
345 | }
|
---|
346 | }
|
---|
347 |
|
---|
348 | /** Resets the user object of the reciever to <I>object</I>. */
|
---|
349 | public void setUserObject(Object object) {
|
---|
350 | // Can't ever change Elements from here. Have to use editor. */
|
---|
351 | }
|
---|
352 |
|
---|
353 | public void setValue(String value) {
|
---|
354 | setNodeValue("Value", value);
|
---|
355 | }
|
---|
356 |
|
---|
357 | public int size() {
|
---|
358 | int size = 0;
|
---|
359 | if(children != null) {
|
---|
360 | size = children.size();
|
---|
361 | }
|
---|
362 | return size;
|
---|
363 | }
|
---|
364 |
|
---|
365 | /** Returns a <I>String</I> representation of the reciever. If this
|
---|
366 | * happens to be the AssignedValues 'root' then we do something slightly
|
---|
367 | * different, otherwise we return the value of the <I>#Text</I> child of
|
---|
368 | * the <I>Value</I> of this <I>Subject</I> node!
|
---|
369 | */
|
---|
370 | public String toString() {
|
---|
371 | if(default_value != null) {
|
---|
372 | return default_value;
|
---|
373 | }
|
---|
374 | Element element = getElement();
|
---|
375 | String name = element.getNodeName();
|
---|
376 | String result = null;
|
---|
377 | if(name.equals("Subject")) {
|
---|
378 | result = MSMUtils.getValue(element);
|
---|
379 | }
|
---|
380 | else if(name.equals("AssignedValues")) {
|
---|
381 | result = getMetadataElementName();
|
---|
382 | }
|
---|
383 | return Utility.stripNL(result);
|
---|
384 | }
|
---|
385 |
|
---|
386 | public void unmap() {
|
---|
387 | children = null;
|
---|
388 | }
|
---|
389 |
|
---|
390 | private void map() {
|
---|
391 | children = new Vector();
|
---|
392 | for(Node node = getElement().getFirstChild(); node != null; node = node.getNextSibling()) {
|
---|
393 | if(node.getNodeName().equals("Subject")) {
|
---|
394 | GValueNode child = new GValueNode((Element)node);
|
---|
395 | child.setParent(this);
|
---|
396 | children.add(child);
|
---|
397 | }
|
---|
398 | }
|
---|
399 | }
|
---|
400 |
|
---|
401 | private void setNodeValue(String name, String value) {
|
---|
402 | boolean found = false;
|
---|
403 | // Attempt to retrieve a child node named name
|
---|
404 | Element element = (Element) userObject;
|
---|
405 | for(Node pos_node = element.getFirstChild(); pos_node != null; pos_node = pos_node.getNextSibling()) {
|
---|
406 | // And if we find such a node
|
---|
407 | if(pos_node.getNodeName().equals(name)) {
|
---|
408 | // And the new value is non-null, retrieve its text node and change it.
|
---|
409 | if(value != null) {
|
---|
410 | for(Node pos_text = pos_node.getFirstChild(); pos_text != null; pos_text = pos_text.getNextSibling()) {
|
---|
411 | // When we find the node...
|
---|
412 | if(pos_text.getNodeName().equals("#text")) {
|
---|
413 | pos_text.setNodeValue(value);
|
---|
414 | }
|
---|
415 | }
|
---|
416 | }
|
---|
417 | // Otherwise remove the node altogether
|
---|
418 | else {
|
---|
419 | element.removeChild(pos_node);
|
---|
420 | }
|
---|
421 | found = true;
|
---|
422 | }
|
---|
423 | }
|
---|
424 | // Otherwise if no such node exists add it.
|
---|
425 | if(!found && value != null) {
|
---|
426 | Document document = element.getOwnerDocument();
|
---|
427 | Node new_node = document.createElementNS("", name);
|
---|
428 | element.appendChild(new_node);
|
---|
429 | Node new_text = document.createTextNode(value);
|
---|
430 | new_node.appendChild(new_text);
|
---|
431 | new_text = null;
|
---|
432 | new_node = null;
|
---|
433 | }
|
---|
434 | // Done.
|
---|
435 | element = null;
|
---|
436 | return;
|
---|
437 | }
|
---|
438 | }
|
---|
439 |
|
---|
440 |
|
---|
441 |
|
---|
442 |
|
---|