1 11 package org.eclipse.jdt.internal.corext.fix; 12 13 import java.util.ArrayList ; 14 import java.util.HashMap ; 15 import java.util.Iterator ; 16 import java.util.LinkedList ; 17 import java.util.List ; 18 import java.util.Map ; 19 20 import org.eclipse.text.edits.TextEdit; 21 import org.eclipse.text.edits.UndoEdit; 22 23 import org.eclipse.core.runtime.Assert; 24 import org.eclipse.core.runtime.CoreException; 25 import org.eclipse.core.runtime.IPath; 26 import org.eclipse.core.runtime.IProgressMonitor; 27 import org.eclipse.core.runtime.IStatus; 28 import org.eclipse.core.runtime.NullProgressMonitor; 29 import org.eclipse.core.runtime.Status; 30 import org.eclipse.core.runtime.SubProgressMonitor; 31 import org.eclipse.core.runtime.preferences.DefaultScope; 32 import org.eclipse.core.runtime.preferences.IEclipsePreferences; 33 import org.eclipse.core.runtime.preferences.InstanceScope; 34 35 import org.eclipse.core.filebuffers.FileBuffers; 36 import org.eclipse.core.filebuffers.ITextFileBuffer; 37 import org.eclipse.core.filebuffers.ITextFileBufferManager; 38 import org.eclipse.core.filebuffers.LocationKind; 39 40 import org.eclipse.core.resources.IFile; 41 import org.eclipse.core.resources.IProject; 42 import org.eclipse.core.resources.ProjectScope; 43 44 import org.eclipse.swt.widgets.Shell; 45 46 import org.eclipse.jface.dialogs.Dialog; 47 import org.eclipse.jface.window.Window; 48 49 import org.eclipse.jface.text.BadLocationException; 50 import org.eclipse.jface.text.IDocument; 51 import org.eclipse.jface.text.IDocumentExtension4; 52 53 import org.eclipse.ui.PlatformUI; 54 55 import org.eclipse.ltk.core.refactoring.Change; 56 import org.eclipse.ltk.core.refactoring.CompositeChange; 57 import org.eclipse.ltk.core.refactoring.IRefactoringCoreStatusCodes; 58 import org.eclipse.ltk.core.refactoring.IUndoManager; 59 import org.eclipse.ltk.core.refactoring.NullChange; 60 import org.eclipse.ltk.core.refactoring.PerformChangeOperation; 61 import org.eclipse.ltk.core.refactoring.RefactoringCore; 62 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 63 import org.eclipse.ltk.core.refactoring.TextFileChange; 64 import org.eclipse.ltk.ui.refactoring.RefactoringUI; 65 66 import org.eclipse.jdt.core.ICompilationUnit; 67 import org.eclipse.jdt.core.IJavaProject; 68 import org.eclipse.jdt.core.dom.ASTParser; 69 import org.eclipse.jdt.core.dom.CompilationUnit; 70 71 import org.eclipse.jdt.internal.corext.fix.CleanUpRefactoring.CleanUpChange; 72 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; 73 import org.eclipse.jdt.internal.corext.util.Messages; 74 75 import org.eclipse.jdt.ui.JavaUI; 76 77 import org.eclipse.jdt.internal.ui.actions.ActionUtil; 78 import org.eclipse.jdt.internal.ui.fix.ICleanUp; 79 import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider; 80 import org.eclipse.jdt.internal.ui.javaeditor.saveparticipant.IPostSaveListener; 81 82 public class CleanUpPostSaveListener implements IPostSaveListener { 83 84 private static class CleanUpSaveUndo extends TextFileChange { 85 86 private final IFile fFile; 87 private final UndoEdit[] fUndos; 88 private final long fDocumentStamp; 89 private final long fFileStamp; 90 91 public CleanUpSaveUndo(String name, IFile file, UndoEdit[] undos, long documentStamp, long fileStamp) { 92 super(name, file); 93 Assert.isNotNull(undos); 94 95 fDocumentStamp= documentStamp; 96 fFileStamp= fileStamp; 97 fFile= file; 98 fUndos= undos; 99 } 100 101 public final boolean needsSaving() { 102 return true; 103 } 104 105 108 public Change perform(IProgressMonitor pm) throws CoreException { 109 if (isValid(pm).hasFatalError()) 110 return new NullChange(); 111 112 if (pm == null) 113 pm= new NullProgressMonitor(); 114 115 ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager(); 116 pm.beginTask("", 2); ITextFileBuffer buffer= null; 118 try { 119 manager.connect(fFile.getFullPath(), LocationKind.IFILE, new SubProgressMonitor(pm, 1)); 120 buffer= manager.getTextFileBuffer(fFile.getFullPath(), LocationKind.IFILE); 121 IDocument document= buffer.getDocument(); 122 123 long oldFileValue= fFile.getModificationStamp(); 124 long oldDocValue; 125 if (document instanceof IDocumentExtension4) { 126 oldDocValue= ((IDocumentExtension4)document).getModificationStamp(); 127 } else { 128 oldDocValue= oldFileValue; 129 } 130 131 LinkedList list= new LinkedList (); 133 for (int index= 0; index < fUndos.length; index++) { 134 UndoEdit edit= fUndos[index]; 135 UndoEdit redo= edit.apply(document, TextEdit.CREATE_UNDO); 136 list.addFirst(redo); 137 } 138 139 boolean stampSetted= false; 140 141 if (document instanceof IDocumentExtension4 && fDocumentStamp != IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP) { 142 try { 143 ((IDocumentExtension4)document).replace(0, 0, "", fDocumentStamp); stampSetted= true; 145 } catch (BadLocationException e) { 146 String message= e.getMessage(); 147 if (message == null) 148 message= "BadLocationException"; throw new CoreException(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IRefactoringCoreStatusCodes.BAD_LOCATION, message, e)); 150 } 151 } 152 153 buffer.commit(pm, false); 154 if (!stampSetted) { 155 fFile.revertModificationStamp(fFileStamp); 156 } 157 158 return new CleanUpSaveUndo(getName(), fFile, ((UndoEdit[]) list.toArray(new UndoEdit[list.size()])), oldDocValue, oldFileValue); 159 } catch (BadLocationException e) { 160 String message= e.getMessage(); 161 if (message == null) 162 message= "BadLocationException"; throw new CoreException(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IRefactoringCoreStatusCodes.BAD_LOCATION, message, e)); 164 } finally { 165 if (buffer != null) 166 manager.disconnect(fFile.getFullPath(), LocationKind.IFILE, new SubProgressMonitor(pm, 1)); 167 } 168 } 169 } 170 171 public static final String POSTSAVELISTENER_ID= "org.eclipse.jdt.ui.postsavelistener.cleanup"; private static final String WARNING_VALUE= "warning"; private static final String ERROR_VALUE= "error"; 175 178 public void saved(ICompilationUnit unit, IProgressMonitor monitor) throws CoreException { 179 if (monitor == null) 180 monitor= new NullProgressMonitor(); 181 182 monitor.beginTask(getName(), IProgressMonitor.UNKNOWN); 183 184 try { 185 if (!ActionUtil.isOnBuildPath(unit)) 186 return; 187 188 IProject project= unit.getJavaProject().getProject(); 189 Map settings= CleanUpPreferenceUtil.loadSaveParticipantOptions(new ProjectScope(project)); 190 if (settings == null) { 191 IEclipsePreferences contextNode= new InstanceScope().getNode(JavaUI.ID_PLUGIN); 192 String id= contextNode.get(CleanUpConstants.CLEANUP_ON_SAVE_PROFILE, null); 193 if (id == null) { 194 id= new DefaultScope().getNode(JavaUI.ID_PLUGIN).get(CleanUpConstants.CLEANUP_ON_SAVE_PROFILE, CleanUpConstants.DEFAULT_SAVE_PARTICIPANT_PROFILE); 195 } 196 throw new CoreException(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, Messages.format(FixMessages.CleanUpPostSaveListener_unknown_profile_error_message, id))); 197 } 198 199 ICleanUp[] cleanUps; 200 if (CleanUpConstants.TRUE.equals(settings.get(CleanUpConstants.CLEANUP_ON_SAVE_ADDITIONAL_OPTIONS))) { 201 cleanUps= CleanUpRefactoring.createCleanUps(settings); 202 } else { 203 HashMap filteredSettins= new HashMap (); 204 filteredSettins.put(CleanUpConstants.FORMAT_SOURCE_CODE, settings.get(CleanUpConstants.FORMAT_SOURCE_CODE)); 205 filteredSettins.put(CleanUpConstants.ORGANIZE_IMPORTS, settings.get(CleanUpConstants.ORGANIZE_IMPORTS)); 206 cleanUps= CleanUpRefactoring.createCleanUps(filteredSettins); 207 } 208 209 long oldFileValue= unit.getResource().getModificationStamp(); 210 long oldDocValue= getDocumentStamp((IFile)unit.getResource(), new SubProgressMonitor(monitor, 2)); 211 212 CompositeChange result= new CompositeChange(FixMessages.CleanUpPostSaveListener_SaveAction_ChangeName); 213 LinkedList undoEdits= new LinkedList (); 214 215 IUndoManager manager= RefactoringCore.getUndoManager(); 216 217 try { 218 manager.aboutToPerformChange(result); 219 220 do { 221 RefactoringStatus preCondition= new RefactoringStatus(); 222 for (int i= 0; i < cleanUps.length; i++) { 223 RefactoringStatus conditions= cleanUps[i].checkPreConditions(unit.getJavaProject(), new ICompilationUnit[] {unit}, new SubProgressMonitor(monitor, 5)); 224 preCondition.merge(conditions); 225 } 226 if (showStatus(preCondition) != Window.OK) 227 return; 228 229 Map options= new HashMap (); 230 for (int i= 0; i < cleanUps.length; i++) { 231 Map map= cleanUps[i].getRequiredOptions(); 232 if (map != null) { 233 options.putAll(map); 234 } 235 } 236 237 CompilationUnit ast= null; 238 if (requiresAST(cleanUps, unit)) { 239 ast= createAst(unit, options, new SubProgressMonitor(monitor, 10)); 240 } 241 242 List undoneCleanUps= new ArrayList (); 243 CleanUpChange change= CleanUpRefactoring.calculateChange(ast, unit, cleanUps, undoneCleanUps); 244 245 RefactoringStatus postCondition= new RefactoringStatus(); 246 for (int i= 0; i < cleanUps.length; i++) { 247 RefactoringStatus conditions= cleanUps[i].checkPostConditions(new SubProgressMonitor(monitor, 1)); 248 postCondition.merge(conditions); 249 } 250 if (showStatus(postCondition) != Window.OK) 251 return; 252 253 if (change != null) { 254 result.add(change); 255 256 change.setSaveMode(TextFileChange.LEAVE_DIRTY); 257 change.initializeValidationData(new NullProgressMonitor()); 258 259 PerformChangeOperation performChangeOperation= RefactoringUI.createUIAwareChangeOperation(change); 260 performChangeOperation.setSchedulingRule(unit.getSchedulingRule()); 261 262 performChangeOperation.run(new SubProgressMonitor(monitor, 5)); 263 264 performChangeOperation.getUndoChange(); 265 undoEdits.addFirst(change.getUndoEdit()); 266 } 267 268 cleanUps= (ICleanUp[])undoneCleanUps.toArray(new ICleanUp[undoneCleanUps.size()]); 269 } while (cleanUps.length > 0); 270 } finally { 271 manager.changePerformed(result, true); 272 } 273 274 if (undoEdits.size() > 0) { 275 UndoEdit[] undoEditArray= (UndoEdit[])undoEdits.toArray(new UndoEdit[undoEdits.size()]); 276 CleanUpSaveUndo undo= new CleanUpSaveUndo(result.getName(), (IFile)unit.getResource(), undoEditArray, oldDocValue, oldFileValue); 277 undo.initializeValidationData(new NullProgressMonitor()); 278 manager.addUndo(result.getName(), undo); 279 } 280 } finally { 281 monitor.done(); 282 } 283 } 284 285 private int showStatus(RefactoringStatus status) { 286 if (!status.hasError()) 287 return Window.OK; 288 289 Shell shell= PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); 290 291 Dialog dialog= RefactoringUI.createRefactoringStatusDialog(status, shell, "", false); return dialog.open(); 293 } 294 295 private long getDocumentStamp(IFile file, IProgressMonitor monitor) throws CoreException { 296 final ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager(); 297 final IPath path= file.getFullPath(); 298 299 monitor.beginTask("", 2); 301 ITextFileBuffer buffer= null; 302 try { 303 manager.connect(path, LocationKind.IFILE, new SubProgressMonitor(monitor, 1)); 304 buffer= manager.getTextFileBuffer(path, LocationKind.IFILE); 305 IDocument document= buffer.getDocument(); 306 307 if (document instanceof IDocumentExtension4) { 308 return ((IDocumentExtension4)document).getModificationStamp(); 309 } else { 310 return file.getModificationStamp(); 311 } 312 } finally { 313 if (buffer != null) 314 manager.disconnect(path, LocationKind.IFILE, new SubProgressMonitor(monitor, 1)); 315 monitor.done(); 316 } 317 } 318 319 private boolean requiresAST(ICleanUp[] cleanUps, ICompilationUnit unit) throws CoreException { 320 for (int i= 0; i < cleanUps.length; i++) { 321 if (cleanUps[i].requireAST(unit)) 322 return true; 323 } 324 325 return false; 326 } 327 328 private CompilationUnit createAst(ICompilationUnit unit, Map cleanUpOptions, IProgressMonitor monitor) { 329 IJavaProject project= unit.getJavaProject(); 330 if (compatibleOptions(project, cleanUpOptions)) { 331 CompilationUnit ast= ASTProvider.getASTProvider().getAST(unit, ASTProvider.WAIT_NO, monitor); 332 if (ast != null) 333 return ast; 334 } 335 336 ASTParser parser= ASTParser.newParser(ASTProvider.SHARED_AST_LEVEL); 337 parser.setResolveBindings(true); 338 parser.setProject(project); 339 parser.setSource(unit); 340 Map compilerOptions= RefactoringASTParser.getCompilerOptions(unit.getJavaProject()); 341 compilerOptions.putAll(cleanUpOptions); 342 parser.setCompilerOptions(compilerOptions); 343 344 return (CompilationUnit)parser.createAST(monitor); 345 } 346 347 private boolean compatibleOptions(IJavaProject project, Map cleanUpOptions) { 348 if (cleanUpOptions.size() == 0) 349 return true; 350 351 Map projectOptions= project.getOptions(true); 352 353 for (Iterator iterator= cleanUpOptions.keySet().iterator(); iterator.hasNext();) { 354 String key= (String )iterator.next(); 355 String projectOption= (String )projectOptions.get(key); 356 String cleanUpOption= (String )cleanUpOptions.get(key); 357 if (!strongerEquals(projectOption, cleanUpOption)) 358 return false; 359 } 360 361 return true; 362 } 363 364 private boolean strongerEquals(String projectOption, String cleanUpOption) { 365 if (projectOption == null) 366 return false; 367 368 if (ERROR_VALUE.equals(cleanUpOption)) { 369 return ERROR_VALUE.equals(projectOption); 370 } else if (WARNING_VALUE.equals(cleanUpOption)) { 371 return ERROR_VALUE.equals(projectOption) || WARNING_VALUE.equals(projectOption); 372 } 373 374 return false; 375 } 376 377 380 public String getName() { 381 return FixMessages.CleanUpPostSaveListener_name; 382 } 383 384 387 public String getId() { 388 return POSTSAVELISTENER_ID; 389 } 390 391 } 392 | Popular Tags |