Copyright (c) 2000, 2015 IBM Corporation and others.
This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
which accompanies this distribution, and is available at
https://www.eclipse.org/legal/epl-2.0/
SPDX-License-Identifier: EPL-2.0
Contributors:
IBM Corporation - initial API and implementation
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.core.internal.watson;
import org.eclipse.core.internal.dtree.AbstractDataTreeNode;
import org.eclipse.core.internal.dtree.DataTreeNode;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
A class for performing operations on each element in an element tree.
For example, this can be used to print the contents of a tree.
When creating an ElementTree iterator, an element tree and root path must be
supplied. When the iterate()
method is called, a visitor object
must be provided. The visitor is called once for each node of the tree. For
each node, the visitor is passed the entire tree, the object in the tree at
that node, and a callback for requesting the full path of that node.
Example:
// printing a crude representation of the poster child
IElementContentVisitor visitor=
new IElementContentVisitor() {
public boolean visitElement(ElementTree tree, IPathRequestor requestor, Object elementContents) {
System.out.println(requestor.requestPath() + " -> " + elementContents);
return true;
}
});
ElementTreeIterator iterator = new ElementTreeIterator(tree, Path.ROOT);
iterator.iterate(visitor);
/**
* A class for performing operations on each element in an element tree.
* For example, this can be used to print the contents of a tree.
* <p>
* When creating an ElementTree iterator, an element tree and root path must be
* supplied. When the <code>iterate()</code> method is called, a visitor object
* must be provided. The visitor is called once for each node of the tree. For
* each node, the visitor is passed the entire tree, the object in the tree at
* that node, and a callback for requesting the full path of that node.
* <p>
* <b>Example:</b>
* <pre><code>
* // printing a crude representation of the poster child
* IElementContentVisitor visitor=
* new IElementContentVisitor() {
* public boolean visitElement(ElementTree tree, IPathRequestor requestor, Object elementContents) {
* System.out.println(requestor.requestPath() + " -> " + elementContents);
* return true;
* }
* });
* ElementTreeIterator iterator = new ElementTreeIterator(tree, Path.ROOT);
* iterator.iterate(visitor);
* </code></pre>
*/
public class ElementTreeIterator implements IPathRequestor {
//for path requestor
private String[] segments = new String[10];
private int nextFreeSegment;
/* the tree being visited */
private ElementTree tree;
/* the root of the subtree to visit */
private IPath path;
/* the immutable data tree being visited */
private DataTreeNode treeRoot;
Creates a new element tree iterator for visiting the given tree starting
at the given path.
/**
* Creates a new element tree iterator for visiting the given tree starting
* at the given path.
*/
public ElementTreeIterator(ElementTree tree, IPath path) {
this.tree = tree;
this.path = path;
//treeRoot can be null if deleted concurrently
//must copy the tree while owning the tree's monitor to prevent concurrent deletion while creating visitor's copy
synchronized (tree) {
treeRoot = (DataTreeNode) tree.getDataTree().safeCopyCompleteSubtree(path);
}
}
Iterates through the given element tree and visit each element (node)
passing in the element's ID and element object.
/**
* Iterates through the given element tree and visit each element (node)
* passing in the element's ID and element object.
*/
private void doIteration(DataTreeNode node, IElementContentVisitor visitor) {
//push the name of this node to the requestor stack
if (nextFreeSegment >= segments.length) {
grow();
}
segments[nextFreeSegment++] = node.getName();
//do the visit
if (visitor.visitElement(tree, this, node.getData())) {
//recurse
AbstractDataTreeNode[] children = node.getChildren();
int len = children.length;
for (int i = 0; i < len; i++) {
doIteration((DataTreeNode) children[i], visitor);
}
}
//pop the segment from the requestor stack
nextFreeSegment--;
if (nextFreeSegment < 0)
nextFreeSegment = 0;
}
Method grow.
/**
* Method grow.
*/
private void grow() {
//grow the segments array
int oldLen = segments.length;
String[] newPaths = new String[oldLen * 2];
System.arraycopy(segments, 0, newPaths, 0, oldLen);
segments = newPaths;
}
Iterates through this iterator's tree and visits each element in the
subtree rooted at the given path. The visitor is passed each element's
data and a request callback for obtaining the path.
/**
* Iterates through this iterator's tree and visits each element in the
* subtree rooted at the given path. The visitor is passed each element's
* data and a request callback for obtaining the path.
*/
public void iterate(IElementContentVisitor visitor) {
if (path.isRoot()) {
//special visit for root element to use special treeData
if (visitor.visitElement(tree, this, tree.getTreeData())) {
if (treeRoot == null)
return;
AbstractDataTreeNode[] children = treeRoot.getChildren();
int len = children.length;
for (int i = 0; i < len; i++) {
AbstractDataTreeNode node = children[i];
if (node instanceof DataTreeNode) {
doIteration((DataTreeNode) node, visitor);
}
}
}
} else {
if (treeRoot == null)
return;
push(path, path.segmentCount() - 1);
doIteration(treeRoot, visitor);
}
}
Push the first "toPush" segments of this path.
/**
* Push the first "toPush" segments of this path.
*/
private void push(IPath pathToPush, int toPush) {
if (toPush <= 0)
return;
for (int i = 0; i < toPush; i++) {
if (nextFreeSegment >= segments.length) {
grow();
}
segments[nextFreeSegment++] = pathToPush.segment(i);
}
}
@Override
public String requestName() {
if (nextFreeSegment == 0)
return ""; //$NON-NLS-1$
return segments[nextFreeSegment - 1];
}
@Override
public IPath requestPath() {
if (nextFreeSegment == 0)
return Path.ROOT;
int length = nextFreeSegment;
for (int i = 0; i < nextFreeSegment; i++) {
length += segments[i].length();
}
StringBuilder pathBuf = new StringBuilder(length);
for (int i = 0; i < nextFreeSegment; i++) {
pathBuf.append('/');
pathBuf.append(segments[i]);
}
return new Path(null, pathBuf.toString());
}
}