blob: f548b832ac917d045536b556407c567dfc18baff [file] [log] [blame]
package org.eclipse.vex.core.internal.dom;
import java.util.List;
/**
* This visitor creates a deep copy of the visited nodes. Deep copy means a full copy of each visited node and its
* children down to the leaf level. All copied nodes are associated with a given content. The copied nodes on the root
* level are collected in a given List.
*
* @author Florian Thienel
*/
public class DeepCopyVisitor implements INodeVisitor {
private final CopyVisitor copyVisitor = new CopyVisitor();
private final List<Node> rootNodes;
private final Content content;
private final int delta;
private Parent currentParent = null;
/**
* @param rootNodes
* the List to collect the copied nodes on the root level
* @param content
* the content to associate the copied nodes with
* @param delta
* the shift for the content association, relative to the beginning of the first node in the source
* content
*/
public DeepCopyVisitor(final List<Node> rootNodes, final Content content, final int delta) {
this.rootNodes = rootNodes;
this.content = content;
this.delta = delta;
}
public void visit(final Document document) {
throw new UnsupportedOperationException("Document cannot be deep copied");
}
public void visit(final DocumentFragment fragment) {
copyChildren(fragment, null);
}
public void visit(final Element element) {
final Element copy = copy(element);
addToParent(copy);
associate(element, copy);
copyChildren(element, copy);
}
public void visit(final Text text) {
// ignore Text nodes because they are created dynamically in Element.getChildNodes()
}
private <T extends Node> T copy(final T node) {
node.accept(copyVisitor);
return copyVisitor.<T> getCopy();
}
private void addToParent(final Node node) {
if (currentParent == null) {
rootNodes.add(node);
} else {
currentParent.addChild(node);
}
}
private void associate(final Node source, final Node copy) {
if (source.isAssociated()) {
final Range range = source.getRange();
copy.associate(content, range.moveBounds(delta));
}
}
private void copyChildren(final Parent source, final Parent copy) {
final Parent lastParent = currentParent;
for (final Node child : source.getChildNodes()) {
currentParent = copy;
child.accept(this);
}
currentParent = lastParent;
}
}