blob: b418efe0340cf057173bf8ada3b5edd542758b9e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.css.core.util;
import java.util.ArrayList;
import java.util.Stack;
import java.util.Vector;
import org.eclipse.wst.css.core.document.ICSSImportRule;
import org.eclipse.wst.css.core.document.ICSSModel;
import org.eclipse.wst.css.core.document.ICSSNode;
import org.eclipse.wst.css.core.document.ICSSStyleSheet;
/**
*
*/
public abstract class AbstractCssTraverser {
public static short TRAV_CONT = 0;
public static short TRAV_PRUNE = 1;
public static short TRAV_STOP = 2;
protected java.util.Stack travStack;
private boolean fTraverseImported = false;
private boolean fTraverseImportFirst = false;
private java.util.Vector traversedSheets;
/**
* CssPropCMNode constructor comment.
*/
public AbstractCssTraverser() {
super();
}
/**
* @param model
* org.eclipse.wst.css.core.model.interfaces.ICSSModel
*/
public final void apply(ICSSModel model) {
apply(model.getDocument());
}
/**
* @param root
* com.ibm.sed.css.interfaces.ICSSNode
*/
public final void apply(ICSSNode root) {
travStack = new Stack();
if (fTraverseImported) {
traversedSheets = new Vector();
if (root != null && root.getOwnerDocument() != null && root.getOwnerDocument().getNodeType() == ICSSNode.STYLESHEET_NODE) {
traversedSheets.add(root.getOwnerDocument());
}
}
// first call begin()
begin(root);
// traverse
traverse(root);
// last call end()
end(root);
}
/**
* @return short
* @param node
* com.ibm.sed.css.interfaces.ICSSNode
*/
protected void begin(ICSSNode node) {
}
/**
* @param node
* com.ibm.sed.css.interfaces.ICSSNode
*/
protected void end(ICSSNode node) {
}
/**
* @return boolean
*/
public final boolean isTraverseImported() {
return fTraverseImported;
}
/**
* @return short
* @param node
* com.ibm.sed.css.interfaces.ICSSNode
*/
protected short postNode(ICSSNode node) {
return (short) 0;
}
/**
* @return short
* @param node
* com.ibm.sed.css.interfaces.ICSSNode
*/
protected short preNode(ICSSNode node) {
return (short) 0;
}
/**
* @param newTraverseImported
* boolean
*/
public final void setTraverseImported(boolean newTraverseImported) {
fTraverseImported = newTraverseImported;
}
/**
* @param newTraverseImportFirst
* boolean
*/
public final void setTraverseImportFirst(boolean newTraverseImportFirst) {
fTraverseImportFirst = newTraverseImportFirst;
}
/**
* @return short
* @param node
* com.ibm.sed.css.interfaces.ICSSNode
*/
private final short traverse(ICSSNode node) {
if (node == null)
return TRAV_CONT;
travStack.push(node);
// pre-action
short ret = preNode(node);
if (ret == TRAV_CONT) {
if (fTraverseImported && (node.getNodeType() == ICSSNode.IMPORTRULE_NODE)) {
ICSSImportRule rule = (ICSSImportRule) node;
// traverse external style-sheet
ICSSStyleSheet sheet = (ICSSStyleSheet) rule.getStyleSheet();
if (sheet != null && !traversedSheets.contains(sheet)) { // prevent
// loop
traversedSheets.add(sheet);
short retExt = traverse(sheet);
if (retExt == TRAV_STOP) {
travStack.pop();
return retExt;
}
}
}
// collect children
ArrayList children = new ArrayList();
ICSSNode child = node.getFirstChild();
if (fTraverseImportFirst) {
ArrayList others = new ArrayList();
while (child != null) {
if (child.getNodeType() == ICSSNode.IMPORTRULE_NODE)
children.add(child);
else
others.add(child);
child = child.getNextSibling();
}
children.addAll(others);
}
else {
while (child != null) {
children.add(child);
child = child.getNextSibling();
}
}
// traverse children
for (int i = 0; i < children.size(); i++) {
child = (ICSSNode) children.get(i);
short retChild = traverse(child);
if (retChild == TRAV_STOP) {
travStack.pop();
return retChild;
}
}
}
else if (ret == TRAV_STOP) {
travStack.pop();
return ret;
}
// post-action
ret = postNode(node);
travStack.pop();
return (ret == TRAV_PRUNE) ? TRAV_CONT : ret;
}
}