001 package net.sourceforge.pmd.util.viewer.model;
002
003 import java.io.StringReader;
004 import java.util.ArrayList;
005 import java.util.List;
006
007 import net.sourceforge.pmd.lang.LanguageVersion;
008 import net.sourceforge.pmd.lang.ast.Node;
009 import net.sourceforge.pmd.lang.ast.xpath.DocumentNavigator;
010 import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
011 import net.sourceforge.pmd.lang.java.ast.ParseException;
012
013 import org.jaxen.BaseXPath;
014 import org.jaxen.JaxenException;
015 import org.jaxen.XPath;
016
017 public class ViewerModel {
018
019 private List<ViewerModelListener> listeners;
020 private Node rootNode;
021 private List<Node> evaluationResults;
022
023 public ViewerModel() {
024 listeners = new ArrayList<ViewerModelListener>(5);
025 }
026
027 public Node getRootNode() {
028 return rootNode;
029 }
030
031 /**
032 * commits source code to the model.
033 * all existing source will be replaced
034 */
035 public void commitSource(String source, LanguageVersion languageVersion) {
036 ASTCompilationUnit compilationUnit = (ASTCompilationUnit) languageVersion.getLanguageVersionHandler()
037 .getParser().parse(null, new StringReader(source));
038 rootNode = compilationUnit;
039 fireViewerModelEvent(new ViewerModelEvent(this, ViewerModelEvent.CODE_RECOMPILED));
040 }
041
042 /**
043 * determines whether the model has a compiled tree at it's disposal
044 *
045 * @return true if there is an AST, false otherwise
046 */
047 public boolean hasCompiledTree() {
048 return rootNode != null;
049 }
050
051 /**
052 * evaluates the given XPath expression against the current tree
053 *
054 * @param xPath XPath expression to be evaluated
055 * @param evaluator object which requests the evaluation
056 */
057 public void evaluateXPathExpression(String xPath, Object evaluator) throws ParseException, JaxenException {
058 XPath xpath = new BaseXPath(xPath, new DocumentNavigator());
059 evaluationResults = xpath.selectNodes(rootNode);
060 fireViewerModelEvent(new ViewerModelEvent(evaluator, ViewerModelEvent.PATH_EXPRESSION_EVALUATED));
061 }
062
063 /**
064 * retrieves the results of last evaluation
065 *
066 * @return a list containing the nodes selected by the last XPath expression
067 * <p/>
068 * evaluation
069 */
070 public List<Node> getLastEvaluationResults() {
071 return evaluationResults;
072 }
073
074 /**
075 * selects the given node in the AST
076 *
077 * @param node node to be selected
078 * @param selector object which requests the selection
079 */
080 public void selectNode(Node node, Object selector) {
081 fireViewerModelEvent(new ViewerModelEvent(selector, ViewerModelEvent.NODE_SELECTED, node));
082 }
083
084 /**
085 * appends the given fragment to the XPath expression
086 *
087 * @param pathFragment fragment to be added
088 * @param appender object that is trying to append the fragment
089 */
090 public void appendToXPathExpression(String pathFragment, Object appender) {
091 fireViewerModelEvent(new ViewerModelEvent(appender, ViewerModelEvent.PATH_EXPRESSION_APPENDED, pathFragment));
092 }
093
094 public void addViewerModelListener(ViewerModelListener l) {
095 listeners.add(l);
096 }
097
098 public void removeViewerModelListener(ViewerModelListener l) {
099 listeners.remove(l);
100 }
101
102 protected void fireViewerModelEvent(ViewerModelEvent e) {
103 for (int i = 0; i < listeners.size(); i++) {
104 listeners.get(i).viewerModelChanged(e);
105 }
106 }
107 }
|