0N/A/*
2362N/A * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage javax.swing.text;
0N/A
0N/Aimport java.util.Stack;
0N/Aimport java.util.Enumeration;
0N/A
0N/A/**
0N/A * <p>
0N/A * ElementIterator, as the name suggests, iteratates over the Element
0N/A * tree. The constructor can be invoked with either Document or an Element
0N/A * as an argument. If the constructor is invoked with a Document as an
0N/A * argument then the root of the iteration is the return value of
0N/A * document.getDefaultRootElement().
0N/A *
0N/A * The iteration happens in a depth-first manner. In terms of how
0N/A * boundary conditions are handled:
0N/A * a) if next() is called before first() or current(), the
0N/A * root will be returned.
0N/A * b) next() returns null to indicate the end of the list.
0N/A * c) previous() returns null when the current element is the root
0N/A * or next() has returned null.
0N/A *
0N/A * The ElementIterator does no locking of the Element tree. This means
0N/A * that it does not track any changes. It is the responsibility of the
0N/A * user of this class, to ensure that no changes happen during element
0N/A * iteration.
0N/A *
0N/A * Simple usage example:
0N/A *
0N/A * public void iterate() {
0N/A * ElementIterator it = new ElementIterator(root);
0N/A * Element elem;
0N/A * while (true) {
0N/A * if ((elem = next()) != null) {
0N/A * // process element
0N/A * System.out.println("elem: " + elem.getName());
0N/A * } else {
0N/A * break;
0N/A * }
0N/A * }
0N/A * }
0N/A *
0N/A * @author Sunita Mani
0N/A *
0N/A */
0N/A
0N/Apublic class ElementIterator implements Cloneable {
0N/A
0N/A
0N/A private Element root;
611N/A private Stack<StackItem> elementStack = null;
0N/A
0N/A /**
0N/A * The StackItem class stores the element
0N/A * as well as a child index. If the
0N/A * index is -1, then the element represented
0N/A * on the stack is the element itself.
0N/A * Otherwise, the index functions as as index
0N/A * into the vector of children of the element.
0N/A * In this case, the item on the stack
0N/A * represents the "index"th child of the element
0N/A *
0N/A */
0N/A private class StackItem implements Cloneable {
0N/A Element item;
0N/A int childIndex;
0N/A
0N/A private StackItem(Element elem) {
0N/A /**
0N/A * -1 index implies a self reference,
0N/A * as opposed to an index into its
0N/A * list of children.
0N/A */
0N/A this.item = elem;
0N/A this.childIndex = -1;
0N/A }
0N/A
0N/A private void incrementIndex() {
0N/A childIndex++;
0N/A }
0N/A
0N/A private Element getElement() {
0N/A return item;
0N/A }
0N/A
0N/A private int getIndex() {
0N/A return childIndex;
0N/A }
0N/A
0N/A protected Object clone() throws java.lang.CloneNotSupportedException {
0N/A return super.clone();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Creates a new ElementIterator. The
0N/A * root element is taken to get the
0N/A * default root element of the document.
0N/A *
0N/A * @param document a Document.
0N/A */
0N/A public ElementIterator(Document document) {
0N/A root = document.getDefaultRootElement();
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Creates a new ElementIterator.
0N/A *
0N/A * @param root the root Element.
0N/A */
0N/A public ElementIterator(Element root) {
0N/A this.root = root;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Clones the ElementIterator.
0N/A *
0N/A * @return a cloned ElementIterator Object.
0N/A */
0N/A public synchronized Object clone() {
0N/A
0N/A try {
0N/A ElementIterator it = new ElementIterator(root);
0N/A if (elementStack != null) {
611N/A it.elementStack = new Stack<StackItem>();
0N/A for (int i = 0; i < elementStack.size(); i++) {
611N/A StackItem item = elementStack.elementAt(i);
0N/A StackItem clonee = (StackItem)item.clone();
0N/A it.elementStack.push(clonee);
0N/A }
0N/A }
0N/A return it;
0N/A } catch (CloneNotSupportedException e) {
0N/A throw new InternalError();
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Fetches the first element.
0N/A *
0N/A * @return an Element.
0N/A */
0N/A public Element first() {
0N/A // just in case...
0N/A if (root == null) {
0N/A return null;
0N/A }
0N/A
611N/A elementStack = new Stack<StackItem>();
0N/A if (root.getElementCount() != 0) {
0N/A elementStack.push(new StackItem(root));
0N/A }
0N/A return root;
0N/A }
0N/A
0N/A /**
0N/A * Fetches the current depth of element tree.
0N/A *
0N/A * @return the depth.
0N/A */
0N/A public int depth() {
0N/A if (elementStack == null) {
0N/A return 0;
0N/A }
0N/A return elementStack.size();
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Fetches the current Element.
0N/A *
0N/A * @return element on top of the stack or
0N/A * <code>null</code> if the root element is <code>null</code>
0N/A */
0N/A public Element current() {
0N/A
0N/A if (elementStack == null) {
0N/A return first();
0N/A }
0N/A
0N/A /*
0N/A get a handle to the element on top of the stack.
0N/A */
0N/A if (! elementStack.empty()) {
611N/A StackItem item = elementStack.peek();
0N/A Element elem = item.getElement();
0N/A int index = item.getIndex();
0N/A // self reference
0N/A if (index == -1) {
0N/A return elem;
0N/A }
0N/A // return the child at location "index".
0N/A return elem.getElement(index);
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Fetches the next Element. The strategy
0N/A * used to locate the next element is
0N/A * a depth-first search.
0N/A *
0N/A * @return the next element or <code>null</code>
0N/A * at the end of the list.
0N/A */
0N/A public Element next() {
0N/A
0N/A /* if current() has not been invoked
0N/A and next is invoked, the very first
0N/A element will be returned. */
0N/A if (elementStack == null) {
0N/A return first();
0N/A }
0N/A
0N/A // no more elements
0N/A if (elementStack.isEmpty()) {
0N/A return null;
0N/A }
0N/A
0N/A // get a handle to the element on top of the stack
0N/A
611N/A StackItem item = elementStack.peek();
0N/A Element elem = item.getElement();
0N/A int index = item.getIndex();
0N/A
0N/A if (index+1 < elem.getElementCount()) {
0N/A Element child = elem.getElement(index+1);
0N/A if (child.isLeaf()) {
0N/A /* In this case we merely want to increment
0N/A the child index of the item on top of the
0N/A stack.*/
0N/A item.incrementIndex();
0N/A } else {
0N/A /* In this case we need to push the child(branch)
0N/A on the stack so that we can iterate over its
0N/A children. */
0N/A elementStack.push(new StackItem(child));
0N/A }
0N/A return child;
0N/A } else {
0N/A /* No more children for the item on top of the
0N/A stack therefore pop the stack. */
0N/A elementStack.pop();
0N/A if (!elementStack.isEmpty()) {
0N/A /* Increment the child index for the item that
0N/A is now on top of the stack. */
611N/A StackItem top = elementStack.peek();
0N/A top.incrementIndex();
0N/A /* We now want to return its next child, therefore
0N/A call next() recursively. */
0N/A return next();
0N/A }
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Fetches the previous Element. If howver the current
0N/A * element is the last element, or the current element
0N/A * is null, then null is returned.
0N/A *
0N/A * @return previous <code>Element</code> if available
0N/A *
0N/A */
0N/A public Element previous() {
0N/A
0N/A int stackSize;
0N/A if (elementStack == null || (stackSize = elementStack.size()) == 0) {
0N/A return null;
0N/A }
0N/A
0N/A // get a handle to the element on top of the stack
0N/A //
611N/A StackItem item = elementStack.peek();
0N/A Element elem = item.getElement();
0N/A int index = item.getIndex();
0N/A
0N/A if (index > 0) {
0N/A /* return child at previous index. */
0N/A return getDeepestLeaf(elem.getElement(--index));
0N/A } else if (index == 0) {
0N/A /* this implies that current is the element's
0N/A first child, therefore previous is the
0N/A element itself. */
0N/A return elem;
0N/A } else if (index == -1) {
0N/A if (stackSize == 1) {
0N/A // current is the root, nothing before it.
0N/A return null;
0N/A }
0N/A /* We need to return either the item
0N/A below the top item or one of the
0N/A former's children. */
611N/A StackItem top = elementStack.pop();
611N/A item = elementStack.peek();
0N/A
0N/A // restore the top item.
0N/A elementStack.push(top);
0N/A elem = item.getElement();
0N/A index = item.getIndex();
0N/A return ((index == -1) ? elem : getDeepestLeaf(elem.getElement
0N/A (index)));
0N/A }
0N/A // should never get here.
0N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * Returns the last child of <code>parent</code> that is a leaf. If the
0N/A * last child is a not a leaf, this method is called with the last child.
0N/A */
0N/A private Element getDeepestLeaf(Element parent) {
0N/A if (parent.isLeaf()) {
0N/A return parent;
0N/A }
0N/A int childCount = parent.getElementCount();
0N/A if (childCount == 0) {
0N/A return parent;
0N/A }
0N/A return getDeepestLeaf(parent.getElement(childCount - 1));
0N/A }
0N/A
0N/A /*
0N/A Iterates through the element tree and prints
0N/A out each element and its attributes.
0N/A */
0N/A private void dumpTree() {
0N/A
0N/A Element elem;
0N/A while (true) {
0N/A if ((elem = next()) != null) {
0N/A System.out.println("elem: " + elem.getName());
0N/A AttributeSet attr = elem.getAttributes();
0N/A String s = "";
0N/A Enumeration names = attr.getAttributeNames();
0N/A while (names.hasMoreElements()) {
0N/A Object key = names.nextElement();
0N/A Object value = attr.getAttribute(key);
0N/A if (value instanceof AttributeSet) {
0N/A // don't go recursive
0N/A s = s + key + "=**AttributeSet** ";
0N/A } else {
0N/A s = s + key + "=" + value + " ";
0N/A }
0N/A }
0N/A System.out.println("attributes: " + s);
0N/A } else {
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A}