KickJava   Java API By Example, From Geeks To Geeks.

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


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.ArrayList JavaDoc;
14 import java.util.List JavaDoc;
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 JavaDoc fLabel;
41     private String JavaDoc fDescription;
42     private Change fExecuteChange;
43     private Change fUndoChange;
44     private Change fRedoChange;
45     private Change fActiveChange;
46     
47     private List JavaDoc fContexts= new ArrayList JavaDoc();
48     
49     private static class ContextAdapter implements IAdaptable {
50         private IAdaptable fInfoAdapter;
51         private String JavaDoc fTitle;
52         public ContextAdapter(IAdaptable infoAdapter, String JavaDoc title) {
53             fInfoAdapter= infoAdapter;
54             fTitle= title;
55         }
56         public Object JavaDoc getAdapter(Class JavaDoc adapter) {
57             if (String JavaDoc.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 JavaDoc label) {
90         fLabel= label;
91     }
92     
93     public String JavaDoc getLabel() {
94         if (fLabel != null)
95             return fLabel;
96         return fActiveChange.getName();
97     }
98
99     public String JavaDoc getDescription() {
100         if (fDescription != null)
101             return fDescription;
102         return fActiveChange.getName();
103     }
104
105     public Object JavaDoc[] 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             // have to check both ways because one context may be more general in
122
// its matching rules than another.
123
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); //$NON-NLS-1$
157
} 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); //$NON-NLS-1$
185
} 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                 // The operation can no longer be undo.
201
fUndoChange= null;
202                 clearActiveChange();
203                 return asStatus(status);
204             } else {
205                 // return OK in all other cases. This by passes the dialog shown
206
// in the operation approver and allows refactoring to show its
207
// own dialog again inside the runnable.
208
return new Status(IStatus.OK, RefactoringCorePlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$
209
}
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); //$NON-NLS-1$
238
} 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                 // The operation can no longer be redone.
254
fRedoChange= null;
255                 clearActiveChange();
256                 return asStatus(status);
257             } else {
258                 // return OK in all other cases. This by passes the dialog shown
259
// in the operation approver and allows refactoring to show its
260
// own dialog again inside the runnable.
261
return new Status(IStatus.OK, RefactoringCorePlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$
262
}
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         // the active change could be cleared.
284
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); //$NON-NLS-1$
297
result.validationStatus= fActiveChange.isValid(new SubProgressMonitor(monitor, 2));
298                     if (result.validationStatus.hasFatalError()) {
299                         query.stopped(result.validationStatus);
300                         // no need to dispose here. The framework disposes
301
// the undo since it couldn't be executed.
302
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 JavaDoc 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); //$NON-NLS-1$
357
} else {
358             return status.getEntryWithHighestSeverity().toStatus();
359         }
360     }
361
362     private IValidationCheckResultQuery getQuery(IAdaptable info, String JavaDoc 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