package jas2.util.tree;

import java.util.*;

/**
 * A simple node represents a node in a tree. Each node has a number of properties:
 * 
  • *
      Name: The name of the node *
        Type: The type of the node *
          Flags: A set of flags associated with the node *
            Object: An object associated with the node * * SimpleNode contains a number of methods for making it easy to use TreeItems to * build the tree. It is also possible to add a NodeListener to any node of the tree, * and this will be informed of all changes (additions and deletions) below that node. * Within a node, children are kept in a OrderedHashmap, which keeps items ordered by * insertion order, and also enables nodes to be rapidly looked up by name. * * */ public class SimpleNode { /** * Create a root node, with no name, type or flag */ public SimpleNode() // create a root node { flags = 0; type = null; parent = null; name = null; } /** * Create a root node * @param name The name of the node * @param type The type of the node * @param object The Object associated with the node */ public SimpleNode(String name, String type, int flags, Object object) { this.parent = null; this.name = name; this.type = type; this.flags = flags; this.object = object; } /** * Create a node * @param parent The parent of this node * @param name The name of the node * @param type The type of the node * @param object The Object associated with the node */ public SimpleNode(SimpleNode parent, String name, String type, int flags, Object object) { this.parent = parent; this.name = name; this.type = type; this.flags = flags; this.object = object; parent.addChild(this); } /** * Called to create a node when adding a TreeItem to the tree. Can be overriden * by subclasses to create their own type of SimpleNode. */ protected SimpleNode createNode(SimpleNode parent, String name, String type, int flags, Object object) { return new SimpleNode(parent,name,type,flags,object); } protected void addChild(SimpleNode child) { // BUG: What if a child with this name already exists?? // Is the caller responsible for removing it first, in which case this class // should throw an exception, or should this class treat add as replace if the name // is already is use?? if (children == null) children = new FlashVector(); children.put(child); child.treeChanged(0); } protected void removeChild(SimpleNode child) { child.treeChanged(TreeItem.DELETED); children.remove(child); } protected void renameChild(SimpleNode child, String newName) { // TODO: Need more informative message for this to work in remote case // The messages which are currently sent to update the slave tree are // instances of TreeItem. This is inadequate because items are only // specified by name, meaning // a) There is no way to have two items with the same name // b) No way to perform a rename operation // For now rename is represented as a remove followed by an add child.treeChanged(TreeItem.DELETED); children.remove(child); child.name = newName; children.put(child); child.treeChanged(0); } protected void treeChanged(int extraFlags) { SimpleNode n = this.parent; for (int depth=1; n != null ; depth++) { if (n.listener != null) { String[] path = new String[depth]; SimpleNode c = this; for (int j=depth-1; j>=0; j--) { path[j] = c.name; c = c.parent; } n.fireTreeChanged(new TreeItem(path,type,flags | extraFlags)); } n = n.parent; } } /** * Get a TreeItem describing this node, relative to a base node * @param base The base node * @return The TreeItem describing the relative path */ public TreeItem getTreeItem(SimpleNode base) { int depth; SimpleNode n = this; for (depth = 0; n != base; depth++) n = n.parent; String[] path = new String[depth]; n = this; for (int j=depth-1; j>=0; j--) { path[j] = n.name; n = n.parent; } return new TreeItem(path,type,flags); } /** * Find a child node with a given name * @param name The name to search for * @return The child node, or null of no node was found by the given name */ public SimpleNode findChild(String name) { if (children == null) return null; return children.get(name); } /** * Destroy a node (remove it from its parents list of children) * No further use of a node or its chilren should be made after it has been destroyed */ public void destroy() { parent.removeChild(this); children = null; //help garbage collector // Maybe we should also destroy our children, to help out the gc even more? } /** * Add a node specified by a TreeItem. The path in the TreeItem is interpreted * as relavive to the current node, and any intervening nodes specified by the * path are created automatically as needed. * @param item The subnode to add * @return The leaf node created */ public SimpleNode add(TreeItem item) { return add(item,null); } /** * Add a node specified by a TreeItem, with an associated object. The path in the TreeItem is interpreted * as relavive to the current node, and any intervening nodes specified by the * path are created automatically as needed. * @param item The subnode to add * @param object The associated object * @return The leaf node created */ public SimpleNode add(TreeItem item, Object object) { SimpleNode parent = this; int l = item.path.length; for (int i=0; i=0; j--) { path[j] = c.name; c = c.parent; } TreeItem item = new TreeItem(path,type,flags); object = tos.getItem(new TreeItem(path,type,flags)); break; } n = n.parent; } } return object; } public void setFlags(int mask) { int newFlags = flags | mask; if (newFlags != flags) { flags = newFlags; treeChanged(0); } } public void clearFlags(int mask) { int newFlags = flags & ~mask; if (newFlags != flags) { flags = newFlags; treeChanged(0); } } public boolean isAncestorOf(SimpleNode root) { for (SimpleNode search = this; search != null; search = search.parent) if (search == root) return true; return false; } public String getType() { return type; } public int getFlags() { return flags; } public String getName() { return name; } public SimpleNode getParent() { return parent; } public void addNodeListener(SimpleNodeListener l) { if (listener == null) listener = new java.util.Vector(); listener.addElement(l); } public void removeNodeListener(SimpleNodeListener l) { if (listener != null) listener.removeElement(l); } private void fireTreeChanged(TreeItem item) { Enumeration e = listener.elements(); while (e.hasMoreElements()) { SimpleNodeListener l = (SimpleNodeListener) e.nextElement(); l.treeChanged(item); } } public String toString() { return name; } private java.util.Vector listener; private int flags; private String name; private String type; private SimpleNode parent; /** * Note, since many nodes are leaves, the children map is not created until * at least one child is added. */ protected FlashVector children; protected Object object; protected final static Enumeration nullEnumeration = new java.util.Vector().elements(); /** * The FlashVector class is used to keep children in insertion order, but also to * allow them to be looked up efficiently by name. It also provides an efficient * implementation of indexOf() */ static class FlashVector { void put(SimpleNode node) { vector.add(node); if (flash != null) flash.put(node.name,vector.size()-1); } void remove(SimpleNode node) { if (flash != null) vector.remove(flash.get(node.name)); else vector.remove(node); flash = null; } SimpleNode get(String name) { if (flash == null) fillFlash(); int index = flash.get(name); return index<0 ? null : (SimpleNode) vector.get(index); } SimpleNode elementAt(int index) { return (SimpleNode) vector.get(index); } int indexOf(SimpleNode node) { if (flash == null) fillFlash(); return flash.get(node.name); } int size() { return vector.size(); } //Enumeration elements() //{ // return vector.elements(); //} Collection elements() { return Collections.unmodifiableCollection(vector); } private void fillFlash() { int s = vector.size(); flash = new Flash(s); for (int i=0; i threshold) rehash(); int hash = Math.abs(name.hashCode())%array.length; while (array[hash] != 0) hash = (hash+1)%array.length; array[hash] = index+1; // Add one to avoid 0, which is used for empty node } private void rehash() { int newLength = array.length*2 + 1; int[] newArray = new int[newLength]; threshold = newLength/2; for (int i=0; i
  • Ads help maintain this website.