KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > text > ElementIterator


1 /*
2  * @(#)ElementIterator.java 1.14 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing.text;
9
10 import java.util.Stack JavaDoc;
11 import java.util.Enumeration JavaDoc;
12
13 /**
14  * <p>
15  * ElementIterator, as the name suggests, iteratates over the Element
16  * tree. The constructor can be invoked with either Document or an Element
17  * as an argument. If the constructor is invoked with a Document as an
18  * argument then the root of the iteration is the return value of
19  * document.getDefaultRootElement().
20  *
21  * The iteration happens in a depth-first manner. In terms of how
22  * boundary conditions are handled:
23  * a) if next() is called before first() or current(), the
24  * root will be returned.
25  * b) next() returns null to indicate the end of the list.
26  * c) previous() returns null when the current element is the root
27  * or next() has returned null.
28  *
29  * The ElementIterator does no locking of the Element tree. This means
30  * that it does not track any changes. It is the responsibility of the
31  * user of this class, to ensure that no changes happen during element
32  * iteration.
33  *
34  * Simple usage example:
35  *
36  * public void iterate() {
37  * ElementIterator it = new ElementIterator(root);
38  * Element elem;
39  * while (true) {
40  * if ((elem = next()) != null) {
41  * // process element
42  * System.out.println("elem: " + elem.getName());
43  * } else {
44  * break;
45  * }
46  * }
47  * }
48  *
49  * @author Sunita Mani
50  * @version 1.14 12/19/03
51  *
52  */

