KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > ide > undo > WorkspaceUndoMonitor


1 /*******************************************************************************
2  * Copyright (c) 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
12 package org.eclipse.ui.internal.ide.undo;
13
14 import org.eclipse.core.commands.ExecutionException;
15 import org.eclipse.core.commands.operations.IAdvancedUndoableOperation;
16 import org.eclipse.core.commands.operations.IAdvancedUndoableOperation2;
17 import org.eclipse.core.commands.operations.IOperationHistory;
18 import org.eclipse.core.commands.operations.IOperationHistoryListener;
19 import org.eclipse.core.commands.operations.IUndoableOperation;
20 import org.eclipse.core.commands.operations.OperationHistoryEvent;
21 import org.eclipse.core.resources.IResourceChangeEvent;
22 import org.eclipse.core.resources.IResourceChangeListener;
23 import org.eclipse.core.resources.ResourcesPlugin;
24 import org.eclipse.core.runtime.IStatus;
25 import org.eclipse.core.runtime.Status;
26 import org.eclipse.ui.PlatformUI;
27 import org.eclipse.ui.ide.undo.WorkspaceUndoUtil;
28 import org.eclipse.ui.internal.ide.Policy;
29
30 /**
31  * WorkspaceUndoMonitor monitors the workspace for resource changes and
32  * periodically checks the undo history to make sure it is valid.
33  *
34  * This class is not intended to be instantiated or used by clients.
35  *
36  * @since 3.3
37  *
38  */

