Home » openjdk-7 » javax » swing » text » [javadoc | source]

    1   /*
    2    * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package javax.swing.text;
   27   
   28   import java.util.Stack;
   29   import java.util.Enumeration;
   30   
   31   /**
   32    * <p>
   33    * ElementIterator, as the name suggests, iteratates over the Element
   34    * tree.  The constructor can be invoked with either Document or an Element
   35    * as an argument.  If the constructor is invoked with a Document as an
   36    * argument then the root of the iteration is the return value of
   37    * document.getDefaultRootElement().
   38    *
   39    * The iteration happens in a depth-first manner.  In terms of how
   40    * boundary conditions are handled:
   41    * a) if next() is called before first() or current(), the
   42    *    root will be returned.
   43    * b) next() returns null to indicate the end of the list.
   44    * c) previous() returns null when the current element is the root
   45    *    or next() has returned null.
   46    *
   47    * The ElementIterator does no locking of the Element tree. This means
   48    * that it does not track any changes.  It is the responsibility of the
   49    * user of this class, to ensure that no changes happen during element
   50    * iteration.
   51    *
   52    * Simple usage example:
   53    *
   54    *    public void iterate() {
   55    *        ElementIterator it = new ElementIterator(root);
   56    *        Element elem;
   57    *        while (true) {
   58    *           if ((elem = next()) != null) {
   59    *               // process element
   60    *               System.out.println("elem: " + elem.getName());
   61    *           } else {
   62    *               break;
   63    *           }
   64    *        }
   65    *    }
   66    *
   67    * @author Sunita Mani
   68    *
   69    */
   70   
   71   public class ElementIterator implements Cloneable {
   72   
   73   
   74       private Element root;
   75       private Stack<StackItem> elementStack = null;
   76   
   77       /**
   78        * The StackItem class stores the element
   79        * as well as a child index.  If the
   80        * index is -1, then the element represented
   81        * on the stack is the element itself.
   82        * Otherwise, the index functions as as index
   83        * into the vector of children of the element.
   84        * In this case, the item on the stack
   85        * represents the "index"th child of the element
   86        *
   87        */
   88       private class StackItem implements Cloneable {
   89           Element item;
   90           int childIndex;
   91   
   92           private StackItem(Element elem) {
   93               /**
   94                * -1 index implies a self reference,
   95                * as opposed to an index into its
   96                * list of children.
   97                */
   98               this.item = elem;
   99               this.childIndex = -1;
  100           }
  101   
  102           private void incrementIndex() {
  103               childIndex++;
  104           }
  105   
  106           private Element getElement() {
  107               return item;
  108           }
  109   
  110           private int getIndex() {
  111               return childIndex;
  112           }
  113   
  114           protected Object clone() throws java.lang.CloneNotSupportedException {
  115               return super.clone();
  116           }
  117       }
  118   
  119       /**
  120        * Creates a new ElementIterator. The
  121        * root element is taken to get the
  122        * default root element of the document.
  123        *
  124        * @param document a Document.
  125        */
  126       public ElementIterator(Document document) {
  127           root = document.getDefaultRootElement();
  128       }
  129   
  130   
  131       /**
  132        * Creates a new ElementIterator.
  133        *
  134        * @param root the root Element.
  135        */
  136       public ElementIterator(Element root) {
  137           this.root = root;
  138       }
  139   
  140   
  141       /**
  142        * Clones the ElementIterator.
  143        *
  144        * @return a cloned ElementIterator Object.
  145        */
  146       public synchronized Object clone() {
  147   
  148           try {
  149               ElementIterator it = new ElementIterator(root);
  150               if (elementStack != null) {
  151                   it.elementStack = new Stack<StackItem>();
  152                   for (int i = 0; i < elementStack.size(); i++) {
  153                       StackItem item = elementStack.elementAt(i);
  154                       StackItem clonee = (StackItem)item.clone();
  155                       it.elementStack.push(clonee);
  156                   }
  157               }
  158               return it;
  159           } catch (CloneNotSupportedException e) {
  160               throw new InternalError();
  161           }
  162       }
  163   
  164   
  165       /**
  166        * Fetches the first element.
  167        *
  168        * @return an Element.
  169        */
  170       public Element first() {
  171           // just in case...
  172           if (root == null) {
  173               return null;
  174           }
  175   
  176           elementStack = new Stack<StackItem>();
  177           if (root.getElementCount() != 0) {
  178               elementStack.push(new StackItem(root));
  179           }
  180           return root;
  181       }
  182   
  183       /**
  184        * Fetches the current depth of element tree.
  185        *
  186        * @return the depth.
  187        */
  188       public int depth() {
  189           if (elementStack == null) {
  190               return 0;
  191           }
  192           return elementStack.size();
  193       }
  194   
  195   
  196       /**
  197        * Fetches the current Element.
  198        *
  199        * @return element on top of the stack or
  200        *          <code>null</code> if the root element is <code>null</code>
  201        */
  202       public Element current() {
  203   
  204           if (elementStack == null) {
  205               return first();
  206           }
  207   
  208           /*
  209             get a handle to the element on top of the stack.
  210           */
  211           if (! elementStack.empty()) {
  212               StackItem item = elementStack.peek();
  213               Element elem = item.getElement();
  214               int index = item.getIndex();
  215               // self reference
  216               if (index == -1) {
  217                   return elem;
  218               }
  219               // return the child at location "index".
  220               return elem.getElement(index);
  221           }
  222           return null;
  223       }
  224   
  225   
  226       /**
  227        * Fetches the next Element. The strategy
  228        * used to locate the next element is
  229        * a depth-first search.
  230        *
  231        * @return the next element or <code>null</code>
  232        *          at the end of the list.
  233        */
  234       public Element next() {
  235   
  236           /* if current() has not been invoked
  237              and next is invoked, the very first
  238              element will be returned. */
  239           if (elementStack == null) {
  240               return first();
  241           }
  242   
  243           // no more elements
  244           if (elementStack.isEmpty()) {
  245               return null;
  246           }
  247   
  248           // get a handle to the element on top of the stack
  249   
  250           StackItem item = elementStack.peek();
  251           Element elem = item.getElement();
  252           int index = item.getIndex();
  253   
  254           if (index+1 < elem.getElementCount()) {
  255               Element child = elem.getElement(index+1);
  256               if (child.isLeaf()) {
  257                   /* In this case we merely want to increment
  258                      the child index of the item on top of the
  259                      stack.*/
  260                   item.incrementIndex();
  261               } else {
  262                   /* In this case we need to push the child(branch)
  263                      on the stack so that we can iterate over its
  264                      children. */
  265                   elementStack.push(new StackItem(child));
  266               }
  267               return child;
  268           } else {
  269               /* No more children for the item on top of the
  270                  stack therefore pop the stack. */
  271               elementStack.pop();
  272               if (!elementStack.isEmpty()) {
  273                   /* Increment the child index for the item that
  274                      is now on top of the stack. */
  275                   StackItem top = elementStack.peek();
  276                   top.incrementIndex();
  277                   /* We now want to return its next child, therefore
  278                      call next() recursively. */
  279                   return next();
  280               }
  281           }
  282           return null;
  283       }
  284   
  285   
  286       /**
  287        * Fetches the previous Element. If howver the current
  288        * element is the last element, or the current element
  289        * is null, then null is returned.
  290        *
  291        * @return previous <code>Element</code> if available
  292        *
  293        */
  294       public Element previous() {
  295   
  296           int stackSize;
  297           if (elementStack == null || (stackSize = elementStack.size()) == 0) {
  298               return null;
  299           }
  300   
  301           // get a handle to the element on top of the stack
  302           //
  303           StackItem item = elementStack.peek();
  304           Element elem = item.getElement();
  305           int index = item.getIndex();
  306   
  307           if (index > 0) {
  308               /* return child at previous index. */
  309               return getDeepestLeaf(elem.getElement(--index));
  310           } else if (index == 0) {
  311               /* this implies that current is the element's
  312                  first child, therefore previous is the
  313                  element itself. */
  314               return elem;
  315           } else if (index == -1) {
  316               if (stackSize == 1) {
  317                   // current is the root, nothing before it.
  318                   return null;
  319               }
  320               /* We need to return either the item
  321                  below the top item or one of the
  322                  former's children. */
  323               StackItem top = elementStack.pop();
  324               item = elementStack.peek();
  325   
  326               // restore the top item.
  327               elementStack.push(top);
  328               elem = item.getElement();
  329               index = item.getIndex();
  330               return ((index == -1) ? elem : getDeepestLeaf(elem.getElement
  331                                                             (index)));
  332           }
  333           // should never get here.
  334           return null;
  335       }
  336   
  337       /**
  338        * Returns the last child of <code>parent</code> that is a leaf. If the
  339        * last child is a not a leaf, this method is called with the last child.
  340        */
  341       private Element getDeepestLeaf(Element parent) {
  342           if (parent.isLeaf()) {
  343               return parent;
  344           }
  345           int childCount = parent.getElementCount();
  346           if (childCount == 0) {
  347               return parent;
  348           }
  349           return getDeepestLeaf(parent.getElement(childCount - 1));
  350       }
  351   
  352       /*
  353         Iterates through the element tree and prints
  354         out each element and its attributes.
  355       */
  356       private void dumpTree() {
  357   
  358           Element elem;
  359           while (true) {
  360               if ((elem = next()) != null) {
  361                   System.out.println("elem: " + elem.getName());
  362                   AttributeSet attr = elem.getAttributes();
  363                   String s = "";
  364                   Enumeration names = attr.getAttributeNames();
  365                   while (names.hasMoreElements()) {
  366                       Object key = names.nextElement();
  367                       Object value = attr.getAttribute(key);
  368                       if (value instanceof AttributeSet) {
  369                           // don't go recursive
  370                           s = s + key + "=**AttributeSet** ";
  371                       } else {
  372                           s = s + key + "=" + value + " ";
  373                       }
  374                   }
  375                   System.out.println("attributes: " + s);
  376               } else {
  377                   break;
  378               }
  379           }
  380       }
  381   }

Home » openjdk-7 » javax » swing » text » [javadoc | source]