1 11 package org.eclipse.ltk.internal.core.refactoring; 12 13 import org.eclipse.core.runtime.CoreException; 14 import org.eclipse.core.runtime.IAdaptable; 15 import org.eclipse.core.runtime.IProgressMonitor; 16 import org.eclipse.core.runtime.ISafeRunnable; 17 import org.eclipse.core.runtime.IStatus; 18 import org.eclipse.core.runtime.ListenerList; 19 import org.eclipse.core.runtime.SafeRunner; 20 import org.eclipse.core.runtime.Status; 21 22 import org.eclipse.core.commands.ExecutionException; 23 import org.eclipse.core.commands.operations.IOperationHistory; 24 import org.eclipse.core.commands.operations.IOperationHistoryListener; 25 import org.eclipse.core.commands.operations.IUndoableOperation; 26 import org.eclipse.core.commands.operations.OperationHistoryEvent; 27 import org.eclipse.core.commands.operations.OperationHistoryFactory; 28 import org.eclipse.core.commands.operations.TriggeredOperations; 29 30 import org.eclipse.ltk.core.refactoring.Change; 31 import org.eclipse.ltk.core.refactoring.IUndoManager; 32 import org.eclipse.ltk.core.refactoring.IUndoManagerListener; 33 import org.eclipse.ltk.core.refactoring.IValidationCheckResultQuery; 34 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 35 36 public class UndoManager2 implements IUndoManager { 37 38 private class OperationHistroyListener implements IOperationHistoryListener { 39 public void historyNotification(OperationHistoryEvent event) { 40 IUndoableOperation op= event.getOperation(); 41 if (op instanceof TriggeredOperations) { 42 op= ((TriggeredOperations)op).getTriggeringOperation(); 43 } 44 UndoableOperation2ChangeAdapter changeOperation= null; 45 if (op instanceof UndoableOperation2ChangeAdapter) { 46 changeOperation= (UndoableOperation2ChangeAdapter)op; 47 } 48 if (changeOperation == null) 49 return; 50 Change change= changeOperation.getChange(); 51 switch(event.getEventType()) { 52 case OperationHistoryEvent.ABOUT_TO_EXECUTE: 53 case OperationHistoryEvent.ABOUT_TO_UNDO: 54 case OperationHistoryEvent.ABOUT_TO_REDO: 55 fireAboutToPerformChange(change); 56 break; 57 case OperationHistoryEvent.DONE: 58 case OperationHistoryEvent.UNDONE: 59 case OperationHistoryEvent.REDONE: 60 fireChangePerformed(change); 61 fireUndoStackChanged(); 62 fireRedoStackChanged(); 63 break; 64 case OperationHistoryEvent.OPERATION_NOT_OK: 65 fireChangePerformed(change); 66 break; 67 case OperationHistoryEvent.OPERATION_ADDED: 68 fireUndoStackChanged(); 70 fireRedoStackChanged(); 71 break; 72 case OperationHistoryEvent.OPERATION_REMOVED: 73 fireUndoStackChanged(); 75 fireRedoStackChanged(); 76 break; 77 } 78 } 79 } 80 81 private static class NullQuery implements IValidationCheckResultQuery { 82 public boolean proceed(RefactoringStatus status) { 83 return true; 84 } 85 public void stopped(RefactoringStatus status) { 86 } 88 } 89 90 private static class QueryAdapter implements IAdaptable { 91 private IValidationCheckResultQuery fQuery; 92 public QueryAdapter(IValidationCheckResultQuery query) { 93 fQuery= query; 94 } 95 public Object getAdapter(Class adapter) { 96 if (IValidationCheckResultQuery.class.equals(adapter)) 97 return fQuery; 98 return null; 99 } 100 } 101 102 private IOperationHistory fOperationHistroy; 103 private IOperationHistoryListener fOperationHistoryListener; 104 105 private boolean fIsOpen; 106 private TriggeredOperations fActiveOperation; 107 108 private ListenerList fListeners; 109 110 public UndoManager2() { 111 fOperationHistroy= OperationHistoryFactory.getOperationHistory(); 112 } 113 114 public void addListener(IUndoManagerListener listener) { 115 if (fListeners == null) { 116 fListeners= new ListenerList(ListenerList.IDENTITY); 117 fOperationHistoryListener= new OperationHistroyListener(); 118 fOperationHistroy.addOperationHistoryListener(fOperationHistoryListener); 119 } 120 fListeners.add(listener); 121 } 122 123 public void removeListener(IUndoManagerListener listener) { 124 if (fListeners == null) 125 return; 126 fListeners.remove(listener); 127 if (fListeners.size() == 0) { 128 fOperationHistroy.removeOperationHistoryListener(fOperationHistoryListener); 129 fListeners= null; 130 fOperationHistoryListener= null; 131 } 132 } 133 134 public void aboutToPerformChange(Change change) { 135 IUndoableOperation operation= new UndoableOperation2ChangeAdapter(change); 136 operation.addContext(RefactoringCorePlugin.getUndoContext()); 137 fActiveOperation= new TriggeredOperations(operation, fOperationHistroy); 138 fActiveOperation.addContext(RefactoringCorePlugin.getUndoContext()); 139 fOperationHistroy.openOperation(fActiveOperation, IOperationHistory.EXECUTE); 140 fIsOpen= true; 141 } 142 143 public void changePerformed(Change change) { 144 changePerformed(change, true); 145 } 146 147 public void changePerformed(Change change, boolean successful) { 148 if (fIsOpen && fActiveOperation != null) { 149 fOperationHistroy.closeOperation(successful, false, IOperationHistory.EXECUTE); 150 fIsOpen= false; 151 } 152 } 153 154 public void addUndo(String name, Change change) { 155 if (fActiveOperation != null) { 156 UndoableOperation2ChangeAdapter operation= (UndoableOperation2ChangeAdapter)fActiveOperation.getTriggeringOperation(); 157 operation.setUndoChange(change); 158 operation.setLabel(name); 159 fOperationHistroy.add(fActiveOperation); 160 fActiveOperation= null; 161 } 162 } 163 164 public boolean anythingToUndo() { 165 return fOperationHistroy.canUndo(RefactoringCorePlugin.getUndoContext()); 166 } 167 168 public String peekUndoName() { 169 IUndoableOperation op= fOperationHistroy.getUndoOperation(RefactoringCorePlugin.getUndoContext()); 170 if (op == null) 171 return null; 172 return op.getLabel(); 173 } 174 175 public void performUndo(IValidationCheckResultQuery query, IProgressMonitor pm) throws CoreException { 176 IUndoableOperation undo= fOperationHistroy.getUndoOperation(RefactoringCorePlugin.getUndoContext()); 177 UndoableOperation2ChangeAdapter changeOperation= getUnwrappedOperation(undo); 178 if (changeOperation == null) 179 throw new CoreException(new Status(IStatus.ERROR, RefactoringCorePlugin.getPluginId(), 180 IStatus.ERROR, RefactoringCoreMessages.UndoManager2_no_change, null)); 181 if (query == null) 182 query= new NullQuery(); 183 try { 184 fOperationHistroy.undoOperation(undo, pm, new QueryAdapter(query)); 185 } catch (ExecutionException e) { 186 handleException(e); 187 } 188 } 189 190 public boolean anythingToRedo() { 191 return fOperationHistroy.canRedo(RefactoringCorePlugin.getUndoContext()); 192 } 193 194 public String peekRedoName() { 195 IUndoableOperation op= fOperationHistroy.getRedoOperation(RefactoringCorePlugin.getUndoContext()); 196 if (op == null) 197 return null; 198 return op.getLabel(); 199 } 200 201 public void performRedo(IValidationCheckResultQuery query, IProgressMonitor pm) throws CoreException { 202 IUndoableOperation redo= fOperationHistroy.getRedoOperation(RefactoringCorePlugin.getUndoContext()); 203 UndoableOperation2ChangeAdapter changeOperation= getUnwrappedOperation(redo); 204 if (changeOperation == null) 205 throw new CoreException(new Status(IStatus.ERROR, RefactoringCorePlugin.getPluginId(), 206 IStatus.ERROR, RefactoringCoreMessages.UndoManager2_no_change, null)); 207 if (query == null) 208 query= new NullQuery(); 209 try { 210 fOperationHistroy.redoOperation(redo, pm, new QueryAdapter(query)); 211 } catch (ExecutionException e) { 212 handleException(e); 213 } 214 } 215 216 private UndoableOperation2ChangeAdapter getUnwrappedOperation(IUndoableOperation operation) { 217 IUndoableOperation result= operation; 218 if (result instanceof TriggeredOperations) { 219 result= ((TriggeredOperations)result).getTriggeringOperation(); 220 } 221 if (result instanceof UndoableOperation2ChangeAdapter) { 222 return (UndoableOperation2ChangeAdapter)result; 223 } 224 return null; 225 } 226 227 public void flush() { 228 if (fActiveOperation != null) { 229 if (fIsOpen) { 230 fOperationHistroy.closeOperation(false, false, IOperationHistory.EXECUTE); 231 } 232 238 fOperationHistroy.add(fActiveOperation); 239 } 240 fActiveOperation= null; 241 fIsOpen= false; 242 fOperationHistroy.dispose(RefactoringCorePlugin.getUndoContext(), true, true, false); 243 } 244 245 public void shutdown() { 246 } 248 249 private void handleException(ExecutionException e) throws CoreException { 250 Throwable cause= e.getCause(); 251 if (cause instanceof CoreException) { 252 throw (CoreException)cause; 253 } else { 254 throw new CoreException(new Status( 255 IStatus.ERROR, RefactoringCorePlugin.getPluginId(),IStatus.ERROR, 256 RefactoringCoreMessages.RefactoringCorePlugin_internal_error, 257 e)); 258 } 259 } 260 261 263 private void fireAboutToPerformChange(final Change change) { 264 if (fListeners == null) 265 return; 266 Object [] listeners= fListeners.getListeners(); 267 for (int i= 0; i < listeners.length; i++) { 268 final IUndoManagerListener listener= (IUndoManagerListener)listeners[i]; 269 SafeRunner.run(new ISafeRunnable() { 270 public void run() throws Exception { 271 listener.aboutToPerformChange(UndoManager2.this, change); 272 } 273 public void handleException(Throwable exception) { 274 RefactoringCorePlugin.log(exception); 275 } 276 }); 277 } 278 } 279 280 private void fireChangePerformed(final Change change) { 281 if (fListeners == null) 282 return; 283 Object [] listeners= fListeners.getListeners(); 284 for (int i= 0; i < listeners.length; i++) { 285 final IUndoManagerListener listener= (IUndoManagerListener)listeners[i]; 286 SafeRunner.run(new ISafeRunnable() { 287 public void run() throws Exception { 288 listener.changePerformed(UndoManager2.this, change); 289 } 290 public void handleException(Throwable exception) { 291 RefactoringCorePlugin.log(exception); 292 } 293 }); 294 } 295 } 296 297 private void fireUndoStackChanged() { 298 if (fListeners == null) 299 return; 300 Object [] listeners= fListeners.getListeners(); 301 for (int i= 0; i < listeners.length; i++) { 302 final IUndoManagerListener listener= (IUndoManagerListener)listeners[i]; 303 SafeRunner.run(new ISafeRunnable() { 304 public void run() throws Exception { 305 listener.undoStackChanged(UndoManager2.this); 306 } 307 public void handleException(Throwable exception) { 308 RefactoringCorePlugin.log(exception); 309 } 310 }); 311 } 312 } 313 314 private void fireRedoStackChanged() { 315 if (fListeners == null) 316 return; 317 Object [] listeners= fListeners.getListeners(); 318 for (int i= 0; i < listeners.length; i++) { 319 final IUndoManagerListener listener= (IUndoManagerListener)listeners[i]; 320 SafeRunner.run(new ISafeRunnable() { 321 public void run() throws Exception { 322 listener.redoStackChanged(UndoManager2.this); 323 } 324 public void handleException(Throwable exception) { 325 RefactoringCorePlugin.log(exception); 326 } 327 }); 328 } 329 } 330 331 333 public boolean testHasNumberOfUndos(int number) { 334 return fOperationHistroy.getUndoHistory(RefactoringCorePlugin.getUndoContext()).length == number; 335 } 336 337 public boolean testHasNumberOfRedos(int number) { 338 return fOperationHistroy.getRedoHistory(RefactoringCorePlugin.getUndoContext()).length == number; 339 } 340 } 341 | Popular Tags |