39 public class WorkspaceUndoMonitor {
40
41     /**
42      * Singleton instance.
43      */

44     private static WorkspaceUndoMonitor instance;
45
46     /**
47      * Number of workspace changes that will cause validation of undo history
48      */

49     private static int CHANGE_THRESHHOLD = 10;
50
51     /**
52      * Prefix to use on debug info
53      */

54     private static String JavaDoc DEBUG_PREFIX = "Workspace Undo Monitor: "; //$NON-NLS-1$
55

56     /**
57      * Get the singleton instance of this class.
58      *
59      * @return the singleton instance of this class.
60      */

61     public static WorkspaceUndoMonitor getInstance() {
62         if (instance == null) {
63             instance = new WorkspaceUndoMonitor();
64         }
65         return instance;
66     }
67
68     /**
69      * Number of workspace changes that have occurred since the last undoable
70      * operation was executed, undone, or redone.
71      */

72     private int numChanges = 0;
73
74     /**
75      * The IUndoableOperation in progress, or <code>null</code> if there is
76      * none in progress.
77      */

78     private IUndoableOperation operationInProgress = null;
79
80     /**
81      * Resource listener used to determine how often to validate the workspace
82      * undo history.
83      */

84     private IResourceChangeListener resourceListener;
85
86     /**
87      * Operation history listener used to determine whether there is an undoable
88      * operation in progress.
89      */

90     private IOperationHistoryListener historyListener;
91
92     /**
93      * Construct an instance. Should only be called by {@link #getInstance()}
94      */

95     private WorkspaceUndoMonitor() {
96         if (Policy.DEBUG_UNDOMONITOR) {
97             System.out.println(DEBUG_PREFIX + "Installing listeners"); //$NON-NLS-1$
98
}
99         resourceListener = getResourceChangeListener();
100         ResourcesPlugin.getWorkspace().addResourceChangeListener(
101                 resourceListener);
102
103         historyListener = getOperationHistoryListener();
104         getOperationHistory().addOperationHistoryListener(historyListener);
105
106     }
107
108     /**
109      * Get a change listener for listening to resource changes.
110      *
111      * @return the resource change listeners
112      */

113     private IResourceChangeListener getResourceChangeListener() {
114         return new IResourceChangeListener() {
115             /*
116              * (non-Javadoc)
117              *
118              * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent)
119              */

120             public void resourceChanged(IResourceChangeEvent event) {
121                 // If there is an operation in progress, this event is to be
122
// ignored.
123
if (operationInProgress != null) {
124                     return;
125                 }
126                 if (event.getType() == IResourceChangeEvent.POST_CHANGE
127                         || event.getType() == IResourceChangeEvent.POST_BUILD) {
128                     // For now, we consider any change a change worth tracking.
129
// We can be more specific later if warranted.
130
incrementChangeCount();
131                     if (numChanges >= CHANGE_THRESHHOLD) {
132                         checkOperationHistory();
133                     }
134                 }
135             }
136         };
137     }
138
139     /**
140      * Get a change listener for listening to operation history changes.
141      *
142      * @return the resource change listeners
143      */

144     private IOperationHistoryListener getOperationHistoryListener() {
145         return new IOperationHistoryListener() {
146
147             /*
148              * (non-Javadoc)
149              *
150              * @see org.eclipse.core.commands.operations.IOperationHistoryListener#historyNotification(org.eclipse.core.commands.operations.OperationHistoryEvent)
151              */

152             public void historyNotification(OperationHistoryEvent event) {
153                 // We only care about events that have the workspace undo
154
// context.
155
if (!event.getOperation().hasContext(
156                         WorkspaceUndoUtil.getWorkspaceUndoContext())) {
157                     return;
158                 }
159                 switch (event.getEventType()) {
160                 case OperationHistoryEvent.ABOUT_TO_EXECUTE:
161                 case OperationHistoryEvent.ABOUT_TO_UNDO:
162                 case OperationHistoryEvent.ABOUT_TO_REDO:
163                     operationInProgress = event.getOperation();
164                     break;
165                 case OperationHistoryEvent.DONE:
166                 case OperationHistoryEvent.UNDONE:
167                 case OperationHistoryEvent.REDONE:
168                     resetChangeCount();
169                     operationInProgress = null;
170                     break;
171                 case OperationHistoryEvent.OPERATION_NOT_OK:
172                     operationInProgress = null;
173                     break;
174                 }
175             }
176
177         };
178     }
179
180     /**
181      * Shutdown the workspace undo monitor. Unhooks the listeners.
182      */

183     public void shutdown() {
184         if (Policy.DEBUG_UNDOMONITOR) {
185             System.out.println(DEBUG_PREFIX + "Shutting Down"); //$NON-NLS-1$
186
}
187
188         if (resourceListener != null) {
189             ResourcesPlugin.getWorkspace().removeResourceChangeListener(
190                     resourceListener);
191         }
192         if (historyListener != null) {
193             getOperationHistory().removeOperationHistoryListener(
194                     historyListener);
195         }
196     }
197
198     /**
199      * Get the operation history.
200      */

201     private IOperationHistory getOperationHistory() {
202         return PlatformUI.getWorkbench().getOperationSupport()
203                 .getOperationHistory();
204     }
205
206     /**
207      * Check the pending undoable operation to see if it is still valid.
208      */

209     private void checkOperationHistory() {
210         if (Policy.DEBUG_UNDOMONITOR) {
211             System.out.println(DEBUG_PREFIX + "Checking Operation History..."); //$NON-NLS-1$
212
}
213         IUndoableOperation currentOp = getOperationHistory().getUndoOperation(
214                 WorkspaceUndoUtil.getWorkspaceUndoContext());
215         // If there is no pending op, nothing to do.
216
if (currentOp == null) {
217             resetChangeCount();
218             return;
219         }
220         // First try the simple check
221
if (!currentOp.canUndo()) {
222             flushWorkspaceHistory(currentOp);
223             return;
224         }
225         // Now try a more advanced check. If the undoable status is definitely
226
// an error, flush the history. Anything less than an error status
227
// should be left alone so that the user can be prompted as to what
228
// should be done when an undo is actually attempted.
229
if (currentOp instanceof IAdvancedUndoableOperation
230                 && currentOp instanceof IAdvancedUndoableOperation2) {
231             ((IAdvancedUndoableOperation2) currentOp).setQuietCompute(true);
232             IStatus status;
233             try {
234                 status = ((IAdvancedUndoableOperation) currentOp)
235                         .computeUndoableStatus(null);
236             } catch (ExecutionException e) {
237                 // Things are not really OK, but we do not want to
238
// interrupt the user with notification of this problem.
239
// For now, we pretend that everything is OK, knowing that
240
// computation will occur again just before the user attempts to
241
// undo this operation.
242
status = Status.OK_STATUS;
243             }
244             ((IAdvancedUndoableOperation2) currentOp).setQuietCompute(false);
245             if (status.getSeverity() == IStatus.ERROR) {
246                 flushWorkspaceHistory(currentOp);
247             }
248         }
249         resetChangeCount();
250     }
251
252     /**
253      * Flush the undo and redo history for the workspace undo context.
254      */

255     private void flushWorkspaceHistory(IUndoableOperation op) {
256         if (Policy.DEBUG_UNDOMONITOR) {
257             System.out.println(DEBUG_PREFIX
258                     + "Flushing undo history due to " + op); //$NON-NLS-1$
259
}
260         getOperationHistory().dispose(
261                 WorkspaceUndoUtil.getWorkspaceUndoContext(), true, true, false);
262     }
263
264     /**
265      * Reset the workspace change count
266      */

267     private void resetChangeCount() {
268         numChanges = 0;
269         if (Policy.DEBUG_UNDOMONITOR) {
270             System.out.println(DEBUG_PREFIX + "Resetting change count to 0"); //$NON-NLS-1$
271
}
272     }
273
274     /**
275      * Increment the workspace change count
276      */

277     private void incrementChangeCount() {
278         numChanges++;
279         if (Policy.DEBUG_UNDOMONITOR) {
280             System.out
281                     .println(DEBUG_PREFIX
282                             + "Incrementing workspace change count. Count = " + numChanges); //$NON-NLS-1$
283
}
284     }
285 }
286
Popular Tags