ViewerModel.java
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 = (ASTCompilationUnitlanguageVersion.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 evaluatorthrows 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 }