/** *######################################################################### * * A component of the Gatherer application, part of the Greenstone digital * library suite from the New Zealand Digital Library Project at the * University of Waikato, New Zealand. * * Author: John Thompson, Greenstone Digital Library, University of Waikato * * Copyright (C) 1999 New Zealand Digital Library Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *######################################################################## */ package org.greenstone.gatherer.valuetree; import java.util.*; import javax.swing.tree.*; import org.greenstone.gatherer.Gatherer; import org.greenstone.gatherer.msm.ElementWrapper; import org.greenstone.gatherer.msm.MSMUtils; import org.greenstone.gatherer.util.PatternTokenizer; import org.greenstone.gatherer.util.Utility; import org.w3c.dom.*; /* * @author John Thompson, Greenstone Digital Library, University of Waikato * @version 2.1 */ public class GValueModel extends DefaultTreeModel { static final public String PATH_SEP = "\\\\"; static final public String PATH_SEP_PATTERN = "\\\\\\\\"; private ElementWrapper element; public GValueModel() { super(new DefaultMutableTreeNode("Temp")); } public GValueModel(String root) { super(new DefaultMutableTreeNode(root)); } public GValueModel(ElementWrapper e) { super(new DefaultMutableTreeNode("Temp")); this.element = e; // Load the template value tree document. Document document = MSMUtils.getValueTreeTemplate(); Element new_root = document.getDocumentElement(); new_root.setAttribute("element", e.getName()); root = new GValueNode(new_root); } public GValueModel(ElementWrapper e, Document document) { super(new DefaultMutableTreeNode("Temp")); this.element = e; Element new_root = document.getDocumentElement(); new_root.setAttribute("element", e.getName()); root = new GValueNode(new_root); } /** Value may include path ie news\newssw */ public GValueNode addValue(String value) { try { // Tokenize the string using the escaped character PatternTokenizer tokenizer = new PatternTokenizer(value, PATH_SEP); GValueNode subject = (GValueNode) root; while(tokenizer.hasMoreTokens() && subject != null) { String token = tokenizer.nextToken(); subject = addValue(token, subject, null); } return subject; } catch (Exception error) { error.printStackTrace(); } return null; } public GValueNode addValue(String value, GValueNode subject, String alias) { // To add a value we must first ensure it isn't already present in -this- nodes children. The bummer is that the nice getElements functions search the whole tree so... GValueNode value_node = subject.getValue(value); if(value_node == null) { // Now add the new value. Document document = subject.getElement().getOwnerDocument(); // Now we create a new subject and add it subject Element new_subject = document.createElementNS("","Subject"); Element new_value = document.createElementNS("","Value"); new_subject.appendChild(new_value); Text new_text = document.createTextNode(value); new_value.appendChild(new_text); if(alias != null && alias.length() > 0) { Element new_alias = document.createElementNS("","Alias"); new_subject.appendChild(new_alias); Text new_alias_text = document.createTextNode(alias); new_alias.appendChild(new_alias_text); } value_node = new GValueNode(new_subject); ///ystem.err.println("(GValueModel) addValue()... " + value_node); // Figure out where this node will be inserted in subjects // children. int position = -1; for(int i = 0; position == -1 && i < subject.getChildCount(); i++) { Object sibling = subject.getChildAt(i); int rel_pos = value.compareTo(sibling.toString()); ///ystem.err.println("'"+value+"'.compareTo('"+sibling+"') = " + rel_pos); if(rel_pos <= 0) { position = i; } } if(position == -1) { position = subject.getChildCount(); } // Insert it. If position is still -1, append it to the end of subjects children. ///ystem.err.println("Inserting '" + value + "' at position " + position); insertNodeInto(value_node, subject, position); ///ystem.err.println("(GValueModel) Done insert node into..."); // SynchronizedTreeModelTools.insertNodeInto(this, subject, value_node); // Inform listeners that we've changed. Gatherer.c_man.getCollection().msm.fireValueChanged(element, null, this); } return value_node; } public Document getDocument() { return ((GValueNode)root).getElement().getOwnerDocument(); } public ElementWrapper getElement() { return element; } /** Retrieve the hindex for a certain value within the value tree. * @param value The value whose index you wish to determine as a String. * @return A String containing an index such as "1", "2.1" or "18.2.5". */ public String getHIndex(String value) { ///ystem.err.println("getHIndex(" + value + ")"); return getHIndex((GValueNode) root, value, null); } /** Retrieve a value node given its hierarchical reference or value. * @param index The hierarchy index or value as a String. */ public GValueNode getValue(String index_str) { ///ystem.err.println("Retrieve the value for: " + index_str); GValueNode result = null; if(isHierarchy() && Utility.isIndex(index_str)) { // StringTokenize the index StringTokenizer tokenizer = new StringTokenizer(index_str, "."); result = (GValueNode) root; // Using the index numbers retrieve the appropriate node. try { while(result != null && tokenizer.hasMoreTokens()) { int index = Integer.parseInt(tokenizer.nextToken()) - 1; // Retrieve the index'th child of the current result node if(0 <= index && index < result.getChildCount()) { result = (GValueNode) result.getChildAt(index); } // Otherwise we're broken. else { ///ystem.err.println("There is no " + index + "th childnode of " + result); result = null; } } } // Most likely caused by parseInt throwing a wobbly. catch (Exception error) { result = null; } } if(result == null) { ///ystem.err.println("No existing value. Adding " + index_str); result = addValue(index_str); } return result; } public boolean isHierarchy() { boolean result = false; // We are a hierarchy if our element says so.... if(element.isHierarchy()) { return true; } // Or if our children are actually a hierarchy. for(int i = 0; i < root.getChildCount() && !result; i++) { GValueNode node = (GValueNode) root.getChildAt(i); if(node != null && node.getChildCount() > 0) { result = true; } } return result; } public void removeValue(GValueNode child) { //SynchronizedTreeModelTools.removeNodeFromParent(this, child); removeNodeFromParent(child); Gatherer.c_man.getCollection().msm.fireValueChanged(new ElementWrapper(child.getElement()), null, this); } public void removeValue(String value) { // Retrieve the node to be removed. GValueNode node = getValue(value); if(node != null) { removeValue(node); } } public int size() { return size(root); } private int size(TreeNode current) { int size = 1; for(int i = 0; i < current.getChildCount(); i++) { size = size + size(current.getChildAt(i)); } return size; } public String toString() { return element.toString(); } public Vector traverseTree() { Vector contents = new Vector(); contents.addAll(traverseTree((GValueNode) root)); contents.remove((GValueNode) root); return contents; } /** Called to update a certain value of metadata within a specific * subject within a sbject hierarchy. * Note that this simply in turn calls removeValue() to deal with the * old value, then addValue() to account for the new. * @param new_value A String representing the updated value. * @param old_value A String representing the old value. * @param subject An Element representing the subject you wish to update * this value in. */ public GValueNode updateValue(String new_value, String old_value, GValueNode subject) { return addValue(new_value, subject, null); } private GValueModel copy() { Element document_element = ((GValueNode) root).getElement(); Document document_copy = MSMUtils.getValueTreeTemplate(); Element document_copy_element = document_copy.getDocumentElement(); document_copy_element.setAttribute("element", element.getName()); for(Node node = document_element.getFirstChild(); node != null; node = node.getNextSibling()) { if(node.getNodeName().equals("Subject")) { Node node_copy = document_copy.importNode(node, true); document_copy_element.appendChild(node_copy); } } return new GValueModel(element, document_copy); } private String getHIndex(GValueNode node, String value, String index) { for(int i = node.size(); i != 0; i--) { GValueNode next = (GValueNode)node.get(i - 1); String next_str = next.toString(); if(value.startsWith(next_str)) { if(index == null) { index = String.valueOf(i); } else { index = index + "." + i; } value = value.substring(next.toString().length()); if(value.startsWith(PATH_SEP)) { value = value.substring(2); index = getHIndex(next, value, index); } return index; } } return index; } private Vector traverseTree(GValueNode node) { Vector contents = new Vector(); contents.add(node); for(int i = 0; i < node.getChildCount(); i++) { contents.addAll(traverseTree((GValueNode)node.getChildAt(i))); } return contents; } }