KickJava   Java API By Example, From Geeks To Geeks.

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


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 java.util.Collection JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.Stack JavaDoc;
16
17 import org.eclipse.core.runtime.Assert;
18 import org.eclipse.core.runtime.CoreException;
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.core.runtime.ISafeRunnable;
21 import org.eclipse.core.runtime.ListenerList;
22 import org.eclipse.core.runtime.NullProgressMonitor;
23 import org.eclipse.core.runtime.SafeRunner;
24 import org.eclipse.core.runtime.SubProgressMonitor;
25
26 import org.eclipse.core.resources.IWorkspaceRunnable;
27 import org.eclipse.core.resources.ResourcesPlugin;
28
29 import org.eclipse.ltk.core.refactoring.Change;
30 import org.eclipse.ltk.core.refactoring.IUndoManager;
31 import org.eclipse.ltk.core.refactoring.IUndoManagerListener;
32 import org.eclipse.ltk.core.refactoring.IValidationCheckResultQuery;
33 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
34
35 /**
36  * Default implementation of IUndoManager.
37  */

38 public class UndoManager implements IUndoManager {
39
40     private Stack JavaDoc fUndoChanges;
41     private Stack JavaDoc fRedoChanges;
42     private Stack JavaDoc fUndoNames;
43     private Stack JavaDoc fRedoNames;
44
45     private ListenerList fListeners;
46     // Maximum numbers of undos on the refactoring undo stack.
47
private static final int MAX_UNDO_REDOS= 5;
48     
49     private static class NullQuery implements IValidationCheckResultQuery {
50         public boolean proceed(RefactoringStatus status) {
51             return true;
52         }
53         public void stopped(RefactoringStatus status) {
54             // do nothing
55
}
56     }
57
58     /**
59      * Creates a new undo manager with an empty undo and redo stack.
60      */

61     public UndoManager() {
62         flush();
63     }
64
65     /*
66      * (Non-Javadoc) Method declared in IUndoManager.
67      */

68     public void addListener(IUndoManagerListener listener) {
69         if (fListeners == null)
70             fListeners= new ListenerList(ListenerList.IDENTITY);
71         fListeners.add(listener);
72     }
73
74     /*
75      * (Non-Javadoc) Method declared in IUndoManager.
76      */

77     public void removeListener(IUndoManagerListener listener) {
78         if (fListeners == null)
79             return;
80         fListeners.remove(listener);
81         if (fListeners.size() == 0)
82             fListeners= null;
83     }
84     
85     public void aboutToPerformChange(final Change change) {
86         if (fListeners == null)
87             return;
88         Object JavaDoc[] listeners= fListeners.getListeners();
89         for (int i= 0; i < listeners.length; i++) {
90             final IUndoManagerListener listener= (IUndoManagerListener)listeners[i];
91             SafeRunner.run(new ISafeRunnable() {
92                 public void run() throws Exception JavaDoc {
93                     listener.aboutToPerformChange(UndoManager.this, change);
94                 }
95                 public void handleException(Throwable JavaDoc exception) {
96                     RefactoringCorePlugin.log(exception);
97                 }
98             });
99         }
100     }
101     
102     public void changePerformed(final Change change) {
103         if (fListeners == null)
104             return;
105         Object JavaDoc[] listeners= fListeners.getListeners();
106         for (int i= 0; i < listeners.length; i++) {
107             final IUndoManagerListener listener= (IUndoManagerListener)listeners[i];
108             SafeRunner.run(new ISafeRunnable() {
109                 public void run() throws Exception JavaDoc {
110                     listener.changePerformed(UndoManager.this, change);
111                 }
112                 public void handleException(Throwable JavaDoc exception) {
113                     RefactoringCorePlugin.log(exception);
114                 }
115             });
116         }
117     }
118     
119     public void changePerformed(Change change, boolean successful) {
120         // the listeners don't care about success or not.
121
changePerformed(change);
122     }
123
124     /*
125      * (Non-Javadoc) Method declared in IUndoManager.
126      */

127     public void aboutToPerformRefactoring() {
128     }
129
130     /*
131      * (Non-Javadoc) Method declared in IUndoManager.
132      */

133     public void refactoringPerformed(boolean success) {
134     }
135
136     /*
137      * (non-Javadoc)
138      *
139      * @see IUndoManager#shutdown()
140      */

141     public void shutdown() {
142     }
143
144     /*
145      * (Non-Javadoc) Method declared in IUndoManager.
146      */

147     public void flush() {
148         flushUndo();
149         flushRedo();
150     }
151
152     private void flushUndo() {
153         if (fUndoChanges != null) {
154             sendDispose(fUndoChanges);
155         }
156         fUndoChanges= new Stack JavaDoc();
157         fUndoNames= new Stack JavaDoc();
158         fireUndoStackChanged();
159     }
160
161     private void flushRedo() {
162         if (fRedoChanges != null) {
163             sendDispose(fRedoChanges);
164         }
165         fRedoChanges= new Stack JavaDoc();
166         fRedoNames= new Stack JavaDoc();
167         fireRedoStackChanged();
168     }
169
170     /*
171      * (Non-Javadoc) Method declared in IUndoManager.
172      */

173     public void addUndo(String JavaDoc refactoringName, Change change) {
174         Assert.isNotNull(refactoringName, "refactoring"); //$NON-NLS-1$
175
Assert.isNotNull(change, "change"); //$NON-NLS-1$
176
fUndoNames.push(refactoringName);
177         fUndoChanges.push(change);
178         if (fUndoChanges.size() > MAX_UNDO_REDOS) {
179             Change removedChange= (Change)fUndoChanges.remove(0);
180             fUndoNames.remove(0);
181             removedChange.dispose();
182         }
183         flushRedo();
184         fireUndoStackChanged();
185     }
186
187     /*
188      * (Non-Javadoc) Method declared in IUndoManager.
189      */

190     public void performUndo(IValidationCheckResultQuery query, IProgressMonitor pm) throws CoreException {
191         if (pm == null)
192             pm= new NullProgressMonitor();
193         RefactoringStatus result= new RefactoringStatus();
194
195         if (fUndoChanges.empty())
196             return;
197
198         Change change= (Change)fUndoChanges.pop();
199         if (query == null)
200             query= new NullQuery();
201         Change redo;
202         try {
203             redo= executeChange(result, change, query, pm);
204         } catch (InterruptedException JavaDoc e) {
205             fUndoChanges.push(change);
206             return;
207         }
208         if (!result.hasFatalError()) {
209             if (redo != null && !fUndoNames.isEmpty()) {
210                 fRedoNames.push(fUndoNames.pop());
211                 fRedoChanges.push(redo);
212                 fireUndoStackChanged();
213                 fireRedoStackChanged();
214             } else {
215                 flush();
216             }
217         } else {
218             flush();
219         }
220     }
221
222     /*
223      * (Non-Javadoc) Method declared in IUndoManager.
224      */

225     public void performRedo(IValidationCheckResultQuery query, IProgressMonitor pm) throws CoreException {
226         if (pm == null)
227             pm= new NullProgressMonitor();
228         RefactoringStatus result= new RefactoringStatus();
229
230         if (fRedoChanges.empty())
231             return;
232
233         Change change= (Change)fRedoChanges.pop();
234         if (query == null)
235             query= new NullQuery();
236         Change undo;
237         try {
238             undo= executeChange(result, change, query, pm);
239         } catch (InterruptedException JavaDoc e) {
240             fRedoChanges.push(change);
241             return;
242         }
243         if (!result.hasFatalError()) {
244             if (undo != null && !fRedoNames.isEmpty()) {
245                 fUndoNames.push(fRedoNames.pop());
246                 fUndoChanges.push(undo);
247                 fireRedoStackChanged();
248                 fireUndoStackChanged();
249             }
250         } else {
251             flush();
252         }
253     }
254
255     private Change executeChange(final RefactoringStatus status, final Change change, final IValidationCheckResultQuery query, IProgressMonitor pm) throws CoreException, InterruptedException JavaDoc {
256         final Change[] undo= new Change[1];
257         final boolean[] interrupted= new boolean[1];
258         IWorkspaceRunnable runnable= new IWorkspaceRunnable() {
259             public void run(IProgressMonitor monitor) throws CoreException {
260                 boolean undoInitialized= false;
261                 try {
262                     monitor.beginTask("", 11); //$NON-NLS-1$
263
status.merge(change.isValid(new SubProgressMonitor(monitor, 2)));
264                     if (status.hasFatalError()) {
265                         query.stopped(status);
266                         change.dispose();
267                         return;
268                     }
269                     if (!status.isOK() && !query.proceed(status)) {
270                         interrupted[0]= true;
271                         return;
272                     }
273                     ResourcesPlugin.getWorkspace().checkpoint(false);
274                     boolean successful= false;
275                     try {
276                         aboutToPerformChange(change);
277                         undo[0]= change.perform(new SubProgressMonitor(monitor, 8));
278                         successful= true;
279                         ResourcesPlugin.getWorkspace().checkpoint(false);
280                     } finally {
281                         changePerformed(change, successful);
282                     }
283                     change.dispose();
284                     if (undo[0] != null) {
285                         undo[0].initializeValidationData(new SubProgressMonitor(monitor, 1));
286                         undoInitialized= true;
287                     }
288                 } catch (CoreException e) {
289                     flush();
290                     if (undo[0] != null && undoInitialized) {
291                         Change ch= undo[0];
292                         undo[0]= null;
293                         ch.dispose();
294                     } else {
295                         undo[0]= null;
296                     }
297                     throw e;
298                 } catch (RuntimeException JavaDoc e) {
299                     flush();
300                     if (undo[0] != null && undoInitialized) {
301                         Change ch= undo[0];
302                         undo[0]= null;
303                         ch.dispose();
304                     } else {
305                         undo[0]= null;
306                     }
307                     throw e;
308                 } finally {
309                     monitor.done();
310                 }
311             }
312         };
313         ResourcesPlugin.getWorkspace().run(runnable, pm);
314         if (interrupted[0])
315             throw new InterruptedException JavaDoc();
316         return undo[0];
317     }
318
319     /*
320      * (Non-Javadoc) Method declared in IUndoManager.
321      */

322     public boolean anythingToRedo() {
323         return !fRedoChanges.empty();
324     }
325
326     /*
327      * (Non-Javadoc) Method declared in IUndoManager.
328      */

329     public boolean anythingToUndo() {
330         return !fUndoChanges.empty();
331     }
332
333     /*
334      * (Non-Javadoc) Method declared in IUndoManager.
335      */

336     public String JavaDoc peekUndoName() {
337         if (fUndoNames.size() > 0)
338             return (String JavaDoc)fUndoNames.peek();
339         return null;
340     }
341
342     /*
343      * (Non-Javadoc) Method declared in IUndoManager.
344      */

345     public String JavaDoc peekRedoName() {
346         if (fRedoNames.size() > 0)
347             return (String JavaDoc)fRedoNames.peek();
348         return null;
349     }
350
351     private void fireUndoStackChanged() {
352         if (fListeners == null)
353             return;
354         Object JavaDoc[] listeners= fListeners.getListeners();
355         for (int i= 0; i < listeners.length; i++) {
356             ((IUndoManagerListener)listeners[i]).undoStackChanged(this);
357         }
358     }
359
360     private void fireRedoStackChanged() {
361         if (fListeners == null)
362             return;
363         Object JavaDoc[] listeners= fListeners.getListeners();
364         for (int i= 0; i < listeners.length; i++) {
365             ((IUndoManagerListener)listeners[i]).redoStackChanged(this);
366         }
367     }
368     
369     private void sendDispose(Collection JavaDoc collection) {
370         for (Iterator JavaDoc iter= collection.iterator(); iter.hasNext();) {
371             final Change change= (Change)iter.next();
372             ISafeRunnable r= new ISafeRunnable() {
373                 public void run() {
374                     change.dispose();
375                 }
376                 public void handleException(Throwable JavaDoc exception) {
377                     RefactoringCorePlugin.log(exception);
378                 }
379             };
380             SafeRunner.run(r);
381         }
382     }
383     
384     //---- testing methods ---------------------------------------------
385

386     public boolean testHasNumberOfUndos(int number) {
387         return fUndoChanges.size() == number;
388     }
389     
390     public boolean testHasNumberOfRedos(int number) {
391         return fRedoChanges.size() == number;
392     }
393 }
394
Popular Tags