001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.dom.traversal;
020:
021: import org.apache.batik.dom.AbstractDocument;
022: import org.w3c.dom.DOMException;
023: import org.w3c.dom.Node;
024: import org.w3c.dom.traversal.NodeFilter;
025: import org.w3c.dom.traversal.NodeIterator;
026:
027: /**
028: * This class implements the {@link org.w3c.dom.traversal.NodeIterator}
029: * interface.
030: *
031: * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
032: * @version $Id: DOMNodeIterator.java 478249 2006-11-22 17:29:37Z dvholten $
033: */
034: public class DOMNodeIterator implements NodeIterator {
035:
036: /**
037: * The initial state.
038: */
039: protected static final short INITIAL = 0;
040:
041: /**
042: * The invalid state.
043: */
044: protected static final short INVALID = 1;
045:
046: /**
047: * The forward state.
048: */
049: protected static final short FORWARD = 2;
050:
051: /**
052: * The backward state.
053: */
054: protected static final short BACKWARD = 3;
055:
056: /**
057: * The document which created the iterator.
058: */
059: protected AbstractDocument document;
060:
061: /**
062: * The root node.
063: */
064: protected Node root;
065:
066: /**
067: * Which node types are presented via the iterator.
068: */
069: protected int whatToShow;
070:
071: /**
072: * The NodeFilter used to screen nodes.
073: */
074: protected NodeFilter filter;
075:
076: /**
077: * Whether the children of entity reference nodes are visible
078: * to the iterator.
079: */
080: protected boolean expandEntityReferences;
081:
082: /**
083: * The iterator state.
084: */
085: protected short state;
086:
087: /**
088: * The reference node.
089: */
090: protected Node referenceNode;
091:
092: /**
093: * Creates a new NodeIterator object.
094: * @param doc The document which created the tree walker.
095: * @param n The root node.
096: * @param what Which node types are presented via the iterator.
097: * @param nf The NodeFilter used to screen nodes.
098: * @param exp Whether the children of entity reference nodes are visible
099: * to the iterator.
100: */
101: public DOMNodeIterator(AbstractDocument doc, Node n, int what,
102: NodeFilter nf, boolean exp) {
103: document = doc;
104: root = n;
105: whatToShow = what;
106: filter = nf;
107: expandEntityReferences = exp;
108:
109: referenceNode = root;
110: }
111:
112: /**
113: * <b>DOM</b>: Implements {@link NodeIterator#getRoot()}.
114: */
115: public Node getRoot() {
116: return root;
117: }
118:
119: /**
120: * <b>DOM</b>: Implements {@link NodeIterator#getWhatToShow()}.
121: */
122: public int getWhatToShow() {
123: return whatToShow;
124: }
125:
126: /**
127: * <b>DOM</b>: Implements {@link NodeIterator#getFilter()}.
128: */
129: public NodeFilter getFilter() {
130: return filter;
131: }
132:
133: /**
134: * <b>DOM</b>: Implements {@link NodeIterator#getExpandEntityReferences()}.
135: */
136: public boolean getExpandEntityReferences() {
137: return expandEntityReferences;
138: }
139:
140: /**
141: * <b>DOM</b>: Implements {@link NodeIterator#nextNode()}.
142: */
143: public Node nextNode() {
144: switch (state) {
145: case INVALID:
146: throw document.createDOMException(
147: DOMException.INVALID_STATE_ERR,
148: "detached.iterator", null);
149: case BACKWARD:
150: case INITIAL:
151: state = FORWARD;
152: return referenceNode;
153: case FORWARD:
154: }
155:
156: for (;;) {
157: unfilteredNextNode();
158: if (referenceNode == null) {
159: return null;
160: }
161: if ((whatToShow & (1 << referenceNode.getNodeType() - 1)) != 0) {
162: if (filter == null
163: || filter.acceptNode(referenceNode) == NodeFilter.FILTER_ACCEPT) {
164: return referenceNode;
165: }
166: }
167: }
168: }
169:
170: /**
171: * <b>DOM</b>: Implements {@link NodeIterator#previousNode()}.
172: */
173: public Node previousNode() {
174: switch (state) {
175: case INVALID:
176: throw document.createDOMException(
177: DOMException.INVALID_STATE_ERR,
178: "detached.iterator", null);
179: case FORWARD:
180: case INITIAL:
181: state = BACKWARD;
182: return referenceNode;
183: case BACKWARD:
184: }
185:
186: for (;;) {
187: unfilteredPreviousNode();
188: if (referenceNode == null) {
189: return referenceNode;
190: }
191: if ((whatToShow & (1 << referenceNode.getNodeType() - 1)) != 0) {
192: if (filter == null
193: || filter.acceptNode(referenceNode) == NodeFilter.FILTER_ACCEPT) {
194: return referenceNode;
195: }
196: }
197: }
198: }
199:
200: /**
201: * <b>DOM</b>: Implements {@link NodeIterator#detach()}.
202: */
203: public void detach() {
204: state = INVALID;
205: document.detachNodeIterator(this );
206: }
207:
208: /**
209: * Called by the DOM when a node will be removed from the current document.
210: */
211: public void nodeToBeRemoved(Node removedNode) {
212: if (state == INVALID) {
213: return;
214: }
215:
216: Node node;
217: for (node = referenceNode; node != null && node != root; node = node
218: .getParentNode()) {
219: if (node == removedNode) {
220: break;
221: }
222: }
223: if (node == null || node == root) {
224: return;
225: }
226:
227: if (state == BACKWARD) {
228: // Go to the first child
229: if (node.getNodeType() != Node.ENTITY_REFERENCE_NODE
230: || expandEntityReferences) {
231: Node n = node.getFirstChild();
232: if (n != null) {
233: referenceNode = n;
234: return;
235: }
236: }
237:
238: // Go to the next sibling
239: Node n = node.getNextSibling();
240: if (n != null) {
241: referenceNode = n;
242: return;
243: }
244:
245: // Go to the first sibling of one of the ancestors
246: n = node;
247: while ((n = n.getParentNode()) != null && n != root) {
248: Node t = n.getNextSibling();
249: if (t != null) {
250: referenceNode = t;
251: return;
252: }
253: }
254:
255: referenceNode = null;
256: } else {
257: Node n = node.getPreviousSibling();
258:
259: // Go to the parent of a first child
260: if (n == null) {
261: referenceNode = node.getParentNode();
262: return;
263: }
264:
265: // Go to the last child of child...
266: if (n.getNodeType() != Node.ENTITY_REFERENCE_NODE
267: || expandEntityReferences) {
268: Node t;
269: while ((t = n.getLastChild()) != null) {
270: n = t;
271: }
272: }
273:
274: referenceNode = n;
275: }
276: }
277:
278: /**
279: * Sets the reference node to the next node, unfiltered.
280: */
281: protected void unfilteredNextNode() {
282: if (referenceNode == null) {
283: return;
284: }
285:
286: // Go to the first child
287: if (referenceNode.getNodeType() != Node.ENTITY_REFERENCE_NODE
288: || expandEntityReferences) {
289: Node n = referenceNode.getFirstChild();
290: if (n != null) {
291: referenceNode = n;
292: return;
293: }
294: }
295:
296: // Go to the next sibling
297: Node n = referenceNode.getNextSibling();
298: if (n != null) {
299: referenceNode = n;
300: return;
301: }
302:
303: // Go to the first sibling of one of the ancestors
304: n = referenceNode;
305: while ((n = n.getParentNode()) != null && n != root) {
306: Node t = n.getNextSibling();
307: if (t != null) {
308: referenceNode = t;
309: return;
310: }
311: }
312: referenceNode = null;
313: }
314:
315: /**
316: * Sets the reference node to the previous node, unfiltered.
317: */
318: protected void unfilteredPreviousNode() {
319: if (referenceNode == null) {
320: return;
321: }
322:
323: // The previous of root is null
324: if (referenceNode == root) {
325: referenceNode = null;
326: return;
327: }
328:
329: Node n = referenceNode.getPreviousSibling();
330:
331: // Go to the parent of a first child
332: if (n == null) {
333: referenceNode = referenceNode.getParentNode();
334: return;
335: }
336:
337: // Go to the last child of child...
338: if (n.getNodeType() != Node.ENTITY_REFERENCE_NODE
339: || expandEntityReferences) {
340: Node t;
341: while ((t = n.getLastChild()) != null) {
342: n = t;
343: }
344: }
345:
346: referenceNode = n;
347: }
348: }
|