blob: e9a77fbd2199d14b2f947146f1959efc9882ea91 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.odftoolkit.simple.common.navigation;
import org.odftoolkit.odfdom.dom.element.office.OfficeAnnotationElement;
import org.w3c.dom.Node;
/**
* <code>Navigation</code> is used to navigate the document and find the matched
* element by user defined conditions.
*/
public abstract class Navigation {
/**
* Return true if document still has more matched {@link Selection
* Selection} when traversing the document(in other words return true if
* getNextMatchElement() would return an element instance rather than return
* null)
*
* @return true if document still has more matched Selection, and vice versa
*/
public abstract boolean hasNext();
// public abstract void gotoPrevious();
/**
* Get next {@link Selection Selection} result.
*
* @return the next <code>Selection</code> result
*/
public abstract Selection nextSelection();
/**
* Check if the element is a qualified one.
* <p> Developers can define their own logic here to determine whether an element satisfies the requirements.
*
* @param element
* navigate this element node.
* @return true if the element node match the user defined condition; false
* if not match.
*/
public abstract boolean match(Node element);
/**
* Get the next matched element in the whole element tree.
*
* @param startpoint
* navigate from the start point
* @return the next matched element node
*/
protected Node getNextMatchElement(Node startpoint) {
// match the sub tree up to the root node (parent == null)
return getNextMatchElementInTree(startpoint, null);
}
/**
* Get the next matched element node in a sub tree
*
* @param startpoint
* navigate from the start point
* @param root
* the root of the sub tree
* @return the next matched element
*/
protected Node getNextMatchElementInTree(Node startpoint, Node root) {
Node matchedNode = null;
matchedNode = traverseTree(startpoint);
Node currentpoint = startpoint;
while ((matchedNode == null) && (currentpoint != root)) {
Node sibling = currentpoint.getNextSibling();
if ((sibling != null)
&& (sibling.getNodeType() == Node.TEXT_NODE || sibling.getNodeType() == Node.ELEMENT_NODE)
&& (match(sibling))) {
matchedNode = sibling;
break;
}
while ((sibling != null) && (matchedNode == null)) {
if ((sibling.getNodeType() == Node.TEXT_NODE || sibling.getNodeType() == Node.ELEMENT_NODE)) {
matchedNode = traverseTree(sibling);
}
if (matchedNode == null) {
sibling = sibling.getNextSibling();
if (sibling != null && match(sibling)) {
matchedNode = sibling;
break;
}
}
}
currentpoint = currentpoint.getParentNode();
}
return matchedNode;
}
private Node traverseTree(Node root) {
Node matchedNode = null;
if (root == null) {
return null;
}
// if (match(root)) return root;
Node node = root.getFirstChild();
while (node != null) {
if ((node.getNodeType() == Node.TEXT_NODE || node.getNodeType() == Node.ELEMENT_NODE)
&& (!(node instanceof OfficeAnnotationElement))) {
if (match(node) == true) {
matchedNode = node;
break;
} else {
matchedNode = traverseTree(node);
if (matchedNode != null) {
break;
}
}
}
node = node.getNextSibling();
}
return matchedNode;
}
}