1 19 20 package org.netbeans.api.java.source; 21 22 import com.sun.source.tree.CompilationUnitTree; 23 import com.sun.source.tree.Tree; 24 import com.sun.tools.javac.api.JavacTaskImpl; 25 import com.sun.tools.javac.code.Source; 26 import com.sun.tools.javac.util.Context; 27 import java.io.IOException ; 28 import java.io.PrintWriter ; 29 import java.io.Writer ; 30 import java.util.ArrayList ; 31 import java.util.Collections ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.logging.Level ; 35 import java.util.logging.Logger ; 36 import javax.swing.text.BadLocationException ; 37 import javax.swing.text.Position.Bias; 38 import javax.tools.JavaFileObject; 39 import org.netbeans.api.java.source.ModificationResult.Difference; 40 import org.netbeans.api.java.source.transform.ChangeSet; 41 import org.netbeans.api.java.source.query.QueryException; 42 import org.netbeans.api.java.source.transform.Transformer; 43 import org.netbeans.modules.java.source.engine.RootTree; 44 import org.netbeans.modules.java.source.builder.UndoListService; 45 import org.netbeans.modules.java.source.builder.ASTService; 46 import org.netbeans.modules.java.source.builder.DefaultEnvironment; 47 import org.netbeans.modules.java.source.builder.TreeFactory; 48 import org.netbeans.modules.java.source.engine.DefaultApplicationContext; 49 import org.netbeans.modules.java.source.engine.EngineEnvironment; 50 import org.netbeans.modules.java.source.engine.ReattributionException; 51 import org.netbeans.modules.java.source.engine.SourceReader; 52 import org.netbeans.modules.java.source.engine.SourceRewriter; 53 import org.netbeans.modules.java.source.save.Commit; 54 import org.openide.cookies.EditorCookie; 55 import org.openide.filesystems.FileObject; 56 import org.openide.filesystems.FileUtil; 57 import org.openide.loaders.DataObject; 58 import org.openide.text.CloneableEditorSupport; 59 60 64 public class WorkingCopy extends CompilationController { 65 66 private EngineEnvironment ce; 67 private ChangeSet changes; 68 private boolean afterCommit = false; 69 private WorkingCopyContext wcc; 70 private TreeMaker treeMaker; 71 72 WorkingCopy(final CompilationInfo delegate) throws IOException { 73 super(delegate); 74 wcc = new WorkingCopyContext(); 75 } 76 77 private synchronized void init() throws ReattributionException { 78 final CompilationUnitTree tree = getCompilationUnit(); 79 if (tree != null) { 80 Context context = getContext(); 81 ASTService model = ASTService.instance(context); 82 List <CompilationUnitTree> units = new ArrayList <CompilationUnitTree>(); 83 units.add(tree); 84 model.setRoot(TreeFactory.instance(context).Root(units)); 85 UndoListService.instance(context).reset(); 86 } 87 88 JavacTaskImpl task = this.delegate.getJavacTask(); 89 ce = new DefaultEnvironment( 90 task, getCompilationUnit(), Source.instance(task.getContext()).name, wcc); 91 treeMaker = new TreeMaker(this, ce.getTreeMaker()); 92 changes = new ChangeSet("<no-description>"); 93 changes.attach(ce); 94 } 95 96 private Context getContext() { 97 return getJavacTask().getContext(); 98 } 99 100 102 EngineEnvironment getCommandEnvironment() { 103 return ce; 104 } 105 106 @Override 107 public JavaSource.Phase toPhase(JavaSource.Phase phase) throws IOException { 108 JavaSource.Phase result = super.toPhase(phase); 109 110 if (result.compareTo(JavaSource.Phase.PARSED) >= 0) { 111 try { 112 init(); 113 } catch (ReattributionException ex) { 114 IOException ioe = new IOException (); 115 ioe.initCause(ex); 116 throw ioe; 117 } 118 } 119 120 return result; 121 } 122 123 public synchronized TreeMaker getTreeMaker() { 124 if (treeMaker == null) 125 throw new IllegalStateException ("Cannot call getTreeMaker before toPhase."); 126 return treeMaker; 127 } 128 129 void run(Transformer t) { 130 if (afterCommit) 131 throw new IllegalStateException ("The run method can't be called on a WorkingCopy instance after the commit"); t.init(); 133 t.attach(ce); 134 t.apply(); 135 t.release(); 136 t.destroy();; 137 } 138 139 void run(Transformer t, Tree tree) { 140 if (afterCommit) 141 throw new IllegalStateException ("The run method can't be called on a WorkingCopy instance after the commit"); t.init(); 143 t.attach(ce); 144 t.apply(tree); 145 t.release(); 146 t.destroy();; 147 } 148 149 ChangeSet getChangeSet() { 150 return changes; 151 } 152 153 168 public synchronized void rewrite(Tree oldTree, Tree newTree) { 169 if (changes == null) 170 throw new IllegalStateException ("Cannot call rewrite before toPhase."); 171 if (oldTree == null || newTree == null) 172 throw new IllegalArgumentException ("Null values are not allowed."); 173 174 changes.rewrite(oldTree, newTree); 175 } 176 177 179 List <Difference> getChanges() throws IOException { 180 if (afterCommit) 181 throw new IllegalStateException ("The commit method can be called only once on a WorkingCopy instance"); afterCommit = true; 183 184 if (changes == null) { 185 return null; 187 } 188 189 try { 190 RootTree newRoot = changes.commit((RootTree)ce.getRootNode()); 191 192 if (changes.hasChanges()) { 193 getCommandEnvironment().getModel().setRoot(newRoot); 194 } 195 196 Commit save = new Commit(this); 197 save.init(); 198 save.attach(ce); 199 save.commit(); 200 save.release(); 201 save.destroy(); 202 return wcc.diffs; 203 } catch (QueryException qe) { 204 Logger.getLogger("global").log(Level.WARNING, qe.getMessage(), qe); 205 return null; 206 } catch (ReattributionException qe) { 207 Logger.getLogger("global").log(Level.WARNING, qe.getMessage(), qe); 208 return null; 209 } 210 } 211 212 214 private class WorkingCopyContext extends DefaultApplicationContext { 215 216 private ArrayList <Difference> diffs = new ArrayList <Difference>(); 217 218 public PrintWriter getOutputWriter(String title) { 219 return new PrintWriter (new Writer () { 221 public void write(char[] cbuf, int off, int len) throws IOException {} 222 public void flush() throws IOException {} 223 public void close() throws IOException {} 224 }, true); 225 } 226 227 private Map <Integer , String > userInfo = Collections.<Integer , String >emptyMap(); 228 229 @Override 230 public void setResult(Object result, String title) { 231 if ("user-info".equals(title)) { 232 userInfo = Map .class.cast(result); 233 } 234 } 235 236 public SourceRewriter getSourceRewriter(JavaFileObject sourcefile) throws IOException { 237 return new Rewriter(); 238 } 239 240 private class Rewriter implements SourceRewriter { 241 242 private int offset = 0; 243 private CloneableEditorSupport ces; 244 245 private Rewriter() throws IOException { 246 FileObject fo = getFileObject(); 247 if (fo != null) { 248 DataObject dObj = DataObject.find(fo); 249 ces = dObj != null ? (CloneableEditorSupport)dObj.getCookie(EditorCookie.class) : null; 250 } 251 if (ces == null) 252 throw new IOException ("Could not find CloneableEditorSupport for " + FileUtil.getFileDisplayName (fo)); } 254 255 public void writeTo(String s) throws IOException , BadLocationException { 256 Difference diff = diffs.size() > 0 ? diffs.get(diffs.size() - 1) : null; 257 if (diff != null && diff.getKind() == Difference.Kind.REMOVE && diff.getEndPosition().getOffset() == offset) { 258 diff.kind = Difference.Kind.CHANGE; 259 diff.newText = s; 260 } else { 261 diffs.add(new Difference(Difference.Kind.INSERT, ces.createPositionRef(offset, Bias.Forward), ces.createPositionRef(offset, Bias.Forward), null, s, userInfo.get(offset))); 262 } 263 } 264 265 public void skipThrough(SourceReader in, int pos) throws IOException , BadLocationException { 266 char[] buf = in.getCharsTo(pos); 267 Difference diff = diffs.size() > 0 ? diffs.get(diffs.size() - 1) : null; 268 if (diff != null && diff.getKind() == Difference.Kind.INSERT && diff.getStartPosition().getOffset() == offset) { 269 diff.kind = Difference.Kind.CHANGE; 270 diff.oldText = new String (buf); 271 } else { 272 diffs.add(new Difference(Difference.Kind.REMOVE, ces.createPositionRef(offset, Bias.Forward), ces.createPositionRef(offset + buf.length, Bias.Forward), new String (buf), null, userInfo.get(offset))); 273 } 274 offset += buf.length; 275 } 276 277 public void copyTo(SourceReader in, int pos) throws IOException { 278 char[] buf = in.getCharsTo(pos); 279 offset += buf.length; 280 } 281 282 public void copyRest(SourceReader in) throws IOException { 283 } 284 285 public void close(boolean save) { 286 } 287 } 288 } 289 } 290 | Popular Tags |