pbwest 2002/10/24 07:16:53 Modified: src/org/apache/fop/datastructs Tag: FOP_0-20-0_Alt-Design Tree.java Log: Tabs detected! Untabified. Revision Changes Path No revision No revision 1.1.2.2 +881 -881 xml-fop/src/org/apache/fop/datastructs/Attic/Tree.java Index: Tree.java =================================================================== RCS file: /home/cvs/xml-fop/src/org/apache/fop/datastructs/Attic/Tree.java,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -u -r1.1.2.1 -r1.1.2.2 --- Tree.java 7 May 2002 04:37:53 -0000 1.1.2.1 +++ Tree.java 24 Oct 2002 14:16:53 -0000 1.1.2.2 @@ -63,48 +63,48 @@ public Tree() {} public int modified() { - // In the Tree class, this function updates the modCount - // N.B. This method is always called from within a synchronized - // method. - synchronized (this) { - return ++modCount; - } + // In the Tree class, this function updates the modCount + // N.B. This method is always called from within a synchronized + // method. + synchronized (this) { + return ++modCount; + } } public int getModCount() { - synchronized (this) { - return modCount; - } + synchronized (this) { + return modCount; + } } public boolean modCountEqualTo(int value) { - synchronized (this) { - return value == modCount; - } + synchronized (this) { + return value == modCount; + } } public int size() { - return nodeCount; + return nodeCount; } public boolean isEmpty() { - return nodeCount == 0; + return nodeCount == 0; } public Node getRoot() { - return root; + return root; } public void unsetRoot() { - root = null; + root = null; } public class TreeException extends Exception { - public TreeException(String message) { - super(message); - } - + public TreeException(String message) { + super(message); + } + } /** @@ -138,165 +138,165 @@ public class Node implements Cloneable { - private Node parent; - private ArrayList children; // ArrayList of Node + private Node parent; + private ArrayList children; // ArrayList of Node //protected Object content; - /** - * No argument constructor. - * - * Assumes that this node is the root, and so will throw a - * <tt>TreeException</tt> when the root node in the enclosing - * <tt>Tree</tt> object is non-null. - */ - - public Node() - throws TreeException { - if (Tree.this.root != null) { - throw new TreeException( - "No arg constructor invalid when root exists"); - } - parent = null; - Tree.this.root = this; - children = new ArrayList(); + /** + * No argument constructor. + * + * Assumes that this node is the root, and so will throw a + * <tt>TreeException</tt> when the root node in the enclosing + * <tt>Tree</tt> object is non-null. + */ + + public Node() + throws TreeException { + if (Tree.this.root != null) { + throw new TreeException( + "No arg constructor invalid when root exists"); + } + parent = null; + Tree.this.root = this; + children = new ArrayList(); //content = null; - } + } - /** - * @param parent Node which is the parent of this Node. if this is - * null, the generated Node is assumed to be the root - * node. If the Tree root node is already set, throws - * a <tt>TreeException</tt>. - * @param index int index of child in parent. - */ - - public Node(Node parent, int index) - throws TreeException, IndexOutOfBoundsException { - children = new ArrayList(); + /** + * @param parent Node which is the parent of this Node. if this is + * null, the generated Node is assumed to be the root + * node. If the Tree root node is already set, throws + * a <tt>TreeException</tt>. + * @param index int index of child in parent. + */ + + public Node(Node parent, int index) + throws TreeException, IndexOutOfBoundsException { + children = new ArrayList(); //content = null; - if (parent == null) { - if (Tree.this.root != null) { - throw new TreeException("Null Node constructor " - + "invalid when root exists"); - } - this.parent = null; - Tree.this.root = this; - } - else { - // The parent must be a node in the current tree - if (parent.getTree() != Tree.this) { - throw new TreeException("Parent not in same tree"); - } - this.parent = parent; - // connect me to my parent - parent.addChild(index, this); - } - } - - /** - * @param parent Node which is the parent of this Node. if this is - * null, the generated Node is assumed to be the root - * node. If the Tree root node is already set, throws - * a <tt>TreeException</tt>. - */ - - public Node(Node parent) - throws TreeException, IndexOutOfBoundsException { - children = new ArrayList(); - //content = null; - if (parent == null) { - if (Tree.this.root != null) { - throw new TreeException("Null Node constructor " - + "invalid when root exists"); - } - this.parent = null; - Tree.this.root = this; - } - else { - // The parent must be a node in the current tree - if (parent.getTree() != Tree.this) { - throw new TreeException("Parent not in same tree"); - } - this.parent = parent; - // connect me to my parent - parent.addChild(this); - } - } - - - /** - * Appends a child <tt>Node</tt> to this node. Synchronized on the - * containing <tt>Tree</tt> object. - * - * Calls the <tt>modified</tt> method of the containing Tree to - * maintain the value of <tt>modCount</tt>. - * - * @param child Node to be added. - */ - - public void addChild(Node child) { - synchronized (Tree.this) { - children.add((Object) child); - Tree.this.modified(); - } - } - - /** - * Adds a child <tt>Node</tt> in this node at a specified index - * position. - * Synchronized on the containing <tt>Tree</tt> object. - * - * Calls the <tt>modified</tt> method of the containing Tree to - * maintain the value of <tt>modCount</tt>. - * - * @param index int position of new child - * @param child Node to be added. - */ - - public void addChild(int index, Node child) - throws IndexOutOfBoundsException { - synchronized (Tree.this) { - children.add(index, (Object) child); - Tree.this.modified(); - } - } - - /** - * Copies a subtree of this tree as a new child of this node. - * Synchronized on the containing <tt>Tree</tt> object. - * - * Calls the <tt>modified</tt> method of the containing Tree to - * maintain the value of <tt>modCount</tt>. - * - * Note that it is illegal to try to copy a subtree to one of - * its own descendents or itself. (This restriction could be lifted - * by creating a new Tree containing the subtree, and defining an - * attachTree() method to attach one Tree to another.) - * - * This is the public entry to copyCheckSubTree. It will always - * perform a check for the attempt to copy onto a descendent or - * self. It calls copyCheckSubTree. - * - * @param subtree Node at the root of the subtree to be added. - * @param index int index of child position in Node's children - */ - - public void copySubTree(Node subtree, int index) - throws TreeException, ConcurrentModificationException { - copyCheckSubTree(subtree, index, true); - } - - /** - * Copies a subtree of this tree as a new child of this node. - * Synchronized on the containing <tt>Tree</tt> object. - * - * Calls the <tt>modified</tt> method of the containing Tree to - * maintain the value of <tt>modCount</tt>. - * - * Note that it is illegal to try to copy a subtree to one of - * its own descendents or itself. (This restriction could be lifted - * by creating a new Tree containing the subtree, and defining an - * attachTree() method to attach one Tree to another.) + if (parent == null) { + if (Tree.this.root != null) { + throw new TreeException("Null Node constructor " + + "invalid when root exists"); + } + this.parent = null; + Tree.this.root = this; + } + else { + // The parent must be a node in the current tree + if (parent.getTree() != Tree.this) { + throw new TreeException("Parent not in same tree"); + } + this.parent = parent; + // connect me to my parent + parent.addChild(index, this); + } + } + + /** + * @param parent Node which is the parent of this Node. if this is + * null, the generated Node is assumed to be the root + * node. If the Tree root node is already set, throws + * a <tt>TreeException</tt>. + */ + + public Node(Node parent) + throws TreeException, IndexOutOfBoundsException { + children = new ArrayList(); + //content = null; + if (parent == null) { + if (Tree.this.root != null) { + throw new TreeException("Null Node constructor " + + "invalid when root exists"); + } + this.parent = null; + Tree.this.root = this; + } + else { + // The parent must be a node in the current tree + if (parent.getTree() != Tree.this) { + throw new TreeException("Parent not in same tree"); + } + this.parent = parent; + // connect me to my parent + parent.addChild(this); + } + } + + + /** + * Appends a child <tt>Node</tt> to this node. Synchronized on the + * containing <tt>Tree</tt> object. + * + * Calls the <tt>modified</tt> method of the containing Tree to + * maintain the value of <tt>modCount</tt>. + * + * @param child Node to be added. + */ + + public void addChild(Node child) { + synchronized (Tree.this) { + children.add((Object) child); + Tree.this.modified(); + } + } + + /** + * Adds a child <tt>Node</tt> in this node at a specified index + * position. + * Synchronized on the containing <tt>Tree</tt> object. + * + * Calls the <tt>modified</tt> method of the containing Tree to + * maintain the value of <tt>modCount</tt>. + * + * @param index int position of new child + * @param child Node to be added. + */ + + public void addChild(int index, Node child) + throws IndexOutOfBoundsException { + synchronized (Tree.this) { + children.add(index, (Object) child); + Tree.this.modified(); + } + } + + /** + * Copies a subtree of this tree as a new child of this node. + * Synchronized on the containing <tt>Tree</tt> object. + * + * Calls the <tt>modified</tt> method of the containing Tree to + * maintain the value of <tt>modCount</tt>. + * + * Note that it is illegal to try to copy a subtree to one of + * its own descendents or itself. (This restriction could be lifted + * by creating a new Tree containing the subtree, and defining an + * attachTree() method to attach one Tree to another.) + * + * This is the public entry to copyCheckSubTree. It will always + * perform a check for the attempt to copy onto a descendent or + * self. It calls copyCheckSubTree. + * + * @param subtree Node at the root of the subtree to be added. + * @param index int index of child position in Node's children + */ + + public void copySubTree(Node subtree, int index) + throws TreeException, ConcurrentModificationException { + copyCheckSubTree(subtree, index, true); + } + + /** + * Copies a subtree of this tree as a new child of this node. + * Synchronized on the containing <tt>Tree</tt> object. + * + * Calls the <tt>modified</tt> method of the containing Tree to + * maintain the value of <tt>modCount</tt>. + * + * Note that it is illegal to try to copy a subtree to one of + * its own descendents or itself. (This restriction could be lifted + * by creating a new Tree containing the subtree, and defining an + * attachTree() method to attach one Tree to another.) * * WARNING: this version of the method assumes that <tt>Tree.Node</tt> * will be subclassed; <tt>Tree.Node</tt> has no contents, so for @@ -315,38 +315,38 @@ * the objects from the original subtree. If this has undesirable * effects, the method must be overridden so that the copied subtree * can have its references adjusted after the copy. - * - * @param subtree Node at the root of the subtree to be added. - * @param index int index of child position in Node's children - * @param checkLoops boolean - should the copy been checked for - * loops. Set this to true on the first - * call. - */ - - private void copyCheckSubTree( - Node subtree, int index, boolean checkLoops) - throws TreeException, ConcurrentModificationException { - synchronized (Tree.this) { + * + * @param subtree Node at the root of the subtree to be added. + * @param index int index of child position in Node's children + * @param checkLoops boolean - should the copy been checked for + * loops. Set this to true on the first + * call. + */ + + private void copyCheckSubTree( + Node subtree, int index, boolean checkLoops) + throws TreeException, ConcurrentModificationException { + synchronized (Tree.this) { Node newNode = null; - if (checkLoops) { - checkLoops = false; - if (subtree == this) { - throw new TreeException - ("Copying subtree onto itself."); - } - - // Check that subtree is not an ancestor of this. - Ancestor ancestors = - new Ancestor(Tree.this.getModCount()); - while (ancestors.hasNext()) { - if ((Node)ancestors.next() == subtree) { - throw new TreeException - ("Copying subtree onto descendent."); - } - } - } - - //Node newNode = new Node(this, index, subtree.getContent()); + if (checkLoops) { + checkLoops = false; + if (subtree == this) { + throw new TreeException + ("Copying subtree onto itself."); + } + + // Check that subtree is not an ancestor of this. + Ancestor ancestors = + new Ancestor(Tree.this.getModCount()); + while (ancestors.hasNext()) { + if ((Node)ancestors.next() == subtree) { + throw new TreeException + ("Copying subtree onto descendent."); + } + } + } + + //Node newNode = new Node(this, index, subtree.getContent()); // Clone (shallow copy) the head of the subtree try { newNode = (Node)subtree.clone(); @@ -360,680 +360,680 @@ this.addChild(index, newNode); // Clear the children arrayList newNode.children = new ArrayList(newNode.numChildren()); - // Now iterate over the children of the root of the - // subtree, adding a copy to the newly created Node - Iterator iterator = subtree.nodeChildren(); - while (iterator.hasNext()) { - newNode.copyCheckSubTree((Node)iterator.next(), - newNode.numChildren(), - checkLoops); - } - Tree.this.modified(); - } - } - - - /** - * Removes the child <tt>Node</tt> at the specified index in the - * ArrayList. Synchronized on the enclosing <tt>Tree</tt> object. - * - * Calls the <tt>modified</tt> method of the containing Tree to - * maintain the value of <tt>modCount</tt>. - * - * @param index The int index of the child to be removed. - * @return the node removed. - */ - - public Node removeChildAtIndex(int index) { - synchronized (Tree.this) { - Node tmpNode = (Node) children.remove(index); - Tree.this.modified(); - return tmpNode; - } - } - - /** - * Removes the specified child <tt>Node</tt> from the children - * ArrayList. Synchronized on the enclosing <tt>Tree</tt> object. - * - * Implemented by calling <tt>removeChildAtIndex()</tt>. Relies - * on that method to call the <tt>modified</tt> method of the - * containing Tree to maintain the value of <tt>modCount</tt>. - * - * @param child The child node to be removed. - * @return the node removed. - */ - - public Node removeChild(Node child) - throws NoSuchElementException { - synchronized (Tree.this) { - int index = children.indexOf((Object) child); - if (index == -1) { - throw new NoSuchElementException(); - } - Node tmpNode = removeChildAtIndex(index); - // Note - no call to Tree.this.modified() here - - // done in removeChildAtindex() - return tmpNode; - } - } - - /** - * Deletes the entire subtree rooted on <tt>this</tt> from the - * <tt>Tree</tt>. The Tree is - * traversed in PostOrder, and each Node is removed in PostOrder. - * @return int count of Nodes deleted. - */ - public int deleteSubTree() { - synchronized (Tree.this) { - int count = delete(this); - Tree.this.modified(); - return count; - } - } - - /** - * N.B. this private method must only be called from the deleteSubTree - * method, which is synchronized. In itself, it is not synchronized. - * @param subtree Node at the root of the subtree to be deleted. - * @return int count of Nodes deleted. - */ - private int delete(Node subtree) { - int count = 0; - - while (subtree.numChildren() > 0) { - //System.out.println("# children "+subtree.numChildren()); - - count += delete((Node)subtree.children.get(0)); - } - // Delete this node - // nullify the parent reference - if (subtree.getTree().getRoot() != subtree) { - // Not the root node - remove from parent - subtree.getParent().removeChild(subtree); - subtree.unsetParent(); - } else { - subtree.getTree().unsetRoot(); - } // end of else - return ++count; - } - - public Tree getTree() { - return Tree.this; - } - - public Node getParent() { - return (Node) parent; - } - - public void unsetParent() { - parent = null; - } - - public Node getChild(int index) { - return (Node) children.get(index); - } - - public Iterator nodeChildren() { - return children.iterator(); - } - - public int numChildren() { - return children.size(); - } - - /** - * Class <tt>PreOrder</tt> is a member class of <tt>Node</tt>. - * - * It implements the <tt>Iterator</tt> interface, excluding the - * optional <tt>remove</tt> method. The iterator traverses its - * containing <tt>Tree</tt> from its containing Node in - * preorder order. - * - * The method is implemented recursively; - * at each node, a PreOrder object is instantiated to handle the - * node itself and to trigger the handing of the node's children. - * The node is returned first, and then for each child, a new - * PreOrder is instantiated. That iterator will terminate when the - * last descendant of that child has been returned. - * - * The iterator is <i>fast-fail</i>. If any modifications occur to - * the tree as a whole during the lifetime of the iterator, a - * subsequent call to next() will throw a - * ConcurrentModificationException. See the discussion of - * fast-fail iterators in <tt>AbstractList</tt>. - * - * The <tt>modCount</tt> field used to maintain information about - * structural modifcations is maintained for all nodes in the - * containing Tree instance. - */ - - class PreOrder implements Iterator { - private boolean selfNotReturned = true; - private int nextChildIndex = 0; // N.B. this must be kept as - // the index of the active child until that child is exhausted. - // At the start of proceedings, it may already point past the - // end of the (empty) child vector - - private int age; - private PreOrder nextChildIterator; - - /** - * Constructor - * - * @param age the current value of the modCount field in the - * <tt>Tree</tt> instance which includes this class instance. - */ - public PreOrder(int age) { - this.age = age; - hasNext(); // A call to set up the initial iterators - // so that a call to next() without a preceding call to - // hasNext() will behave sanely - } - - public boolean hasNext() { - // synchronize this against possible changes to the tree - synchronized (Tree.this) { - if (selfNotReturned) { - return true; - } - // self has been returned - are there any children? - // if so, we must always have an iterator available - // even unless it is exhausted. Assume it is set up this - // way by next(). The iterator has a chance to do this - // because self will always be returned first. - // The test of nextChildIndex must always be made because - // there may be no children, or the last child may be - // exhausted, hence no possibility of an - // iterator on the children of any child. - if (nextChildIndex < children.size()) { - return nextChildIterator.hasNext(); - } - else { // no kiddies - return false; - } - } - } - - public Object next() - throws NoSuchElementException, - ConcurrentModificationException { - synchronized (Tree.this) { - // synchronize the whole against changes to the tree - - // Check for ConcurrentModification - if (! Tree.this.modCountEqualTo(age)) { - throw new ConcurrentModificationException(); - } - - if (! hasNext()) { - throw new NoSuchElementException(); - } - if (selfNotReturned) { - selfNotReturned = false; - if (nextChildIndex < children.size()) { - // We have children - create an iterator - // for the first one - nextChildIterator = - ((Node) - (children.get(nextChildIndex))).new - PreOrder(age); - } - // else do nothing; - // the nextChildIndex test in hasNext() - // will prevent us from getting into trouble - return Node.this; - } - else { // self has been returned - // there must be a next available, or we would not have - // come this far - if (! nextChildIterator.hasNext()) { - // last iterator was exhausted; - // if there was another child available, an - //iterator would already have been set up. - // Every iterator will return at least one node - - // the node on which it is defined. - // So why did the initial hasNext succeed? - throw new NoSuchElementException( - "Cannot reach this"); - } - Object tempNode = nextChildIterator.next(); - // Check for exhaustion of the child - if (! nextChildIterator.hasNext()) { - // child iterator empty - another child? - if (++nextChildIndex < children.size()) { - nextChildIterator = - ((Node) - (children.get(nextChildIndex))).new - PreOrder(age); - } - else { - // nullify the iterator - nextChildIterator = null; - } - } - return (Node) tempNode; - } - } - } - - public void remove() - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - } - - - /** - * Class <tt>PostOrder</tt> is a member class of <tt>Node</tt>. - * - * It implements the <tt>Iterator</tt> interface, excluding the - * optional <tt>remove</tt> method. The iterator traverses its - * containing <tt>Tree</tt> from its containing Node in - * postorder order. - * - * The method is implemented recursively; - * at each node, a PostOrder object is instantiated to handle the - * node itself and to trigger the handing of the node's children. - * Firstly, for each child a new PostOrder is instantiated. - * That iterator will terminate when the last descendant of that - * child has been returned. finally, the node itself is returned. - * - * The iterator is <i>fast-fail</i>. iI any modifications occur to - * the tree as a whole during the lifetime of the iterator, a - * subsequent call to next() will throw a - * ConcurrentModificationException. See the discussion of - * fast-fail iterators in <tt>AbstractList</tt>. - * - * The <tt>modCount</tt> field used to maintain information about - * structural modifcations is maintained for all nodes in the - * containing Tree instance. - */ - - class PostOrder implements Iterator { - private boolean selfReturned = false; - private int nextChildIndex = 0; // N.B. this must be kept as - // the index of the active child until that child is exhausted. - // At the start of proceedings, it may already point past the - // end of the (empty) child vector - - private int age; - private PostOrder nextChildIterator; - - /** - * Constructor - * - * @param age the current value of the modCount field in the - * <tt>Tree</tt> instance which includes this class instance. - */ - public PostOrder(int age) { - this.age = age; - hasNext(); // A call to set up the initial iterators - // so that a call to next() without a preceding call to - // hasNext() will behave sanely - } - - public boolean hasNext() { - // Synchronize this against changes in the tree - synchronized (Tree.this) { - // self is always the last to go - if (selfReturned) { // nothing left - return false; - } - - // Check first for children, and set up an iterator if so - if (nextChildIndex < children.size()) { - if (nextChildIterator == null) { - nextChildIterator = - ((Node) - (children.get(nextChildIndex))).new - PostOrder(age); - } - // else an iterator exists. - // Assume that the next() method - // will keep the iterator current - } // end of Any children? - - return true; - } - } - - public Object next() - throws NoSuchElementException, - ConcurrentModificationException { - synchronized (Tree.this) { - // synchronize the whole against changes to the tree - - // Check for ConcurrentModification - if (! Tree.this.modCountEqualTo(age)) { - throw new ConcurrentModificationException(); - } - - if (! hasNext()) { - throw new NoSuchElementException(); - } - // Are there any children? - if (nextChildIndex < children.size()) { - // There will be an active iterator. Is it empty? - if (nextChildIterator.hasNext()) { - // children remain - Object tempNode = nextChildIterator.next(); - // now check for exhaustion of the iterator - if (! nextChildIterator.hasNext()) { - if (++nextChildIndex < children.size()) { - nextChildIterator = - ((Node) - (children.get(nextChildIndex))).new - PostOrder(age); - } - // else leave the iterator bumping on empty - // next call will return self - } - // else iterator not exhausted - // return the Node - return (Node) tempNode; - } - // else children exhausted - fall through - } - // No children - return self object - selfReturned = true; - nextChildIterator = null; - return Node.this; - } - } - - public void remove() - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - } - - - /** - * Class <tt>Ancestor</tt> is a member class of <tt>Node</tt>. - * - * It implements the <tt>Iterator</tt> interface, excluding the - * optional <tt>remove</tt> method. The iterator traverses the - * ancestors of its containing Node from the Node's immediate - * parent back to tge root Node of the containing <tt>Tree</tt>. - * - * The iterator is <i>fast-fail</i>. If any modifications occur to - * the tree as a whole during the lifetime of the iterator, a - * subsequent call to next() will throw a - * ConcurrentModificationException. See the discussion of - * fast-fail iterators in <tt>AbstractList</tt>. - * - * The <tt>modCount</tt> field used to maintain information about - * structural modifcations is maintained for all nodes in the - * containing Tree instance. - */ - - class Ancestor implements Iterator { - private Tree.Node nextAncestor; - private int age; - - /** - * Constructor - * - * @param age the current value of the modCount field in the - * <tt>Tree</tt> instance which includes this class instance. - */ - - public Ancestor(int age) { - this.age = age; - nextAncestor = Node.this.parent; - } - - public boolean hasNext() { - return nextAncestor != null; - } - - public Object next() - throws NoSuchElementException, - ConcurrentModificationException { - synchronized (Tree.this) { - // The tree is a - // potentially dymanic structure, which could be - // undergoing modification as this method is being - // executed, and it is possible that the Comod exception - // could be set to trigger while this call is in process. - if (! Tree.this.modCountEqualTo(age)) { - throw new ConcurrentModificationException(); - } - Tree.Node tmpNode = nextAncestor; - nextAncestor = tmpNode.parent; - return tmpNode; - } - } - - public void remove() - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - } - - - /** - * Class <tt>FollowingSibling</tt> is a member class of <tt>Node</tt>. - * - * It implements the <tt>ListIterator</tt> interface, but has reports - * UnsupportedOperationException for all methods except - * <tt>hasNext()</tt>, <tt>next()</tt> and <tt>nextIndex()</tt>. - * These methods are implemented as synchronized wrappers around the - * underlying ArrayList methods. - * - * The listIterator traverses those children in the parent node's - * <tt>children</tt> <tt>ArrayList</tt> which follow the subject - * node's entry in that array, using the <tt>next()</tt> method. - * - * The iterator is <i>fail-fast</i>. if any modification occur to - * the tree as a whole during the lifetime of the iterator, a - * subsequent call to next() will throw a - * ConcurrentModificationException. See the discussion of - * fast-fail iterators in <tt>AbstractList</tt>. - * - * The fail-fast ListIterator in ArrayList is the underlying - * mechanism for both the listIterator and the fail-fast - * behaviour. - */ - - class FollowingSibling implements ListIterator { - - private ListIterator listIterator; - private ArrayList rootDummy = new ArrayList(); - // An empty ArrayList for the root listIterator - // hasNext() will always return false - - public FollowingSibling() { - synchronized (Tree.this) { - // Set up iterator on the parent's arrayList of children - Tree.Node refNode = Node.this.parent; - if (refNode != null) { - // Not the root node; siblings may exist - // Set up iterator on the parent's children ArrayList - ArrayList siblings = refNode.children; - int index = siblings.indexOf((Object) Node.this); - // if this is invalid, we are in serious trouble - listIterator = siblings.listIterator(index + 1); - } // end of if (Node.this.parent != null) - else { - // Root node - no siblings - listIterator = rootDummy.listIterator(); - } - } - } - - public boolean hasNext() { - // Any CoMod exception will be thrown by the listIterator - // provided with ArrayList. It does not throw such exceptions - // on calls to hasNext(); - synchronized (Tree.this) { - return listIterator.hasNext(); - } - } - - public Object next() - throws NoSuchElementException, - ConcurrentModificationException { - synchronized (Tree.this) { - // N.B. synchronization here is still on the Tree - // rather than on the Node containing the children - // ArryList of interest. Other ArrayList operations - // throughout the Tree are synchronized on the Tree object - // itself, so exceptions cannot be made for these more - // directly Nodal operations. - return listIterator.next(); - } - } - - public int nextIndex() { - synchronized (Tree.this) { - return listIterator.nextIndex(); - } - } - - public void add(Object o) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public void remove() - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public boolean hasPrevious() - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public Object previous() - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public int previousIndex() - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public void set(Object o) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - } - - /** - * Class <tt>PrecedingSibling</tt> is a member class of <tt>Node</tt>. - * - * It implements the <tt>ListIterator</tt> interface, but has reports - * UnsupportedOperationException for all methods except - * <tt>hasPrevious()</tt>, <tt>previous()</tt> and - * <tt>previousIndex()</tt>. - * These methods are implemented as synchronized wrappers around the - * underlying ArrayList methods. - * - * The listIterator traverses those children in the parent node's - * <tt>children</tt> <tt>ArrayList</tt> which precede the subject - * node's entry in that array, using the <tt>previous()</tt> method. - * I.e., siblings are produced in reverse sibling order. - * - * The iterator is <i>fail-fast</i>. if any modification occur to - * the tree as a whole during the lifetime of the iterator, a - * subsequent call to previous() will throw a - * ConcurrentModificationException. See the discussion of - * fast-fail iterators in <tt>AbstractList</tt>. - * - * The fail-fast ListIterator in ArrayList is the underlying - * mechanism for both the listIterator and the fail-fast - * behaviour. - */ - - class PrecedingSibling implements ListIterator { - - private ListIterator listIterator; - private ArrayList rootDummy = new ArrayList(); - // An empty ArrayList for the root listIterator - // hasNext() will always return false - - public PrecedingSibling() { - synchronized (Tree.this) { - // Set up iterator on the parent's arrayList of children - Tree.Node refNode = Node.this.parent; - if (refNode != null) { - // Not the root node; siblings may exist - // Set up iterator on the parent's children ArrayList - ArrayList siblings = refNode.children; - int index = siblings.indexOf((Object) Node.this); - // if this is invalid, we are in serious trouble - listIterator = siblings.listIterator(index); - } // end of if (Node.this.parent != null) - else { - // Root node - no siblings - listIterator = rootDummy.listIterator(); - } - } - } - - public boolean hasPrevious() { - // Any CoMod exception will be thrown by the listIterator - // provided with ArrayList. It does not throw such exceptions - // on calls to hasNext(); - synchronized (Tree.this) { - return listIterator.hasPrevious(); - } - } - - public Object previous() - throws NoSuchElementException, - ConcurrentModificationException { - synchronized (Tree.this) { - // N.B. synchronization here is still on the Tree - // rather than on the Node containing the children - // ArryList of interest. Other ArrayList operations - // throughout the Tree are synchronized on the Tree object - // itself, so exceptions cannot be made for these more - // directly Nodal operations. - return listIterator.previous(); - } - } - - public int previousIndex() { - synchronized (Tree.this) { - return listIterator.previousIndex(); - } - } - - public void add(Object o) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public void remove() - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public boolean hasNext() - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public Object next() - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public int nextIndex() - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public void set(Object o) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - } + // Now iterate over the children of the root of the + // subtree, adding a copy to the newly created Node + Iterator iterator = subtree.nodeChildren(); + while (iterator.hasNext()) { + newNode.copyCheckSubTree((Node)iterator.next(), + newNode.numChildren(), + checkLoops); + } + Tree.this.modified(); + } + } + + + /** + * Removes the child <tt>Node</tt> at the specified index in the + * ArrayList. Synchronized on the enclosing <tt>Tree</tt> object. + * + * Calls the <tt>modified</tt> method of the containing Tree to + * maintain the value of <tt>modCount</tt>. + * + * @param index The int index of the child to be removed. + * @return the node removed. + */ + + public Node removeChildAtIndex(int index) { + synchronized (Tree.this) { + Node tmpNode = (Node) children.remove(index); + Tree.this.modified(); + return tmpNode; + } + } + + /** + * Removes the specified child <tt>Node</tt> from the children + * ArrayList. Synchronized on the enclosing <tt>Tree</tt> object. + * + * Implemented by calling <tt>removeChildAtIndex()</tt>. Relies + * on that method to call the <tt>modified</tt> method of the + * containing Tree to maintain the value of <tt>modCount</tt>. + * + * @param child The child node to be removed. + * @return the node removed. + */ + + public Node removeChild(Node child) + throws NoSuchElementException { + synchronized (Tree.this) { + int index = children.indexOf((Object) child); + if (index == -1) { + throw new NoSuchElementException(); + } + Node tmpNode = removeChildAtIndex(index); + // Note - no call to Tree.this.modified() here - + // done in removeChildAtindex() + return tmpNode; + } + } + + /** + * Deletes the entire subtree rooted on <tt>this</tt> from the + * <tt>Tree</tt>. The Tree is + * traversed in PostOrder, and each Node is removed in PostOrder. + * @return int count of Nodes deleted. + */ + public int deleteSubTree() { + synchronized (Tree.this) { + int count = delete(this); + Tree.this.modified(); + return count; + } + } + + /** + * N.B. this private method must only be called from the deleteSubTree + * method, which is synchronized. In itself, it is not synchronized. + * @param subtree Node at the root of the subtree to be deleted. + * @return int count of Nodes deleted. + */ + private int delete(Node subtree) { + int count = 0; + + while (subtree.numChildren() > 0) { + //System.out.println("# children "+subtree.numChildren()); + + count += delete((Node)subtree.children.get(0)); + } + // Delete this node + // nullify the parent reference + if (subtree.getTree().getRoot() != subtree) { + // Not the root node - remove from parent + subtree.getParent().removeChild(subtree); + subtree.unsetParent(); + } else { + subtree.getTree().unsetRoot(); + } // end of else + return ++count; + } + + public Tree getTree() { + return Tree.this; + } + + public Node getParent() { + return (Node) parent; + } + + public void unsetParent() { + parent = null; + } + + public Node getChild(int index) { + return (Node) children.get(index); + } + + public Iterator nodeChildren() { + return children.iterator(); + } + + public int numChildren() { + return children.size(); + } + + /** + * Class <tt>PreOrder</tt> is a member class of <tt>Node</tt>. + * + * It implements the <tt>Iterator</tt> interface, excluding the + * optional <tt>remove</tt> method. The iterator traverses its + * containing <tt>Tree</tt> from its containing Node in + * preorder order. + * + * The method is implemented recursively; + * at each node, a PreOrder object is instantiated to handle the + * node itself and to trigger the handing of the node's children. + * The node is returned first, and then for each child, a new + * PreOrder is instantiated. That iterator will terminate when the + * last descendant of that child has been returned. + * + * The iterator is <i>fast-fail</i>. If any modifications occur to + * the tree as a whole during the lifetime of the iterator, a + * subsequent call to next() will throw a + * ConcurrentModificationException. See the discussion of + * fast-fail iterators in <tt>AbstractList</tt>. + * + * The <tt>modCount</tt> field used to maintain information about + * structural modifcations is maintained for all nodes in the + * containing Tree instance. + */ + + class PreOrder implements Iterator { + private boolean selfNotReturned = true; + private int nextChildIndex = 0; // N.B. this must be kept as + // the index of the active child until that child is exhausted. + // At the start of proceedings, it may already point past the + // end of the (empty) child vector + + private int age; + private PreOrder nextChildIterator; + + /** + * Constructor + * + * @param age the current value of the modCount field in the + * <tt>Tree</tt> instance which includes this class instance. + */ + public PreOrder(int age) { + this.age = age; + hasNext(); // A call to set up the initial iterators + // so that a call to next() without a preceding call to + // hasNext() will behave sanely + } + + public boolean hasNext() { + // synchronize this against possible changes to the tree + synchronized (Tree.this) { + if (selfNotReturned) { + return true; + } + // self has been returned - are there any children? + // if so, we must always have an iterator available + // even unless it is exhausted. Assume it is set up this + // way by next(). The iterator has a chance to do this + // because self will always be returned first. + // The test of nextChildIndex must always be made because + // there may be no children, or the last child may be + // exhausted, hence no possibility of an + // iterator on the children of any child. + if (nextChildIndex < children.size()) { + return nextChildIterator.hasNext(); + } + else { // no kiddies + return false; + } + } + } + + public Object next() + throws NoSuchElementException, + ConcurrentModificationException { + synchronized (Tree.this) { + // synchronize the whole against changes to the tree + + // Check for ConcurrentModification + if (! Tree.this.modCountEqualTo(age)) { + throw new ConcurrentModificationException(); + } + + if (! hasNext()) { + throw new NoSuchElementException(); + } + if (selfNotReturned) { + selfNotReturned = false; + if (nextChildIndex < children.size()) { + // We have children - create an iterator + // for the first one + nextChildIterator = + ((Node) + (children.get(nextChildIndex))).new + PreOrder(age); + } + // else do nothing; + // the nextChildIndex test in hasNext() + // will prevent us from getting into trouble + return Node.this; + } + else { // self has been returned + // there must be a next available, or we would not have + // come this far + if (! nextChildIterator.hasNext()) { + // last iterator was exhausted; + // if there was another child available, an + //iterator would already have been set up. + // Every iterator will return at least one node - + // the node on which it is defined. + // So why did the initial hasNext succeed? + throw new NoSuchElementException( + "Cannot reach this"); + } + Object tempNode = nextChildIterator.next(); + // Check for exhaustion of the child + if (! nextChildIterator.hasNext()) { + // child iterator empty - another child? + if (++nextChildIndex < children.size()) { + nextChildIterator = + ((Node) + (children.get(nextChildIndex))).new + PreOrder(age); + } + else { + // nullify the iterator + nextChildIterator = null; + } + } + return (Node) tempNode; + } + } + } + + public void remove() + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + } + + + /** + * Class <tt>PostOrder</tt> is a member class of <tt>Node</tt>. + * + * It implements the <tt>Iterator</tt> interface, excluding the + * optional <tt>remove</tt> method. The iterator traverses its + * containing <tt>Tree</tt> from its containing Node in + * postorder order. + * + * The method is implemented recursively; + * at each node, a PostOrder object is instantiated to handle the + * node itself and to trigger the handing of the node's children. + * Firstly, for each child a new PostOrder is instantiated. + * That iterator will terminate when the last descendant of that + * child has been returned. finally, the node itself is returned. + * + * The iterator is <i>fast-fail</i>. iI any modifications occur to + * the tree as a whole during the lifetime of the iterator, a + * subsequent call to next() will throw a + * ConcurrentModificationException. See the discussion of + * fast-fail iterators in <tt>AbstractList</tt>. + * + * The <tt>modCount</tt> field used to maintain information about + * structural modifcations is maintained for all nodes in the + * containing Tree instance. + */ + + class PostOrder implements Iterator { + private boolean selfReturned = false; + private int nextChildIndex = 0; // N.B. this must be kept as + // the index of the active child until that child is exhausted. + // At the start of proceedings, it may already point past the + // end of the (empty) child vector + + private int age; + private PostOrder nextChildIterator; + + /** + * Constructor + * + * @param age the current value of the modCount field in the + * <tt>Tree</tt> instance which includes this class instance. + */ + public PostOrder(int age) { + this.age = age; + hasNext(); // A call to set up the initial iterators + // so that a call to next() without a preceding call to + // hasNext() will behave sanely + } + + public boolean hasNext() { + // Synchronize this against changes in the tree + synchronized (Tree.this) { + // self is always the last to go + if (selfReturned) { // nothing left + return false; + } + + // Check first for children, and set up an iterator if so + if (nextChildIndex < children.size()) { + if (nextChildIterator == null) { + nextChildIterator = + ((Node) + (children.get(nextChildIndex))).new + PostOrder(age); + } + // else an iterator exists. + // Assume that the next() method + // will keep the iterator current + } // end of Any children? + + return true; + } + } + + public Object next() + throws NoSuchElementException, + ConcurrentModificationException { + synchronized (Tree.this) { + // synchronize the whole against changes to the tree + + // Check for ConcurrentModification + if (! Tree.this.modCountEqualTo(age)) { + throw new ConcurrentModificationException(); + } + + if (! hasNext()) { + throw new NoSuchElementException(); + } + // Are there any children? + if (nextChildIndex < children.size()) { + // There will be an active iterator. Is it empty? + if (nextChildIterator.hasNext()) { + // children remain + Object tempNode = nextChildIterator.next(); + // now check for exhaustion of the iterator + if (! nextChildIterator.hasNext()) { + if (++nextChildIndex < children.size()) { + nextChildIterator = + ((Node) + (children.get(nextChildIndex))).new + PostOrder(age); + } + // else leave the iterator bumping on empty + // next call will return self + } + // else iterator not exhausted + // return the Node + return (Node) tempNode; + } + // else children exhausted - fall through + } + // No children - return self object + selfReturned = true; + nextChildIterator = null; + return Node.this; + } + } + + public void remove() + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + } + + + /** + * Class <tt>Ancestor</tt> is a member class of <tt>Node</tt>. + * + * It implements the <tt>Iterator</tt> interface, excluding the + * optional <tt>remove</tt> method. The iterator traverses the + * ancestors of its containing Node from the Node's immediate + * parent back to tge root Node of the containing <tt>Tree</tt>. + * + * The iterator is <i>fast-fail</i>. If any modifications occur to + * the tree as a whole during the lifetime of the iterator, a + * subsequent call to next() will throw a + * ConcurrentModificationException. See the discussion of + * fast-fail iterators in <tt>AbstractList</tt>. + * + * The <tt>modCount</tt> field used to maintain information about + * structural modifcations is maintained for all nodes in the + * containing Tree instance. + */ + + class Ancestor implements Iterator { + private Tree.Node nextAncestor; + private int age; + + /** + * Constructor + * + * @param age the current value of the modCount field in the + * <tt>Tree</tt> instance which includes this class instance. + */ + + public Ancestor(int age) { + this.age = age; + nextAncestor = Node.this.parent; + } + + public boolean hasNext() { + return nextAncestor != null; + } + + public Object next() + throws NoSuchElementException, + ConcurrentModificationException { + synchronized (Tree.this) { + // The tree is a + // potentially dymanic structure, which could be + // undergoing modification as this method is being + // executed, and it is possible that the Comod exception + // could be set to trigger while this call is in process. + if (! Tree.this.modCountEqualTo(age)) { + throw new ConcurrentModificationException(); + } + Tree.Node tmpNode = nextAncestor; + nextAncestor = tmpNode.parent; + return tmpNode; + } + } + + public void remove() + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + } + + + /** + * Class <tt>FollowingSibling</tt> is a member class of <tt>Node</tt>. + * + * It implements the <tt>ListIterator</tt> interface, but has reports + * UnsupportedOperationException for all methods except + * <tt>hasNext()</tt>, <tt>next()</tt> and <tt>nextIndex()</tt>. + * These methods are implemented as synchronized wrappers around the + * underlying ArrayList methods. + * + * The listIterator traverses those children in the parent node's + * <tt>children</tt> <tt>ArrayList</tt> which follow the subject + * node's entry in that array, using the <tt>next()</tt> method. + * + * The iterator is <i>fail-fast</i>. if any modification occur to + * the tree as a whole during the lifetime of the iterator, a + * subsequent call to next() will throw a + * ConcurrentModificationException. See the discussion of + * fast-fail iterators in <tt>AbstractList</tt>. + * + * The fail-fast ListIterator in ArrayList is the underlying + * mechanism for both the listIterator and the fail-fast + * behaviour. + */ + + class FollowingSibling implements ListIterator { + + private ListIterator listIterator; + private ArrayList rootDummy = new ArrayList(); + // An empty ArrayList for the root listIterator + // hasNext() will always return false + + public FollowingSibling() { + synchronized (Tree.this) { + // Set up iterator on the parent's arrayList of children + Tree.Node refNode = Node.this.parent; + if (refNode != null) { + // Not the root node; siblings may exist + // Set up iterator on the parent's children ArrayList + ArrayList siblings = refNode.children; + int index = siblings.indexOf((Object) Node.this); + // if this is invalid, we are in serious trouble + listIterator = siblings.listIterator(index + 1); + } // end of if (Node.this.parent != null) + else { + // Root node - no siblings + listIterator = rootDummy.listIterator(); + } + } + } + + public boolean hasNext() { + // Any CoMod exception will be thrown by the listIterator + // provided with ArrayList. It does not throw such exceptions + // on calls to hasNext(); + synchronized (Tree.this) { + return listIterator.hasNext(); + } + } + + public Object next() + throws NoSuchElementException, + ConcurrentModificationException { + synchronized (Tree.this) { + // N.B. synchronization here is still on the Tree + // rather than on the Node containing the children + // ArryList of interest. Other ArrayList operations + // throughout the Tree are synchronized on the Tree object + // itself, so exceptions cannot be made for these more + // directly Nodal operations. + return listIterator.next(); + } + } + + public int nextIndex() { + synchronized (Tree.this) { + return listIterator.nextIndex(); + } + } + + public void add(Object o) + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public void remove() + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public boolean hasPrevious() + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public Object previous() + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public int previousIndex() + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public void set(Object o) + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + } + + /** + * Class <tt>PrecedingSibling</tt> is a member class of <tt>Node</tt>. + * + * It implements the <tt>ListIterator</tt> interface, but has reports + * UnsupportedOperationException for all methods except + * <tt>hasPrevious()</tt>, <tt>previous()</tt> and + * <tt>previousIndex()</tt>. + * These methods are implemented as synchronized wrappers around the + * underlying ArrayList methods. + * + * The listIterator traverses those children in the parent node's + * <tt>children</tt> <tt>ArrayList</tt> which precede the subject + * node's entry in that array, using the <tt>previous()</tt> method. + * I.e., siblings are produced in reverse sibling order. + * + * The iterator is <i>fail-fast</i>. if any modification occur to + * the tree as a whole during the lifetime of the iterator, a + * subsequent call to previous() will throw a + * ConcurrentModificationException. See the discussion of + * fast-fail iterators in <tt>AbstractList</tt>. + * + * The fail-fast ListIterator in ArrayList is the underlying + * mechanism for both the listIterator and the fail-fast + * behaviour. + */ + + class PrecedingSibling implements ListIterator { + + private ListIterator listIterator; + private ArrayList rootDummy = new ArrayList(); + // An empty ArrayList for the root listIterator + // hasNext() will always return false + + public PrecedingSibling() { + synchronized (Tree.this) { + // Set up iterator on the parent's arrayList of children + Tree.Node refNode = Node.this.parent; + if (refNode != null) { + // Not the root node; siblings may exist + // Set up iterator on the parent's children ArrayList + ArrayList siblings = refNode.children; + int index = siblings.indexOf((Object) Node.this); + // if this is invalid, we are in serious trouble + listIterator = siblings.listIterator(index); + } // end of if (Node.this.parent != null) + else { + // Root node - no siblings + listIterator = rootDummy.listIterator(); + } + } + } + + public boolean hasPrevious() { + // Any CoMod exception will be thrown by the listIterator + // provided with ArrayList. It does not throw such exceptions + // on calls to hasNext(); + synchronized (Tree.this) { + return listIterator.hasPrevious(); + } + } + + public Object previous() + throws NoSuchElementException, + ConcurrentModificationException { + synchronized (Tree.this) { + // N.B. synchronization here is still on the Tree + // rather than on the Node containing the children + // ArryList of interest. Other ArrayList operations + // throughout the Tree are synchronized on the Tree object + // itself, so exceptions cannot be made for these more + // directly Nodal operations. + return listIterator.previous(); + } + } + + public int previousIndex() { + synchronized (Tree.this) { + return listIterator.previousIndex(); + } + } + + public void add(Object o) + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public void remove() + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public boolean hasNext() + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public Object next() + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public int nextIndex() + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public void set(Object o) + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]