KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > ide > undo > AbstractResourcesOperation


1 /*******************************************************************************
2  * Copyright (c) 2006, 2007 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.ide.undo;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.List JavaDoc;
16
17 import org.eclipse.core.resources.IResource;
18 import org.eclipse.core.runtime.CoreException;
19 import org.eclipse.core.runtime.IAdaptable;
20 import org.eclipse.core.runtime.IProgressMonitor;
21 import org.eclipse.core.runtime.IStatus;
22 import org.eclipse.core.runtime.Status;
23 import org.eclipse.core.runtime.jobs.ISchedulingRule;
24 import org.eclipse.core.runtime.jobs.MultiRule;
25 import org.eclipse.ui.actions.ReadOnlyStateChecker;
26 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
27 import org.eclipse.ui.internal.ide.undo.UndoMessages;
28
29 /**
30  * An AbstractResourcesOperation represents an undoable operation that
31  * manipulates resources. It provides implementations for resource rename,
32  * delete, creation, and modification. It also assigns the workspace undo
33  * context as the undo context for operations of this type. Clients may call the
34  * public API from a background thread.
35  *
36  * This class is not intended to be subclassed by clients.
37  *
38  * @since 3.3
39  *
40  */

41 abstract class AbstractResourcesOperation extends AbstractWorkspaceOperation {
42
43     /*
44      * The array of resource descriptions known by this operation to create or
45      * restore overwritten resources.
46      */

47     protected ResourceDescription[] resourceDescriptions;
48     
49     /*
50      * Return true if the specified subResource is a descendant of the specified
51      * super resource. Used to remove descendants from the resource array when
52      * an operation is requested on a parent and its descendant.
53      */

54     private static boolean isDescendantOf(IResource subResource, IResource superResource) {
55         return ! subResource.equals(superResource) && superResource.getFullPath().isPrefixOf(subResource.getFullPath());
56     }
57
58
59     /**
60      * Create an Abstract Resources Operation
61      *
62      * @param resources
63      * the resources to be modified
64      * @param label
65      * the label of the operation
66      */

67     AbstractResourcesOperation(IResource[] resources, String JavaDoc label) {
68         super(label);
69         this.addContext(WorkspaceUndoUtil.getWorkspaceUndoContext());
70
71         setTargetResources(resources);
72     }
73
74     /**
75      * Create an Abstract Resources Operation
76      *
77      * @param resourceDescriptions
78      * the resourceDescriptions describing resources to be created
79      * @param label
80      * the label of the operation
81      */

82     AbstractResourcesOperation(ResourceDescription[] resourceDescriptions,
83             String JavaDoc label) {
84         super(label);
85         addContext(WorkspaceUndoUtil.getWorkspaceUndoContext());
86         setResourceDescriptions(resourceDescriptions);
87     }
88
89     /**
90      * Delete any resources known by this operation. Store enough information to
91      * undo and redo the operation.
92      *
93      * @param monitor
94      * the progress monitor to use for the operation
95      * @param uiInfo
96      * the IAdaptable (or <code>null</code>) provided by the
97      * caller in order to supply UI information for prompting the
98      * user if necessary. When this parameter is not
99      * <code>null</code>, it contains an adapter for the
100      * org.eclipse.swt.widgets.Shell.class
101      * @param deleteContent
102      * <code>true</code> if the content of any known projects
103      * should be deleted along with the project. <code>false</code>
104      * if project content should not be deleted.
105      * @throws CoreException
106      * propagates any CoreExceptions thrown from the resources API
107      */

108     protected void delete(IProgressMonitor monitor, IAdaptable uiInfo,
109             boolean deleteContent) throws CoreException {
110         setResourceDescriptions(WorkspaceUndoUtil.delete(resources, monitor,
111                 uiInfo, deleteContent));
112         setTargetResources(new IResource[0]);
113     }
114
115     /**
116      * Recreate any resources known by this operation. Store enough information
117      * to undo and redo the operation.
118      *
119      * @param monitor
120      * the progress monitor to use for the operation
121      * @param uiInfo
122      * the IAdaptable (or <code>null</code>) provided by the
123      * caller in order to supply UI information for prompting the
124      * user if necessary. When this parameter is not
125      * <code>null</code>, it contains an adapter for the
126      * org.eclipse.swt.widgets.Shell.class
127      * @throws CoreException
128      * propagates any CoreExceptions thrown from the resources API
129      */

130     protected void recreate(IProgressMonitor monitor, IAdaptable uiInfo)
131             throws CoreException {
132         setTargetResources(WorkspaceUndoUtil.recreate(resourceDescriptions,
133                 monitor, uiInfo));
134         setResourceDescriptions(new ResourceDescription[0]);
135     }
136
137     /**
138      * Compute the status for creating resources from the descriptions. A status
139      * severity of <code>OK</code> indicates that the create is likely to be
140      * successful. A status severity of <code>ERROR</code> indicates that the
141      * operation is no longer valid. Other status severities are open to
142      * interpretation by the caller.
143      *
144      * Note this method may be called on initial creation of a resource, or when
145      * a create or delete operation is being undone or redone. Therefore, this
146      * method should check conditions that can change over the life of the
147      * operation, such as the existence of the information needed to carry out
148      * the operation. One-time static checks should typically be done by the
149      * caller (such as the action that creates the operation) so that the user
150      * is not continually prompted or warned about conditions that were
151      * acceptable at the time of original execution.
152      *
153      * @param allowOverwrite
154      * a boolean that specifies whether resource creation should be
155      * allowed to overwrite an existent resource.
156      */

157     protected IStatus computeCreateStatus(boolean allowOverwrite) {
158         if (resourceDescriptions == null || resourceDescriptions.length == 0) {
159             markInvalid();
160             return getErrorStatus(UndoMessages.AbstractResourcesOperation_NotEnoughInfo);
161         }
162         for (int i = 0; i < resourceDescriptions.length; i++) {
163             // Check for enough info to restore the resource
164
if (!resourceDescriptions[i].isValid()) {
165                 markInvalid();
166                 return getErrorStatus(UndoMessages.AbstractResourcesOperation_InvalidRestoreInfo);
167             } else if (!allowOverwrite
168                     && resourceDescriptions[i].verifyExistence(false)) {
169                 // overwrites are not allowed and the resource already exists
170
markInvalid();
171                 return getErrorStatus(UndoMessages.AbstractResourcesOperation_ResourcesAlreadyExist);
172             }
173         }
174         return Status.OK_STATUS;
175     }
176
177     /**
178      * Compute the status for deleting resources. A status severity of
179      * <code>OK</code> indicates that the delete is likely to be successful. A
180      * status severity of <code>ERROR</code> indicates that the operation is
181      * no longer valid. Other status severities are open to interpretation by
182      * the caller.
183      *
184      * Note this method may be called on initial deletion of a resource, or when
185      * a create or delete operation is being undone or redone. Therefore, this
186      * method should check conditions that can change over the life of the
187      * operation, such as the existence of the resources to be deleted. One-time
188      * static checks should typically be done by the caller (such as the action
189      * that creates the operation) so that the user is not continually prompted
190      * or warned about conditions that were acceptable at the time of original
191      * execution.
192      */

193     protected IStatus computeDeleteStatus() {
194         if (resources == null || resources.length == 0) {
195             markInvalid();
196             return getErrorStatus(UndoMessages.AbstractResourcesOperation_NotEnoughInfo);
197         }
198         if (!resourcesExist()) {
199             markInvalid();
200             return getErrorStatus(UndoMessages.AbstractResourcesOperation_ResourcesDoNotExist);
201         }
202         return checkReadOnlyResources(resources);
203     }
204     
205     /**
206      * Check the specified resources for read only state, and return a
207      * status indicating whether the resources can be deleted.
208      */

209     IStatus checkReadOnlyResources(IResource[] resourcesToCheck) {
210         // Check read only status if we are permitted
211
// to consult the user.
212
if (!quietCompute) {
213             ReadOnlyStateChecker checker = new ReadOnlyStateChecker(
214                     getShell(null),
215                     IDEWorkbenchMessages.DeleteResourceAction_title1,
216                     IDEWorkbenchMessages.DeleteResourceAction_readOnlyQuestion);
217             checker.setIgnoreLinkedResources(true);
218             IResource[] approvedResources = checker
219                     .checkReadOnlyResources(resourcesToCheck);
220             if (approvedResources.length == 0) {
221                 // Consider this a cancelled redo.
222
return Status.CANCEL_STATUS;
223             }
224             // Redefine the redo to only include the approved ones.
225
setTargetResources(approvedResources);
226         }
227         return Status.OK_STATUS;
228     }
229
230     /**
231      * Set the array of resource descriptions describing resources to be
232      * restored when undoing or redoing this operation.
233      *
234      * @param descriptions
235      * the array of resource descriptions
236      */

237     protected void setResourceDescriptions(ResourceDescription[] descriptions) {
238         if (descriptions == null) {
239             resourceDescriptions = new ResourceDescription[0];
240         } else {
241             resourceDescriptions = descriptions;
242         }
243     }
244
245     /*
246      * (non-Javadoc)
247      *
248      * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#appendDescriptiveText(java.lang.StringBuffer)
249      */

250     protected void appendDescriptiveText(StringBuffer JavaDoc text) {
251         super.appendDescriptiveText(text);
252         text.append(" resourceDescriptions: "); //$NON-NLS-1$
253
text.append(resourceDescriptions);
254         text.append('\'');
255     }
256
257     /**
258      * Compute a scheduling rule for creating resources.
259      *
260      * @return a scheduling rule appropriate for creating the resources
261      * specified in the resource descriptions
262      */

263     protected ISchedulingRule computeCreateSchedulingRule() {
264         ISchedulingRule[] ruleArray = new ISchedulingRule[resourceDescriptions.length * 3];
265
266         for (int i = 0; i < resourceDescriptions.length; i++) {
267             IResource resource = resourceDescriptions[i].createResourceHandle();
268             // Need a rule for creating...
269
ruleArray[i * 3] = getWorkspaceRuleFactory().createRule(resource);
270             // ...and modifying
271
ruleArray[i * 3 + 1] = getWorkspaceRuleFactory().modifyRule(
272                     resource);
273             // ...and changing the charset
274
ruleArray[i * 3 + 2] = getWorkspaceRuleFactory().charsetRule(
275                     resource);
276
277         }
278         return MultiRule.combine(ruleArray);
279     }
280
281     /**
282      * Compute a scheduling rule for deleting resources.
283      *
284      * @return a scheduling rule appropriate for deleting the resources
285      * specified in the receiver.
286      */

287     protected ISchedulingRule computeDeleteSchedulingRule() {
288         ISchedulingRule[] ruleArray = new ISchedulingRule[resources.length * 2];
289         for (int i = 0; i < resources.length; i++) {
290             ruleArray[i * 2] = getWorkspaceRuleFactory().deleteRule(
291                     resources[i]);
292             // we include a modify rule because we may have to open a project
293
// to record its resources before deleting it.
294
ruleArray[i * 2 + 1] = getWorkspaceRuleFactory().modifyRule(
295                     resources[i]);
296         }
297         return MultiRule.combine(ruleArray);
298
299     }
300
301     /*
302      * (non-Javadoc)
303      *
304      * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#setTargetResources(org.eclipse.core.resources.IResource[])
305      */

306     protected void setTargetResources(IResource[] targetResources) {
307         // Remove any descendants if the parent has also
308
// been specified.
309
List JavaDoc subResources = new ArrayList JavaDoc();
310         for (int i = 0; i < targetResources.length; i++) {
311             IResource subResource = targetResources[i];
312             for (int j = 0; j < targetResources.length; j++) {
313                 IResource superResource = targetResources[j];
314                 if (isDescendantOf(subResource, superResource))
315                     subResources.add(subResource);
316             }
317         }
318         IResource[] nestedResourcesRemoved = new IResource[targetResources.length
319                 - subResources.size()];
320         int j = 0;
321         for (int i = 0; i < targetResources.length; i++) {
322             if (!subResources.contains(targetResources[i])) {
323                 nestedResourcesRemoved[j] = targetResources[i];
324                 j++;
325             }
326         }
327         super.setTargetResources(nestedResourcesRemoved);
328     }
329 }
330
Popular Tags