/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.util.viewer.model;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jaxen.BaseXPath;
import org.jaxen.JaxenException;
import org.jaxen.XPath;
import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.LanguageVersionHandler;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.ParseException;
import net.sourceforge.pmd.lang.ast.xpath.DocumentNavigator;
public class ViewerModel {
private static final Logger LOGGER = Logger.getLogger(ViewerModel.class.getName());
private List<ViewerModelListener> listeners;
private Node rootNode;
private List<Node> evaluationResults;
public ViewerModel() {
listeners = new ArrayList<>(5);
}
public Node getRootNode() {
return rootNode;
}
/**
* Commits source code to the model. all existing source will be replaced.
*/
public void commitSource(String source, LanguageVersion languageVersion) {
LanguageVersionHandler languageVersionHandler = languageVersion.getLanguageVersionHandler();
Node node = languageVersionHandler.getParser(languageVersionHandler.getDefaultParserOptions()).parse(null,
new StringReader(source));
rootNode = node;
fireViewerModelEvent(new ViewerModelEvent(this, ViewerModelEvent.CODE_RECOMPILED));
}
/**
* Determines whether the model has a compiled tree at it's disposal.
*
* @return true if there is an AST, false otherwise
*/
public boolean hasCompiledTree() {
return rootNode != null;
}
/**
* Evaluates the given XPath expression against the current tree.
*
* @param xPath
* XPath expression to be evaluated
* @param evaluator
* object which requests the evaluation
*/
public void evaluateXPathExpression(String xPath, Object evaluator) throws ParseException, JaxenException {
try {
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.finest("xPath=" + xPath);
LOGGER.finest("evaluator=" + evaluator);
}
XPath xpath = new BaseXPath(xPath, new DocumentNavigator());
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.finest("xpath=" + xpath);
LOGGER.finest("rootNode=" + rootNode);
}
try {
evaluationResults = xpath.selectNodes(rootNode);
} catch (Exception e) {
LOGGER.finest("selectNodes problem:");
e.printStackTrace(System.err);
}
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.finest("evaluationResults=" + evaluationResults);
}
fireViewerModelEvent(new ViewerModelEvent(evaluator, ViewerModelEvent.PATH_EXPRESSION_EVALUATED));
} catch (JaxenException je) {
je.printStackTrace(System.err);
throw je;
}
}
/**
* Retrieves the results of last evaluation.
*
* @return a list containing the nodes selected by the last XPath expression
* evaluation
*/
public List<Node> getLastEvaluationResults() {
return evaluationResults;
}
/**
* Selects the given node in the AST.
*
* @param node
* node to be selected
* @param selector
* object which requests the selection
*/
public void selectNode(Node node, Object selector) {
fireViewerModelEvent(new ViewerModelEvent(selector, ViewerModelEvent.NODE_SELECTED, node));
}
/**
* Appends the given fragment to the XPath expression.
*
* @param pathFragment
* fragment to be added
* @param appender
* object that is trying to append the fragment
*/
public void appendToXPathExpression(String pathFragment, Object appender) {
fireViewerModelEvent(new ViewerModelEvent(appender, ViewerModelEvent.PATH_EXPRESSION_APPENDED, pathFragment));
}
public void addViewerModelListener(ViewerModelListener l) {
listeners.add(l);
}
public void removeViewerModelListener(ViewerModelListener l) {
listeners.remove(l);
}
protected void fireViewerModelEvent(ViewerModelEvent e) {
for (int i = 0; i < listeners.size(); i++) {
listeners.get(i).viewerModelChanged(e);
}
}
}