KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ltk > internal > core > refactoring > UndoManager2


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

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                     // would be better to have different events for this
69
fireUndoStackChanged();
70                     fireRedoStackChanged();
71                     break;
72                 case OperationHistoryEvent.OPERATION_REMOVED:
73                     // would be better to have different events for this
74
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             // do nothing
87
}
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 JavaDoc getAdapter(Class JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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             /* the triggering operation is invalid, but we must ensure that any
233              * other operations executed while it was open remain in the undo
234              * history. We accomplish this by adding the invalid operation,
235              * since disposing the context later will cause it to be broken up into
236              * its atomic parts.
237              */

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         // nothing to do since we have a shared undo manager anyways.
247
}
248     
249     private void handleException(ExecutionException e) throws CoreException {
250         Throwable JavaDoc 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     //---- event firing methods -------------------------------------------------
262

263     private void fireAboutToPerformChange(final Change change) {
264         if (fListeners == null)
265             return;
266         Object JavaDoc[] 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 JavaDoc {
271                     listener.aboutToPerformChange(UndoManager2.this, change);
272                 }
273                 public void handleException(Throwable JavaDoc 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 JavaDoc[] 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 JavaDoc {
288                     listener.changePerformed(UndoManager2.this, change);
289                 }
290                 public void handleException(Throwable JavaDoc exception) {
291                     RefactoringCorePlugin.log(exception);
292                 }
293             });
294         }
295     }
296     
297     private void fireUndoStackChanged() {
298         if (fListeners == null)
299             return;
300         Object JavaDoc[] 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 JavaDoc {
305                     listener.undoStackChanged(UndoManager2.this);
306                 }
307                 public void handleException(Throwable JavaDoc exception) {
308                     RefactoringCorePlugin.log(exception);
309                 }
310             });
311         }
312     }
313
314     private void fireRedoStackChanged() {
315         if (fListeners == null)
316             return;
317         Object JavaDoc[] 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 JavaDoc {
322                     listener.redoStackChanged(UndoManager2.this);
323                 }
324                 public void handleException(Throwable JavaDoc exception) {
325                     RefactoringCorePlugin.log(exception);
326                 }
327             });
328         }
329     }
330     
331     //---- testing methods ---------------------------------------------
332

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