1 11 package org.eclipse.ltk.internal.core.refactoring; 12 13 import java.util.ArrayList ; 14 import java.util.List ; 15 16 import org.eclipse.core.runtime.CoreException; 17 import org.eclipse.core.runtime.IAdaptable; 18 import org.eclipse.core.runtime.IProgressMonitor; 19 import org.eclipse.core.runtime.IStatus; 20 import org.eclipse.core.runtime.NullProgressMonitor; 21 import org.eclipse.core.runtime.Status; 22 import org.eclipse.core.runtime.SubProgressMonitor; 23 24 import org.eclipse.core.commands.ExecutionException; 25 import org.eclipse.core.commands.operations.IAdvancedUndoableOperation; 26 import org.eclipse.core.commands.operations.IUndoContext; 27 import org.eclipse.core.commands.operations.IUndoableOperation; 28 import org.eclipse.core.commands.operations.OperationHistoryEvent; 29 30 import org.eclipse.core.resources.IWorkspaceRunnable; 31 import org.eclipse.core.resources.ResourcesPlugin; 32 33 import org.eclipse.ltk.core.refactoring.Change; 34 import org.eclipse.ltk.core.refactoring.IValidationCheckResultQuery; 35 import org.eclipse.ltk.core.refactoring.RefactoringCore; 36 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 37 38 public class UndoableOperation2ChangeAdapter implements IUndoableOperation, IAdvancedUndoableOperation { 39 40 private String fLabel; 41 private String fDescription; 42 private Change fExecuteChange; 43 private Change fUndoChange; 44 private Change fRedoChange; 45 private Change fActiveChange; 46 47 private List fContexts= new ArrayList (); 48 49 private static class ContextAdapter implements IAdaptable { 50 private IAdaptable fInfoAdapter; 51 private String fTitle; 52 public ContextAdapter(IAdaptable infoAdapter, String title) { 53 fInfoAdapter= infoAdapter; 54 fTitle= title; 55 } 56 public Object getAdapter(Class adapter) { 57 if (String .class.equals(adapter)) 58 return fTitle; 59 return fInfoAdapter.getAdapter(adapter); 60 } 61 } 62 63 private static class ExecuteResult { 64 boolean changeExecuted; 65 boolean changeExecutionFailed; 66 Change reverseChange; 67 RefactoringStatus validationStatus; 68 public ExecuteResult() { 69 validationStatus= new RefactoringStatus(); 70 } 71 } 72 73 public UndoableOperation2ChangeAdapter(Change change) { 74 fExecuteChange= change; 75 fActiveChange= change; 76 } 77 78 public void setUndoChange(Change undoChange) { 79 fUndoChange= undoChange; 80 fActiveChange= fUndoChange; 81 fExecuteChange= null; 82 fRedoChange= null; 83 } 84 85 public Change getChange() { 86 return fActiveChange; 87 } 88 89 public void setLabel(String label) { 90 fLabel= label; 91 } 92 93 public String getLabel() { 94 if (fLabel != null) 95 return fLabel; 96 return fActiveChange.getName(); 97 } 98 99 public String getDescription() { 100 if (fDescription != null) 101 return fDescription; 102 return fActiveChange.getName(); 103 } 104 105 public Object [] getAffectedObjects() { 106 if (fActiveChange == null) 107 return null; 108 return fActiveChange.getAffectedObjects(); 109 } 110 111 public void addContext(IUndoContext context) { 112 if (!fContexts.contains(context)) 113 fContexts.add(context); 114 } 115 116 public boolean hasContext(IUndoContext context) { 117 if (context == null) 118 return false; 119 for (int i = 0; i< fContexts.size(); i++) { 120 IUndoContext otherContext = (IUndoContext)fContexts.get(i); 121 if (context.matches(otherContext) || otherContext.matches(context)) 124 return true; 125 } 126 return false; 127 } 128 129 public void removeContext(IUndoContext context) { 130 fContexts.remove(context); 131 } 132 133 public IUndoContext[] getContexts() { 134 return (IUndoContext[])fContexts.toArray(new IUndoContext[fContexts.size()]); 135 } 136 137 public boolean canExecute() { 138 return fExecuteChange != null; 139 } 140 141 public IStatus execute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { 142 if (monitor == null) 143 monitor= new NullProgressMonitor(); 144 try { 145 ExecuteResult result= executeChange( 146 getQuery( 147 info, 148 RefactoringCoreMessages.Refactoring_execute_label), 149 monitor); 150 if (!result.changeExecuted) { 151 return createStatus(result); 152 } 153 fUndoChange= result.reverseChange; 154 fActiveChange= fUndoChange; 155 fExecuteChange= null; 156 return new Status(IStatus.OK, RefactoringCorePlugin.getPluginId(), 0, "", null); } catch (CoreException e) { 158 throw new ExecutionException(e.getStatus().getMessage(), e); 159 } 160 } 161 162 public boolean canUndo() { 163 return fUndoChange != null; 164 } 165 166 public IStatus undo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { 167 if (monitor == null) 168 monitor= new NullProgressMonitor(); 169 try { 170 ExecuteResult result= executeChange( 171 getQuery( 172 info, 173 RefactoringCoreMessages.Refactoring_undo_label), 174 monitor); 175 if (!result.changeExecuted) { 176 fUndoChange= null; 177 fRedoChange= null; 178 clearActiveChange(); 179 return createStatus(result); 180 } 181 fRedoChange= result.reverseChange; 182 fActiveChange= fRedoChange; 183 fUndoChange= null; 184 return new Status(IStatus.OK, RefactoringCorePlugin.getPluginId(), 0, "", null); } catch (CoreException e) { 186 throw new ExecutionException(e.getStatus().getMessage(), e); 187 } 188 } 189 190 public IStatus computeUndoableStatus(IProgressMonitor monitor) throws ExecutionException { 191 if (fUndoChange == null) 192 return new Status(IStatus.ERROR, RefactoringCorePlugin.getPluginId(), IStatus.ERROR, 193 RefactoringCoreMessages.UndoableOperation2ChangeAdapter_no_undo_available, 194 null); 195 try { 196 if (monitor == null) 197 monitor= new NullProgressMonitor(); 198 RefactoringStatus status= fUndoChange.isValid(monitor); 199 if (status.hasFatalError()) { 200 fUndoChange= null; 202 clearActiveChange(); 203 return asStatus(status); 204 } else { 205 return new Status(IStatus.OK, RefactoringCorePlugin.getPluginId(), IStatus.OK, "", null); } 210 } catch (CoreException e) { 211 throw new ExecutionException(e.getStatus().getMessage(), e); 212 } 213 } 214 215 public boolean canRedo() { 216 return fRedoChange != null; 217 } 218 219 public IStatus redo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { 220 if (monitor == null) 221 monitor= new NullProgressMonitor(); 222 try { 223 ExecuteResult result= executeChange( 224 getQuery( 225 info, 226 RefactoringCoreMessages.Refactoring_redo_label), 227 monitor); 228 if (!result.changeExecuted) { 229 fUndoChange= null; 230 fRedoChange= null; 231 clearActiveChange(); 232 return createStatus(result); 233 } 234 fUndoChange= result.reverseChange; 235 fActiveChange= fUndoChange; 236 fRedoChange= null; 237 return new Status(IStatus.OK, RefactoringCorePlugin.getPluginId(), 0, "", null); } catch (CoreException e) { 239 throw new ExecutionException(e.getStatus().getMessage(), e); 240 } 241 } 242 243 public IStatus computeRedoableStatus(IProgressMonitor monitor) throws ExecutionException { 244 if (fRedoChange == null) 245 return new Status(IStatus.ERROR, RefactoringCorePlugin.getPluginId(), IStatus.ERROR, 246 RefactoringCoreMessages.UndoableOperation2ChangeAdapter_no_redo_available, 247 null); 248 try { 249 if (monitor == null) 250 monitor= new NullProgressMonitor(); 251 RefactoringStatus status= fRedoChange.isValid(monitor); 252 if (status.hasFatalError()) { 253 fRedoChange= null; 255 clearActiveChange(); 256 return asStatus(status); 257 } else { 258 return new Status(IStatus.OK, RefactoringCorePlugin.getPluginId(), IStatus.OK, "", null); } 263 } catch (CoreException e) { 264 throw new ExecutionException(e.getStatus().getMessage(), e); 265 } 266 } 267 268 public void aboutToNotify(OperationHistoryEvent event) { 269 switch(event.getEventType()) { 270 case OperationHistoryEvent.ABOUT_TO_EXECUTE: 271 case OperationHistoryEvent.ABOUT_TO_UNDO: 272 case OperationHistoryEvent.ABOUT_TO_REDO: 273 case OperationHistoryEvent.DONE: 274 case OperationHistoryEvent.UNDONE: 275 case OperationHistoryEvent.REDONE: 276 case OperationHistoryEvent.OPERATION_NOT_OK: 277 ResourcesPlugin.getWorkspace().checkpoint(false); 278 break; 279 } 280 } 281 282 public void dispose() { 283 if (fActiveChange != null) 285 fActiveChange.dispose(); 286 } 287 288 private ExecuteResult executeChange(final IValidationCheckResultQuery query, IProgressMonitor pm) throws CoreException { 289 final ExecuteResult result= new ExecuteResult(); 290 if (fActiveChange == null || !fActiveChange.isEnabled()) 291 return result; 292 IWorkspaceRunnable runnable= new IWorkspaceRunnable() { 293 public void run(IProgressMonitor monitor) throws CoreException { 294 boolean reverseIsInitialized= false; 295 try { 296 monitor.beginTask("", 11); result.validationStatus= fActiveChange.isValid(new SubProgressMonitor(monitor, 2)); 298 if (result.validationStatus.hasFatalError()) { 299 query.stopped(result.validationStatus); 300 return; 303 } 304 if (!result.validationStatus.isOK() && !query.proceed(result.validationStatus)) { 305 return; 306 } 307 try { 308 result.changeExecutionFailed= true; 309 result.reverseChange= fActiveChange.perform(new SubProgressMonitor(monitor, 9)); 310 result.changeExecutionFailed= false; 311 result.changeExecuted= true; 312 } finally { 313 ResourcesPlugin.getWorkspace().checkpoint(false); 314 } 315 fActiveChange.dispose(); 316 if (result.reverseChange != null) { 317 result.reverseChange.initializeValidationData(new NotCancelableProgressMonitor( 318 new SubProgressMonitor(monitor, 1))); 319 reverseIsInitialized= true; 320 } 321 } catch (CoreException e) { 322 Change ch= result.reverseChange; 323 result.reverseChange= null; 324 if (ch != null && reverseIsInitialized) { 325 ch.dispose(); 326 } 327 throw e; 328 } catch (RuntimeException e) { 329 Change ch= result.reverseChange; 330 result.reverseChange= null; 331 if (ch != null && reverseIsInitialized) { 332 ch.dispose(); 333 } 334 throw e; 335 } finally { 336 monitor.done(); 337 } 338 } 339 }; 340 ResourcesPlugin.getWorkspace().run(runnable, pm); 341 return result; 342 } 343 344 private IStatus createStatus(ExecuteResult result) { 345 if (!result.validationStatus.isOK()) { 346 return result.validationStatus.getEntryWithHighestSeverity().toStatus(); 347 } else { 348 return new Status(IStatus.ERROR, RefactoringCorePlugin.getPluginId(), IStatus.ERROR, 349 RefactoringCoreMessages.UndoableOperation2ChangeAdapter_error_message, 350 null); 351 } 352 } 353 354 private IStatus asStatus(RefactoringStatus status) { 355 if (status.isOK()) { 356 return new Status(IStatus.OK, RefactoringCorePlugin.getPluginId(), IStatus.OK, "", null); } else { 358 return status.getEntryWithHighestSeverity().toStatus(); 359 } 360 } 361 362 private IValidationCheckResultQuery getQuery(IAdaptable info, String title) { 363 if (info == null) 364 return RefactoringCore.getQueryFactory().create(null); 365 IValidationCheckResultQuery result= (IValidationCheckResultQuery)info.getAdapter(IValidationCheckResultQuery.class); 366 if (result != null) 367 return result; 368 ContextAdapter context= new ContextAdapter(info, title); 369 return RefactoringCore.getQueryFactory().create(context); 370 } 371 372 private void clearActiveChange() { 373 if (fLabel == null) { 374 fLabel= fActiveChange.getName(); 375 } 376 if (fDescription == null) { 377 fDescription= fActiveChange.getName(); 378 } 379 fActiveChange.dispose(); 380 fActiveChange= null; 381 } 382 } 383 | Popular Tags |