Source for javax.swing.text.ElementIterator

   1: /* ElementIterator.java --
   2:    Copyright (C) 2005 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package javax.swing.text;
  39: 
  40: import java.util.Stack;
  41: 
  42: /**
  43:  * This class can be used to iterate over the {@link Element} tree of
  44:  * a {@link Document} or an {@link Element}.  This iterator performs
  45:  * an "in-order" traversal -- first it visits a node, then each of the
  46:  * node's children in order.  No locking is performed during the
  47:  * iteration; that is up to the caller.
  48:  */
  49: public class ElementIterator implements Cloneable
  50: {
  51:   /**
  52:    * Uses to track the iteration on the stack.
  53:    */
  54:   private class ElementRef
  55:   {
  56:     /**
  57:      * The element.
  58:      */
  59:     Element element;
  60: 
  61:     /**
  62:      * The child index. -1 means the element itself. >= 0 values mean the
  63:      * n-th child of the element.
  64:      */
  65:     int index;
  66: 
  67:     /**
  68:      * Creates a new ElementRef.
  69:      *
  70:      * @param el the element
  71:      */
  72:     ElementRef(Element el)
  73:     {
  74:       element = el;
  75:       index = -1;
  76:     }
  77:   }
  78: 
  79:   // The root element.
  80:   private Element root;
  81: 
  82:   /**
  83:    * Holds ElementRefs.
  84:    */
  85:   private Stack stack;
  86: 
  87:   /**
  88:    * Create a new ElementIterator to iterate over the given document.
  89:    * @param document the Document over which we iterate
  90:    */
  91:   public ElementIterator(Document document)
  92:   {
  93:     root = document.getDefaultRootElement();
  94:   }
  95: 
  96:   /**
  97:    * Create a new ElementIterator to iterate over the given document.
  98:    * @param root the Document over which we iterate
  99:    */
 100:   public ElementIterator(Element root)
 101:   {
 102:     this.root = root;
 103:   }
 104: 
 105:   /**
 106:    * Returns a new ElementIterator which is a clone of this
 107:    * ElementIterator.
 108:    */
 109:   public Object clone()
 110:   {
 111:     try
 112:       {
 113:         return super.clone();
 114:       }
 115:     catch (CloneNotSupportedException _)
 116:       {
 117:         // Can't happen.
 118:         return null;
 119:       }
 120:   }
 121: 
 122:   /**
 123:    * Returns the current element.
 124:    */
 125:   public Element current()
 126:   {
 127:     Element current;
 128:     if (stack == null)
 129:       current = first();
 130:     else
 131:       {
 132:         current = null;
 133:         if (! stack.isEmpty())
 134:           {
 135:             ElementRef ref = (ElementRef) stack.peek();
 136:             Element el = ref.element;
 137:             int index = ref.index;
 138:             if (index == -1)
 139:               current = el;
 140:             else
 141:               current = el.getElement(index);
 142:           }
 143:       }
 144:     return current;
 145:   }
 146: 
 147:   /**
 148:    * Returns the depth to which we have descended in the tree.
 149:    */
 150:   public int depth()
 151:   {
 152:     int depth = 0;
 153:     if (stack != null)
 154:       depth = stack.size();
 155:     return depth;
 156:   }
 157: 
 158:   /**
 159:    * Returns the first element in the tree.
 160:    */
 161:   public Element first()
 162:   {
 163:     Element first = null;
 164:     if (root != null)
 165:       {
 166:         stack = new Stack();
 167:         if (root.getElementCount() > 0)
 168:           stack.push(new ElementRef(root));
 169:         first = root;
 170:       }
 171:     return first;
 172:   }
 173: 
 174:   /**
 175:    * Advance the iterator and return the next element of the tree,
 176:    * performing an "in-order" traversal.
 177:    */
 178:   public Element next()
 179:   {
 180:     Element next;
 181:     if (stack == null)
 182:       next = first();
 183:     else
 184:       {
 185:         next = null;
 186:         if (! stack.isEmpty())
 187:           {
 188:             ElementRef ref = (ElementRef) stack.peek();
 189:             Element el = ref.element;
 190:             int index = ref.index;
 191:             if (el.getElementCount() > index + 1)
 192:               {
 193:                 Element child = el.getElement(index + 1);
 194:                 if (child.isLeaf())
 195:                   ref.index++;
 196:                 else
 197:                   stack.push(new ElementRef(child));
 198:                 next = child;
 199:                 next = child;
 200:               }
 201:             else
 202:               {
 203:                 stack.pop();
 204:                 if (! stack.isEmpty())
 205:                   {
 206:                     ElementRef top = (ElementRef) stack.peek();
 207:                     top.index++;
 208:                     next = next();
 209:                   }
 210:               }
 211:           }
 212:         // else return null.
 213:       }
 214:     return next;
 215:   }
 216: 
 217:   /**
 218:    * Returns the previous item.  Does not modify the iterator state.
 219:    */
 220:   public Element previous()
 221:   {
 222:     Element previous = null;
 223:     int stackSize;
 224:     if (stack != null && (stackSize = stack.size()) > 0)
 225:       {
 226:         ElementRef ref = (ElementRef) stack.peek();
 227:         Element el = ref.element;
 228:         int index = ref.index;
 229:         if (index > 0)
 230:           {
 231:             previous = deepestLeaf(el.getElement(--index));
 232:           }
 233:         else if (index == 0)
 234:           {
 235:             previous = el;
 236:           }
 237:         else if (index == -1)
 238:           {
 239:             ElementRef top = (ElementRef) stack.pop();
 240:             ElementRef item = (ElementRef) stack.peek();
 241:             stack.push(top);
 242:             index = item.index;
 243:             el = item.element;
 244:             previous = index == -1 ? el : deepestLeaf(el.getElement(index));
 245:           }
 246:       }
 247:     return previous;
 248:   }
 249: 
 250:   /**
 251:    * Determines and returns the deepest leaf of the element <code>el</code>.
 252:    *
 253:    * @param el the base element
 254:    *
 255:    * @returnthe deepest leaf of the element <code>el</code>
 256:    */
 257:   private Element deepestLeaf(Element el)
 258:   {
 259:     Element leaf;
 260:     if (el.isLeaf())
 261:       leaf = el;
 262:     else
 263:       {
 264:         int count = el.getElementCount();
 265:         if (count == 0)
 266:           leaf = el;
 267:         else
 268:           leaf = deepestLeaf(el.getElement(count - 1));
 269:       }
 270:     return leaf;
 271:   }
 272: }