53
54 public class ElementIterator implements Cloneable JavaDoc {
55
56
57     private Element JavaDoc root;
58     private Stack JavaDoc elementStack = null;
59
60     /**
61      * The StackItem class stores the element
62      * as well as a child index. If the
63      * index is -1, then the element represented
64      * on the stack is the element itself.
65      * Otherwise, the index functions as as index
66      * into the vector of children of the element.
67      * In this case, the item on the stack
68      * represents the "index"th child of the element
69      *
70      */

71     private class StackItem implements Cloneable JavaDoc {
72     Element JavaDoc item;
73     int childIndex;
74
75     private StackItem(Element JavaDoc elem) {
76         /**
77          * -1 index implies a self reference,
78          * as opposed to an index into its
79          * list of children.
80          */

81         this.item = elem;
82         this.childIndex = -1;
83     }
84
85     private void incrementIndex() {
86         childIndex++;
87     }
88
89     private Element JavaDoc getElement() {
90         return item;
91     }
92
93     private int getIndex() {
94         return childIndex;
95     }
96
97     protected Object JavaDoc clone() throws java.lang.CloneNotSupportedException JavaDoc {
98         return super.clone();
99     }
100     }
101
102     /**
103      * Creates a new ElementIterator. The
104      * root element is taken to get the
105      * default root element of the document.
106      *
107      * @param document a Document.
108      */

109     public ElementIterator(Document JavaDoc document) {
110     root = document.getDefaultRootElement();
111     }
112
113
114     /**
115      * Creates a new ElementIterator.
116      *
117      * @param root the root Element.
118      */

119     public ElementIterator(Element JavaDoc root) {
120     this.root = root;
121     }
122
123
124     /**
125      * Clones the ElementIterator.
126      *
127      * @return a cloned ElementIterator Object.
128      */

129     public synchronized Object JavaDoc clone() {
130
131     try {
132         ElementIterator JavaDoc it = new ElementIterator JavaDoc(root);
133         if (elementStack != null) {
134         it.elementStack = new Stack JavaDoc();
135         for (int i = 0; i < elementStack.size(); i++) {
136             StackItem item = (StackItem)elementStack.elementAt(i);
137             StackItem clonee = (StackItem)item.clone();
138             it.elementStack.push(clonee);
139         }
140         }
141         return it;
142     } catch (CloneNotSupportedException JavaDoc e) {
143         throw new InternalError JavaDoc();
144     }
145     }
146
147
148     /**
149      * Fetches the first element.
150      *
151      * @return an Element.
152      */

153     public Element JavaDoc first() {
154     // just in case...
155
if (root == null) {
156         return null;
157     }
158
159     elementStack = new Stack JavaDoc();
160     if (root.getElementCount() != 0) {
161         elementStack.push(new StackItem(root));
162     }
163     return root;
164     }
165
166     /**
167      * Fetches the current depth of element tree.
168      *
169      * @return the depth.
170      */

171     public int depth() {
172     if (elementStack == null) {
173         return 0;
174     }
175     return elementStack.size();
176     }
177
178
179     /**
180      * Fetches the current Element.
181      *
182      * @return element on top of the stack or
183      * <code>null</code> if the root element is <code>null</code>
184      */

185     public Element JavaDoc current() {
186
187     if (elementStack == null) {
188         return first();
189     }
190
191     /*
192       get a handle to the element on top of the stack.
193     */

194     if (! elementStack.empty()) {
195         StackItem item = (StackItem)elementStack.peek();
196         Element JavaDoc elem = item.getElement();
197         int index = item.getIndex();
198         // self reference
199
if (index == -1) {
200         return elem;
201         }
202         // return the child at location "index".
203
return elem.getElement(index);
204     }
205     return null;
206     }
207
208
209     /**
210      * Fetches the next Element. The strategy
211      * used to locate the next element is
212      * a depth-first search.
213      *
214      * @return the next element or <code>null</code>
215      * at the end of the list.
216      */

217     public Element JavaDoc next() {
218
219     /* if current() has not been invoked
220        and next is invoked, the very first
221        element will be returned. */

222     if (elementStack == null) {
223         return first();
224     }
225
226     // no more elements
227
if (elementStack.isEmpty()) {
228         return null;
229     }
230
231     // get a handle to the element on top of the stack
232

233     StackItem item = (StackItem)elementStack.peek();
234     Element JavaDoc elem = item.getElement();
235     int index = item.getIndex();
236
237     if (index+1 < elem.getElementCount()) {
238         Element JavaDoc child = elem.getElement(index+1);
239         if (child.isLeaf()) {
240         /* In this case we merely want to increment
241            the child index of the item on top of the
242            stack.*/

243         item.incrementIndex();
244         } else {
245         /* In this case we need to push the child(branch)
246            on the stack so that we can iterate over its
247            children. */

248         elementStack.push(new StackItem(child));
249         }
250         return child;
251     } else {
252         /* No more children for the item on top of the
253            stack therefore pop the stack. */

254         elementStack.pop();
255         if (!elementStack.isEmpty()) {
256         /* Increment the child index for the item that
257            is now on top of the stack. */

258         StackItem top = (StackItem)elementStack.peek();
259         top.incrementIndex();
260         /* We now want to return its next child, therefore
261            call next() recursively. */

262         return next();
263         }
264     }
265     return null;
266     }
267
268
269     /**
270      * Fetches the previous Element. If howver the current
271      * element is the last element, or the current element
272      * is null, then null is returned.
273      *
274      * @return previous <code>Element</code> if available
275      *
276      */

277     public Element JavaDoc previous() {
278
279     int stackSize;
280     if (elementStack == null || (stackSize = elementStack.size()) == 0) {
281         return null;
282     }
283
284     // get a handle to the element on top of the stack
285
//
286
StackItem item = (StackItem)elementStack.peek();
287     Element JavaDoc elem = item.getElement();
288     int index = item.getIndex();
289
290     if (index > 0) {
291         /* return child at previous index. */
292         return getDeepestLeaf(elem.getElement(--index));
293     } else if (index == 0) {
294         /* this implies that current is the element's
295            first child, therefore previous is the
296            element itself. */

297         return elem;
298     } else if (index == -1) {
299         if (stackSize == 1) {
300         // current is the root, nothing before it.
301
return null;
302         }
303         /* We need to return either the item
304            below the top item or one of the
305            former's children. */

306         Object JavaDoc top = elementStack.pop();
307         item = (StackItem)elementStack.peek();
308
309         // restore the top item.
310
elementStack.push(top);
311         elem = item.getElement();
312         index = item.getIndex();
313         return ((index == -1) ? elem : getDeepestLeaf(elem.getElement
314                               (index)));
315     }
316     // should never get here.
317
return null;
318     }
319
320     /**
321      * Returns the last child of <code>parent</code> that is a leaf. If the
322      * last child is a not a leaf, this method is called with the last child.
323      */

324     private Element JavaDoc getDeepestLeaf(Element JavaDoc parent) {
325     if (parent.isLeaf()) {
326         return parent;
327     }
328     int childCount = parent.getElementCount();
329     if (childCount == 0) {
330         return parent;
331     }
332     return getDeepestLeaf(parent.getElement(childCount - 1));
333     }
334
335     /*
336       Iterates through the element tree and prints
337       out each element and its attributes.
338     */

339     private void dumpTree() {
340
341     Element JavaDoc elem;
342     while (true) {
343         if ((elem = next()) != null) {
344         System.out.println("elem: " + elem.getName());
345         AttributeSet JavaDoc attr = elem.getAttributes();
346         String JavaDoc s = "";
347         Enumeration JavaDoc names = attr.getAttributeNames();
348         while (names.hasMoreElements()) {
349             Object JavaDoc key = names.nextElement();
350             Object JavaDoc value = attr.getAttribute(key);
351             if (value instanceof AttributeSet JavaDoc) {
352             // don't go recursive
353
s = s + key + "=**AttributeSet** ";
354             } else {
355             s = s + key + "=" + value + " ";
356             }
357         }
358         System.out.println("attributes: " + s);
359         } else {
360         break;
361         }
362     }
363     }
364 }
365
Popular Tags