Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 123674 | Differences between
and this patch

Collapse All | Expand All

(-)extensions/org/eclipse/ui/dialogs/WizardNewFileCreationPage.java (-36 / +37 lines)
Lines 15-20 Link Here
15
import java.lang.reflect.InvocationTargetException;
15
import java.lang.reflect.InvocationTargetException;
16
import java.util.Iterator;
16
import java.util.Iterator;
17
17
18
import org.eclipse.core.commands.ExecutionException;
18
import org.eclipse.core.resources.IFile;
19
import org.eclipse.core.resources.IFile;
19
import org.eclipse.core.resources.IFolder;
20
import org.eclipse.core.resources.IFolder;
20
import org.eclipse.core.resources.IResource;
21
import org.eclipse.core.resources.IResource;
Lines 30-39 Link Here
30
import org.eclipse.core.runtime.OperationCanceledException;
31
import org.eclipse.core.runtime.OperationCanceledException;
31
import org.eclipse.core.runtime.Path;
32
import org.eclipse.core.runtime.Path;
32
import org.eclipse.core.runtime.Preferences;
33
import org.eclipse.core.runtime.Preferences;
33
import org.eclipse.core.runtime.SubProgressMonitor;
34
import org.eclipse.core.runtime.jobs.ISchedulingRule;
34
import org.eclipse.core.runtime.jobs.ISchedulingRule;
35
import org.eclipse.jface.dialogs.ErrorDialog;
36
import org.eclipse.jface.dialogs.MessageDialog;
35
import org.eclipse.jface.dialogs.MessageDialog;
36
import org.eclipse.jface.operation.IRunnableWithProgress;
37
import org.eclipse.jface.viewers.IStructuredSelection;
37
import org.eclipse.jface.viewers.IStructuredSelection;
38
import org.eclipse.jface.wizard.WizardPage;
38
import org.eclipse.jface.wizard.WizardPage;
39
import org.eclipse.osgi.util.NLS;
39
import org.eclipse.osgi.util.NLS;
Lines 49-55 Link Here
49
import org.eclipse.swt.widgets.Listener;
49
import org.eclipse.swt.widgets.Listener;
50
import org.eclipse.swt.widgets.Shell;
50
import org.eclipse.swt.widgets.Shell;
51
import org.eclipse.ui.PlatformUI;
51
import org.eclipse.ui.PlatformUI;
52
import org.eclipse.ui.actions.WorkspaceModifyOperation;
52
import org.eclipse.ui.ide.undo.CreateFileOperation;
53
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
53
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
54
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
54
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
55
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
55
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
Lines 218-223 Link Here
218
     * @param monitor the progress monitor to show visual progress with
218
     * @param monitor the progress monitor to show visual progress with
219
     * @exception CoreException if the operation fails
219
     * @exception CoreException if the operation fails
220
     * @exception OperationCanceledException if the operation is canceled
220
     * @exception OperationCanceledException if the operation is canceled
221
     * 
222
     * @deprecated As of 3.3, use or override {@link #createNewFile()} which uses the
223
     *   undoable operation support.  To supply customized file content for
224
     *   a subclass, use {@link #getInitialContents()}.  
221
     */
225
     */
222
    protected void createFile(IFile fileHandle, InputStream contents,
226
    protected void createFile(IFile fileHandle, InputStream contents,
223
            IProgressMonitor monitor) throws CoreException {
227
            IProgressMonitor monitor) throws CoreException {
Lines 321-365 Link Here
321
        final InputStream initialContents = getInitialContents();
325
        final InputStream initialContents = getInitialContents();
322
326
323
        createLinkTarget();
327
        createLinkTarget();
324
        WorkspaceModifyOperation op = new WorkspaceModifyOperation(createRule(newFileHandle)) {
328
		IRunnableWithProgress op = new IRunnableWithProgress() {
325
            protected void execute(IProgressMonitor monitor)
329
			public void run(IProgressMonitor monitor) {
326
                    throws CoreException {
330
				CreateFileOperation op = new CreateFileOperation(
327
                try {
331
						newFileHandle, linkTargetPath, initialContents,
328
                    monitor.beginTask(IDEWorkbenchMessages.WizardNewFileCreationPage_progress, 2000);
332
						IDEWorkbenchMessages.WizardNewFileCreationPage_title);
329
                    ContainerGenerator generator = new ContainerGenerator(
333
				try {
330
                            containerPath);
334
					PlatformUI.getWorkbench().getOperationSupport()
331
                    generator.generateContainer(new SubProgressMonitor(monitor,
335
							.getOperationHistory().execute(op, monitor,
332
                            1000));
336
									new IAdaptable() {
333
                    createFile(newFileHandle, initialContents,
337
										public Object getAdapter(Class clazz) {
334
                            new SubProgressMonitor(monitor, 1000));
338
											if (clazz == Shell.class) {
335
                } finally {
339
												return getContainer()
336
                    monitor.done();
340
														.getShell();
337
                }
341
											}
338
            }
342
											return null;
339
        };
343
										}
344
									});
345
				} catch (ExecutionException e) {
346
					IDEWorkbenchPlugin.log(e.getMessage(), e);
347
				}
348
			}
349
		};
340
350
341
        try {
351
        try {
342
            getContainer().run(true, true, op);
352
            getContainer().run(true, true, op);
343
        } catch (InterruptedException e) {
353
        } catch (InterruptedException e) {
344
            return null;
354
            return null;
345
        } catch (InvocationTargetException e) {
355
        } catch (InvocationTargetException e) {
346
            if (e.getTargetException() instanceof CoreException) {
356
        	// Execution Exceptions are handled above but we may still get unexpected runtime errors.
347
                ErrorDialog
357
            IDEWorkbenchPlugin.log(getClass(),
348
                        .openError(
358
                    "createNewFile()", e.getTargetException()); //$NON-NLS-1$
349
                                getContainer().getShell(), // Was Utilities.getFocusShell()
359
            MessageDialog
350
                                IDEWorkbenchMessages.WizardNewFileCreationPage_errorTitle,
360
                    .openError(
351
                                null, // no special message
361
                            getContainer().getShell(),
352
                                ((CoreException) e.getTargetException())
362
                            IDEWorkbenchMessages.WizardNewFileCreationPage_internalErrorTitle, NLS.bind(IDEWorkbenchMessages.WizardNewFileCreationPage_internalErrorMessage, e.getTargetException().getMessage()));
353
                                        .getStatus());
363
            
354
            } else {
355
                // CoreExceptions are handled above, but unexpected runtime exceptions and errors may still occur.
356
                IDEWorkbenchPlugin.log(getClass(),
357
                        "createNewFile()", e.getTargetException()); //$NON-NLS-1$
358
                MessageDialog
359
                        .openError(
360
                                getContainer().getShell(),
361
                                IDEWorkbenchMessages.WizardNewFileCreationPage_internalErrorTitle, NLS.bind(IDEWorkbenchMessages.WizardNewFileCreationPage_internalErrorMessage, e.getTargetException().getMessage()));
362
            }
363
            return null;
364
            return null;
364
        }
365
        }
365
366
(-)extensions/org/eclipse/ui/dialogs/WizardNewFolderMainPage.java (-408 / +401 lines)
Lines 15-20 Link Here
15
import java.lang.reflect.InvocationTargetException;
15
import java.lang.reflect.InvocationTargetException;
16
import java.util.Iterator;
16
import java.util.Iterator;
17
17
18
import org.eclipse.core.commands.ExecutionException;
18
import org.eclipse.core.resources.IFolder;
19
import org.eclipse.core.resources.IFolder;
19
import org.eclipse.core.resources.IResource;
20
import org.eclipse.core.resources.IResource;
20
import org.eclipse.core.resources.IResourceStatus;
21
import org.eclipse.core.resources.IResourceStatus;
Lines 29-37 Link Here
29
import org.eclipse.core.runtime.Path;
30
import org.eclipse.core.runtime.Path;
30
import org.eclipse.core.runtime.Preferences;
31
import org.eclipse.core.runtime.Preferences;
31
import org.eclipse.core.runtime.SubProgressMonitor;
32
import org.eclipse.core.runtime.SubProgressMonitor;
32
import org.eclipse.core.runtime.jobs.ISchedulingRule;
33
import org.eclipse.jface.dialogs.ErrorDialog;
34
import org.eclipse.jface.dialogs.MessageDialog;
33
import org.eclipse.jface.dialogs.MessageDialog;
34
import org.eclipse.jface.operation.IRunnableWithProgress;
35
import org.eclipse.jface.viewers.IStructuredSelection;
35
import org.eclipse.jface.viewers.IStructuredSelection;
36
import org.eclipse.jface.wizard.WizardPage;
36
import org.eclipse.jface.wizard.WizardPage;
37
import org.eclipse.osgi.util.NLS;
37
import org.eclipse.osgi.util.NLS;
Lines 47-53 Link Here
47
import org.eclipse.swt.widgets.Listener;
47
import org.eclipse.swt.widgets.Listener;
48
import org.eclipse.swt.widgets.Shell;
48
import org.eclipse.swt.widgets.Shell;
49
import org.eclipse.ui.PlatformUI;
49
import org.eclipse.ui.PlatformUI;
50
import org.eclipse.ui.actions.WorkspaceModifyOperation;
50
import org.eclipse.ui.ide.undo.CreateFolderOperation;
51
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
51
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
52
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
52
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
53
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
53
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
Lines 62-509 Link Here
62
 * <p>
62
 * <p>
63
 * Subclasses may extend
63
 * Subclasses may extend
64
 * <ul>
64
 * <ul>
65
 *   <li><code>handleEvent</code></li>
65
 * <li><code>handleEvent</code></li>
66
 * </ul>
66
 * </ul>
67
 * </p>
67
 * </p>
68
 */
68
 */
69
public class WizardNewFolderMainPage extends WizardPage implements Listener {
69
public class WizardNewFolderMainPage extends WizardPage implements Listener {
70
    private static final int SIZING_CONTAINER_GROUP_HEIGHT = 250;
70
	private static final int SIZING_CONTAINER_GROUP_HEIGHT = 250;
71
71
72
    private IStructuredSelection currentSelection;
72
	private IStructuredSelection currentSelection;
73
73
74
    private IFolder newFolder;
74
	private IFolder newFolder;
75
75
76
    // link target location
76
	// link target location
77
    private IPath linkTargetPath;
77
	private IPath linkTargetPath;
78
78
79
    // widgets
79
	// widgets
80
    private ResourceAndContainerGroup resourceGroup;
80
	private ResourceAndContainerGroup resourceGroup;
81
81
82
    private Button advancedButton;
82
	private Button advancedButton;
83
83
84
    private CreateLinkedResourceGroup linkedResourceGroup;
84
	private CreateLinkedResourceGroup linkedResourceGroup;
85
85
86
    private Composite linkedResourceParent;
86
	private Composite linkedResourceParent;
87
87
88
    private Composite linkedResourceComposite;
88
	private Composite linkedResourceComposite;
89
89
90
    /**
90
	/**
91
     * Height of the "advanced" linked resource group. Set when the
91
	 * Height of the "advanced" linked resource group. Set when the advanced
92
     * advanced group is first made visible. 
92
	 * group is first made visible.
93
     */
93
	 */
94
    private int linkedResourceGroupHeight = -1;
94
	private int linkedResourceGroupHeight = -1;
95
95
96
    /**
96
	/**
97
     * First time the advanced group is validated.
97
	 * First time the advanced group is validated.
98
     */
98
	 */
99
    private boolean firstLinkCheck = true;
99
	private boolean firstLinkCheck = true;
100
100
101
    /**
101
	/**
102
     * Creates a new folder creation wizard page. If the initial resource selection 
102
	 * Creates a new folder creation wizard page. If the initial resource
103
     * contains exactly one container resource then it will be used as the default
103
	 * selection contains exactly one container resource then it will be used as
104
     * container resource.
104
	 * the default container resource.
105
     *
105
	 * 
106
     * @param pageName the name of the page
106
	 * @param pageName
107
     * @param selection the current resource selection
107
	 *            the name of the page
108
     */
108
	 * @param selection
109
    public WizardNewFolderMainPage(String pageName,
109
	 *            the current resource selection
110
            IStructuredSelection selection) {
110
	 */
111
        super("newFolderPage1");//$NON-NLS-1$
111
	public WizardNewFolderMainPage(String pageName,
112
        setTitle(pageName);
112
			IStructuredSelection selection) {
113
        setDescription(IDEWorkbenchMessages.WizardNewFolderMainPage_description);
113
		super("newFolderPage1");//$NON-NLS-1$
114
        this.currentSelection = selection;
114
		setTitle(pageName);
115
    }
115
		setDescription(IDEWorkbenchMessages.WizardNewFolderMainPage_description);
116
116
		this.currentSelection = selection;
117
    /**
117
	}
118
     * Creates the widget for advanced options.
118
119
     *  
119
	/**
120
     * @param parent the parent composite
120
	 * Creates the widget for advanced options.
121
     */
121
	 * 
122
    protected void createAdvancedControls(Composite parent) {
122
	 * @param parent
123
        Preferences preferences = ResourcesPlugin.getPlugin()
123
	 *            the parent composite
124
                .getPluginPreferences();
124
	 */
125
125
	protected void createAdvancedControls(Composite parent) {
126
        if (preferences.getBoolean(ResourcesPlugin.PREF_DISABLE_LINKING) == false) {
126
		Preferences preferences = ResourcesPlugin.getPlugin()
127
            linkedResourceParent = new Composite(parent, SWT.NONE);
127
				.getPluginPreferences();
128
            linkedResourceParent.setFont(parent.getFont());
128
129
            linkedResourceParent.setLayoutData(new GridData(
129
		if (preferences.getBoolean(ResourcesPlugin.PREF_DISABLE_LINKING) == false) {
130
                    GridData.FILL_HORIZONTAL));
130
			linkedResourceParent = new Composite(parent, SWT.NONE);
131
            GridLayout layout = new GridLayout();
131
			linkedResourceParent.setFont(parent.getFont());
132
            layout.marginHeight = 0;
132
			linkedResourceParent.setLayoutData(new GridData(
133
            layout.marginWidth = 0;
133
					GridData.FILL_HORIZONTAL));
134
            linkedResourceParent.setLayout(layout);
134
			GridLayout layout = new GridLayout();
135
135
			layout.marginHeight = 0;
136
            advancedButton = new Button(linkedResourceParent, SWT.PUSH);
136
			layout.marginWidth = 0;
137
            advancedButton.setFont(linkedResourceParent.getFont());
137
			linkedResourceParent.setLayout(layout);
138
            advancedButton.setText(IDEWorkbenchMessages.showAdvanced);
138
139
            GridData data = setButtonLayoutData(advancedButton);
139
			advancedButton = new Button(linkedResourceParent, SWT.PUSH);
140
            data.horizontalAlignment = GridData.BEGINNING;
140
			advancedButton.setFont(linkedResourceParent.getFont());
141
            advancedButton.setLayoutData(data);
141
			advancedButton.setText(IDEWorkbenchMessages.showAdvanced);
142
            advancedButton.addSelectionListener(new SelectionAdapter() {
142
			GridData data = setButtonLayoutData(advancedButton);
143
                public void widgetSelected(SelectionEvent e) {
143
			data.horizontalAlignment = GridData.BEGINNING;
144
                    handleAdvancedButtonSelect();
144
			advancedButton.setLayoutData(data);
145
                }
145
			advancedButton.addSelectionListener(new SelectionAdapter() {
146
            });
146
				public void widgetSelected(SelectionEvent e) {
147
        }
147
					handleAdvancedButtonSelect();
148
        linkedResourceGroup = new CreateLinkedResourceGroup(IResource.FOLDER,
148
				}
149
                new Listener() {
149
			});
150
		            public void handleEvent(Event e) {
150
		}
151
		                setPageComplete(validatePage());
151
		linkedResourceGroup = new CreateLinkedResourceGroup(IResource.FOLDER,
152
		                firstLinkCheck = false;
152
				new Listener() {
153
		            }
153
					public void handleEvent(Event e) {
154
                },
154
						setPageComplete(validatePage());
155
                new CreateLinkedResourceGroup.IStringValue() {
155
						firstLinkCheck = false;
156
                	public String getValue() {
156
					}
157
                		return resourceGroup.getResource();
157
				}, new CreateLinkedResourceGroup.IStringValue() {
158
                	}
158
					public String getValue() {
159
                	public void setValue(String string) {
159
						return resourceGroup.getResource();
160
                		resourceGroup.setResource(string);
160
					}
161
                	}
161
162
                });
162
					public void setValue(String string) {
163
    }
163
						resourceGroup.setResource(string);
164
164
					}
165
    /** (non-Javadoc)
165
				});
166
     * Method declared on IDialogPage.
166
	}
167
     */
167
168
    public void createControl(Composite parent) {
168
	/**
169
        initializeDialogUnits(parent);
169
	 * (non-Javadoc) Method declared on IDialogPage.
170
        // top level group
170
	 */
171
        Composite composite = new Composite(parent, SWT.NONE);
171
	public void createControl(Composite parent) {
172
        composite.setFont(parent.getFont());
172
		initializeDialogUnits(parent);
173
        composite.setLayout(new GridLayout());
173
		// top level group
174
        composite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL
174
		Composite composite = new Composite(parent, SWT.NONE);
175
                | GridData.HORIZONTAL_ALIGN_FILL));
175
		composite.setFont(parent.getFont());
176
176
		composite.setLayout(new GridLayout());
177
        PlatformUI.getWorkbench().getHelpSystem()
177
		composite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL
178
                .setHelp(composite, IIDEHelpContextIds.NEW_FOLDER_WIZARD_PAGE);
178
				| GridData.HORIZONTAL_ALIGN_FILL));
179
179
180
        resourceGroup = new ResourceAndContainerGroup(
180
		PlatformUI.getWorkbench().getHelpSystem().setHelp(composite,
181
                composite,
181
				IIDEHelpContextIds.NEW_FOLDER_WIZARD_PAGE);
182
                this,
182
183
                IDEWorkbenchMessages.WizardNewFolderMainPage_folderName, IDEWorkbenchMessages.WizardNewFolderMainPage_folderLabel, false, SIZING_CONTAINER_GROUP_HEIGHT);
183
		resourceGroup = new ResourceAndContainerGroup(composite, this,
184
        resourceGroup.setAllowExistingResources(false);
184
				IDEWorkbenchMessages.WizardNewFolderMainPage_folderName,
185
        createAdvancedControls(composite);
185
				IDEWorkbenchMessages.WizardNewFolderMainPage_folderLabel,
186
        initializePage();
186
				false, SIZING_CONTAINER_GROUP_HEIGHT);
187
        validatePage();
187
		resourceGroup.setAllowExistingResources(false);
188
        // Show description on opening
188
		createAdvancedControls(composite);
189
        setErrorMessage(null);
189
		initializePage();
190
        setMessage(null);
190
		validatePage();
191
        setControl(composite);
191
		// Show description on opening
192
    }
192
		setErrorMessage(null);
193
193
		setMessage(null);
194
    /**
194
		setControl(composite);
195
     * Creates a folder resource given the folder handle.
195
	}
196
     *
196
197
     * @param folderHandle the folder handle to create a folder resource for
197
	/**
198
     * @param monitor the progress monitor to show visual progress with
198
	 * Creates a folder resource given the folder handle.
199
     * @exception CoreException if the operation fails
199
	 * 
200
     * @exception OperationCanceledException if the operation is canceled
200
	 * @param folderHandle
201
     */
201
	 *            the folder handle to create a folder resource for
202
    protected void createFolder(IFolder folderHandle, IProgressMonitor monitor)
202
	 * @param monitor
203
            throws CoreException {
203
	 *            the progress monitor to show visual progress with
204
        try {
204
	 * @exception CoreException
205
            // Create the folder resource in the workspace
205
	 *                if the operation fails
206
            // Update: Recursive to create any folders which do not exist already
206
	 * @exception OperationCanceledException
207
            if (!folderHandle.exists()) {
207
	 *                if the operation is canceled
208
                if (linkTargetPath != null) {
208
	 *                
209
	 * @deprecated As of 3.3, use {@link #createNewFolder()} which uses the 
210
	 *   undoable operation support.
211
	 */
212
	protected void createFolder(IFolder folderHandle, IProgressMonitor monitor)
213
			throws CoreException {
214
		try {
215
			// Create the folder resource in the workspace
216
			// Update: Recursive to create any folders which do not exist
217
			// already
218
			if (!folderHandle.exists()) {
219
				if (linkTargetPath != null) {
209
					folderHandle.createLink(linkTargetPath,
220
					folderHandle.createLink(linkTargetPath,
210
                            IResource.ALLOW_MISSING_LOCAL, monitor);
221
							IResource.ALLOW_MISSING_LOCAL, monitor);
211
				} else {
222
				} else {
212
	                IPath path = folderHandle.getFullPath();
223
					IPath path = folderHandle.getFullPath();
213
	                IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
224
					IWorkspaceRoot root = ResourcesPlugin.getWorkspace()
214
	                int numSegments= path.segmentCount();
225
							.getRoot();
215
	                if (numSegments > 2 && !root.getFolder(path.removeLastSegments(1)).exists()) {
226
					int numSegments = path.segmentCount();
216
	                    // If the direct parent of the path doesn't exist, try to create the
227
					if (numSegments > 2
217
	                    // necessary directories.
228
							&& !root.getFolder(path.removeLastSegments(1))
218
	                    for (int i= numSegments - 2; i > 0; i--) {
229
									.exists()) {
219
	                        IFolder folder = root.getFolder(path.removeLastSegments(i));
230
						// If the direct parent of the path doesn't exist, try
220
	                        if (!folder.exists()) {
231
						// to create the
221
	                            folder.create(false, true, monitor);
232
						// necessary directories.
222
	                        }
233
						for (int i = numSegments - 2; i > 0; i--) {
223
	                    }
234
							IFolder folder = root.getFolder(path
224
	                }
235
									.removeLastSegments(i));
225
                    folderHandle.create(false, true, monitor);
236
							if (!folder.exists()) {
226
                }
237
								folder.create(false, true, monitor);
227
            }
238
							}
228
        } catch (CoreException e) {
239
						}
229
            // If the folder already existed locally, just refresh to get contents
240
					}
230
            if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED) {
241
					folderHandle.create(false, true, monitor);
242
				}
243
			}
244
		} catch (CoreException e) {
245
			// If the folder already existed locally, just refresh to get
246
			// contents
247
			if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED) {
231
				folderHandle.refreshLocal(IResource.DEPTH_INFINITE,
248
				folderHandle.refreshLocal(IResource.DEPTH_INFINITE,
232
                        new SubProgressMonitor(monitor, 500));
249
						new SubProgressMonitor(monitor, 500));
233
			} else {
250
			} else {
234
				throw e;
251
				throw e;
235
			}
252
			}
236
        }
253
		}
237
254
238
        if (monitor.isCanceled()) {
255
		if (monitor.isCanceled()) {
239
			throw new OperationCanceledException();
256
			throw new OperationCanceledException();
240
		}
257
		}
241
    }
258
	}
242
259
243
    /**
260
	/**
244
     * Creates a folder resource handle for the folder with the given workspace path.
261
	 * Creates a folder resource handle for the folder with the given workspace
245
     * This method does not create the folder resource; this is the responsibility
262
	 * path. This method does not create the folder resource; this is the
246
     * of <code>createFolder</code>.
263
	 * responsibility of <code>createFolder</code>.
247
     *
264
	 * 
248
     * @param folderPath the path of the folder resource to create a handle for
265
	 * @param folderPath
249
     * @return the new folder resource handle
266
	 *            the path of the folder resource to create a handle for
250
     * @see #createFolder
267
	 * @return the new folder resource handle
251
     */
268
	 * @see #createFolder
252
    protected IFolder createFolderHandle(IPath folderPath) {
269
	 */
253
        return IDEWorkbenchPlugin.getPluginWorkspace().getRoot().getFolder(
270
	protected IFolder createFolderHandle(IPath folderPath) {
254
                folderPath);
271
		return IDEWorkbenchPlugin.getPluginWorkspace().getRoot().getFolder(
255
    }
272
				folderPath);
256
273
	}
257
    /**
274
258
     * Creates the link target path if a link target has been specified. 
275
	/**
259
     */
276
	 * Creates the link target path if a link target has been specified.
260
    protected void createLinkTarget() {
277
	 */
261
        String linkTarget = linkedResourceGroup.getLinkTarget();
278
	protected void createLinkTarget() {
262
        if (linkTarget != null) {
279
		String linkTarget = linkedResourceGroup.getLinkTarget();
263
            linkTargetPath = new Path(linkTarget);
280
		if (linkTarget != null) {
264
        } else {
281
			linkTargetPath = new Path(linkTarget);
265
            linkTargetPath = null;
282
		} else {
266
        }
283
			linkTargetPath = null;
267
    }
284
		}
268
285
	}
269
    /**
286
270
     * Creates a new folder resource in the selected container and with the selected
287
	/**
271
     * name. Creates any missing resource containers along the path; does nothing if
288
	 * Creates a new folder resource in the selected container and with the
272
     * the container resources already exist.
289
	 * selected name. Creates any missing resource containers along the path;
273
     * <p>
290
	 * does nothing if the container resources already exist.
274
     * In normal usage, this method is invoked after the user has pressed Finish on
291
	 * <p>
275
     * the wizard; the enablement of the Finish button implies that all controls on
292
	 * In normal usage, this method is invoked after the user has pressed Finish
276
     * this page currently contain valid values.
293
	 * on the wizard; the enablement of the Finish button implies that all
277
     * </p>
294
	 * controls on this page currently contain valid values.
278
     * <p>
295
	 * </p>
279
     * Note that this page caches the new folder once it has been successfully
296
	 * <p>
280
     * created; subsequent invocations of this method will answer the same
297
	 * Note that this page caches the new folder once it has been successfully
281
     * folder resource without attempting to create it again.
298
	 * created; subsequent invocations of this method will answer the same
282
     * </p>
299
	 * folder resource without attempting to create it again.
283
     * <p>
300
	 * </p>
284
     * This method should be called within a workspace modify operation since
301
	 * <p>
285
     * it creates resources.
302
	 * This method should be called within a workspace modify operation since it
286
     * </p>
303
	 * creates resources.
287
     *
304
	 * </p>
288
     * @return the created folder resource, or <code>null</code> if the folder
305
	 * 
289
     *    was not created
306
	 * @return the created folder resource, or <code>null</code> if the folder
290
     */
307
	 *         was not created
291
    public IFolder createNewFolder() {
308
	 */
292
        if (newFolder != null) {
309
	public IFolder createNewFolder() {
310
		if (newFolder != null) {
293
			return newFolder;
311
			return newFolder;
294
		}
312
		}
295
313
296
        // create the new folder and cache it if successful
314
		// create the new folder and cache it if successful
297
        final IPath containerPath = resourceGroup.getContainerFullPath();
315
		final IPath containerPath = resourceGroup.getContainerFullPath();
298
        IPath newFolderPath = containerPath.append(resourceGroup.getResource());
316
		IPath newFolderPath = containerPath.append(resourceGroup.getResource());
299
        final IFolder newFolderHandle = createFolderHandle(newFolderPath);
317
		final IFolder newFolderHandle = createFolderHandle(newFolderPath);
300
318
301
        createLinkTarget();
319
		createLinkTarget();
302
        WorkspaceModifyOperation op = new WorkspaceModifyOperation(createRule(newFolderHandle)) {
320
		IRunnableWithProgress op = new IRunnableWithProgress() {
303
            public void execute(IProgressMonitor monitor) throws CoreException {
321
			public void run(IProgressMonitor monitor) {
304
                try {
322
				CreateFolderOperation op = new CreateFolderOperation(
305
                    monitor.beginTask(IDEWorkbenchMessages.WizardNewFolderCreationPage_progress, 2000);
323
						newFolderHandle, linkTargetPath,
306
                    ContainerGenerator generator = new ContainerGenerator(
324
						IDEWorkbenchMessages.WizardNewFolderCreationPage_title);
307
                            containerPath);
325
				try {
308
                    generator.generateContainer(new SubProgressMonitor(monitor,
326
					PlatformUI.getWorkbench().getOperationSupport()
309
                            1000));
327
							.getOperationHistory().execute(op, monitor,
310
                    createFolder(newFolderHandle, new SubProgressMonitor(
328
									new IAdaptable() {
311
                            monitor, 1000));
329
										public Object getAdapter(Class clazz) {
312
                } finally {
330
											if (clazz == Shell.class) {
313
                    monitor.done();
331
												return getContainer()
314
                }
332
														.getShell();
315
            }
333
											}
316
        };
334
											return null;
317
335
										}
318
        try {
336
									});
319
            getContainer().run(true, true, op);
337
				} catch (ExecutionException e) {
320
        } catch (InterruptedException e) {
338
					IDEWorkbenchPlugin.log(e.getMessage(), e);
321
            return null;
339
				}
322
        } catch (InvocationTargetException e) {
340
			}
323
            if (e.getTargetException() instanceof CoreException) {
341
		};
324
                ErrorDialog
342
325
                        .openError(
343
		try {
326
                                getContainer().getShell(), // Was Utilities.getFocusShell()
344
			getContainer().run(true, true, op);
327
                                IDEWorkbenchMessages.WizardNewFolderCreationPage_errorTitle,
345
		} catch (InterruptedException e) {
328
                                null, // no special message
346
			return null;
329
                                ((CoreException) e.getTargetException())
347
		} catch (InvocationTargetException e) {
330
                                        .getStatus());
348
			// ExecutionExceptions are handled above, but unexpected runtime
331
            } else {
349
			// exceptions and errors may still occur.
332
                // CoreExceptions are handled above, but unexpected runtime exceptions and errors may still occur.
350
			IDEWorkbenchPlugin.log(getClass(),
333
351
					"createNewFolder()", e.getTargetException()); //$NON-NLS-1$
334
                IDEWorkbenchPlugin.log(getClass(),
352
            MessageDialog
335
                        "createNewFolder()", e.getTargetException()); //$NON-NLS-1$
353
				.openError(
336
                MessageDialog
354
					getContainer().getShell(),
337
                        .openError(
355
					IDEWorkbenchMessages.WizardNewFolderCreationPage_internalErrorTitle, NLS.bind(IDEWorkbenchMessages.WizardNewFolder_internalError, e.getTargetException().getMessage()));
338
                                getContainer().getShell(),
356
			return null;
339
                                IDEWorkbenchMessages.WizardNewFolderCreationPage_internalErrorTitle, NLS.bind(IDEWorkbenchMessages.WizardNewFolder_internalError, e.getTargetException().getMessage()));
357
		}
340
            }
358
341
            return null; // ie.- one of the steps resulted in a core exception
359
		newFolder = newFolderHandle;
342
        }
360
343
361
		return newFolder;
344
        newFolder = newFolderHandle;
362
	}
345
363
346
        return newFolder;
364
	/**
347
    }
365
	 * Shows/hides the advanced option widgets.
348
366
	 */
349
    /**
367
	protected void handleAdvancedButtonSelect() {
350
     * Returns the scheduling rule to use when creating the resource at
368
		Shell shell = getShell();
351
     * the given container path. The rule should be the creation rule for
369
		Point shellSize = shell.getSize();
352
     * the top-most non-existing parent.
370
		Composite composite = (Composite) getControl();
353
     * @param resource The resource being created
371
354
     * @return The scheduling rule for creating the given resource
372
		if (linkedResourceComposite != null) {
355
     * @since 3.1
373
			linkedResourceComposite.dispose();
356
     */
374
			linkedResourceComposite = null;
357
    private ISchedulingRule createRule(IResource resource) {
375
			composite.layout();
358
		IResource parent = resource.getParent();
376
			shell.setSize(shellSize.x, shellSize.y - linkedResourceGroupHeight);
359
    	while (parent != null) {
377
			advancedButton.setText(IDEWorkbenchMessages.showAdvanced);
360
    		if (parent.exists()) {
378
		} else {
361
				return resource.getWorkspace().getRuleFactory().createRule(resource);
379
			linkedResourceComposite = linkedResourceGroup
380
					.createContents(linkedResourceParent);
381
			if (linkedResourceGroupHeight == -1) {
382
				Point groupSize = linkedResourceComposite.computeSize(
383
						SWT.DEFAULT, SWT.DEFAULT, true);
384
				linkedResourceGroupHeight = groupSize.y;
385
			}
386
			shell.setSize(shellSize.x, shellSize.y + linkedResourceGroupHeight);
387
			composite.layout();
388
			advancedButton.setText(IDEWorkbenchMessages.hideAdvanced);
389
		}
390
	}
391
392
	/**
393
	 * The <code>WizardNewFolderCreationPage</code> implementation of this
394
	 * <code>Listener</code> method handles all events and enablements for
395
	 * controls on this page. Subclasses may extend.
396
	 */
397
	public void handleEvent(Event ev) {
398
		setPageComplete(validatePage());
399
	}
400
401
	/**
402
	 * Initializes this page's controls.
403
	 */
404
	protected void initializePage() {
405
		Iterator it = currentSelection.iterator();
406
		if (it.hasNext()) {
407
			Object next = it.next();
408
			IResource selectedResource = null;
409
			if (next instanceof IResource) {
410
				selectedResource = (IResource) next;
411
			} else if (next instanceof IAdaptable) {
412
				selectedResource = (IResource) ((IAdaptable) next)
413
						.getAdapter(IResource.class);
362
			}
414
			}
363
    		resource = parent;
415
			if (selectedResource != null) {
364
    		parent = parent.getParent();
416
				if (selectedResource.getType() == IResource.FILE) {
365
    	}
366
		return resource.getWorkspace().getRoot();
367
	}
368
369
    /**
370
     * Shows/hides the advanced option widgets. 
371
     */
372
    protected void handleAdvancedButtonSelect() {
373
        Shell shell = getShell();
374
        Point shellSize = shell.getSize();
375
        Composite composite = (Composite) getControl();
376
377
        if (linkedResourceComposite != null) {
378
            linkedResourceComposite.dispose();
379
            linkedResourceComposite = null;
380
            composite.layout();
381
            shell.setSize(shellSize.x, shellSize.y - linkedResourceGroupHeight);
382
            advancedButton.setText(IDEWorkbenchMessages.showAdvanced);
383
        } else {
384
            linkedResourceComposite = linkedResourceGroup
385
                    .createContents(linkedResourceParent);
386
            if (linkedResourceGroupHeight == -1) {
387
                Point groupSize = linkedResourceComposite.computeSize(
388
                        SWT.DEFAULT, SWT.DEFAULT, true);
389
                linkedResourceGroupHeight = groupSize.y;
390
            }
391
            shell.setSize(shellSize.x, shellSize.y + linkedResourceGroupHeight);
392
            composite.layout();
393
            advancedButton.setText(IDEWorkbenchMessages.hideAdvanced);
394
        }
395
    }
396
397
    /**
398
     * The <code>WizardNewFolderCreationPage</code> implementation of this 
399
     * <code>Listener</code> method handles all events and enablements for controls
400
     * on this page. Subclasses may extend.
401
     */
402
    public void handleEvent(Event ev) {
403
        setPageComplete(validatePage());
404
    }
405
406
    /**
407
     * Initializes this page's controls.
408
     */
409
    protected void initializePage() {
410
        Iterator it = currentSelection.iterator();
411
        if (it.hasNext()) {
412
            Object next = it.next();
413
            IResource selectedResource = null;
414
            if (next instanceof IResource) {
415
                selectedResource = (IResource) next;
416
            } else if (next instanceof IAdaptable) {
417
                selectedResource = (IResource) ((IAdaptable) next)
418
                        .getAdapter(IResource.class);
419
            }
420
            if (selectedResource != null) {
421
                if (selectedResource.getType() == IResource.FILE) {
422
					selectedResource = selectedResource.getParent();
417
					selectedResource = selectedResource.getParent();
423
				}
418
				}
424
                if (selectedResource.isAccessible()) {
419
				if (selectedResource.isAccessible()) {
425
					resourceGroup.setContainerFullPath(selectedResource
420
					resourceGroup.setContainerFullPath(selectedResource
426
                            .getFullPath());
421
							.getFullPath());
427
				}
422
				}
428
            }
423
			}
429
        }
424
		}
430
425
431
        setPageComplete(false);
426
		setPageComplete(false);
432
    }
427
	}
433
428
434
    /*
429
	/*
435
     * @see DialogPage.setVisible(boolean)
430
	 * @see DialogPage.setVisible(boolean)
436
     */
431
	 */
437
    public void setVisible(boolean visible) {
432
	public void setVisible(boolean visible) {
438
        super.setVisible(visible);
433
		super.setVisible(visible);
439
        if (visible) {
434
		if (visible) {
440
			resourceGroup.setFocus();
435
			resourceGroup.setFocus();
441
		}
436
		}
442
    }
437
	}
443
438
444
    /**
439
	/**
445
     * Checks whether the linked resource target is valid.
440
	 * Checks whether the linked resource target is valid. Sets the error
446
     * Sets the error message accordingly and returns the status.
441
	 * message accordingly and returns the status.
447
     *  
442
	 * 
448
     * @return IStatus validation result from the CreateLinkedResourceGroup
443
	 * @return IStatus validation result from the CreateLinkedResourceGroup
449
     */
444
	 */
450
    protected IStatus validateLinkedResource() {
445
	protected IStatus validateLinkedResource() {
451
        IPath containerPath = resourceGroup.getContainerFullPath();
446
		IPath containerPath = resourceGroup.getContainerFullPath();
452
        IPath newFolderPath = containerPath.append(resourceGroup.getResource());
447
		IPath newFolderPath = containerPath.append(resourceGroup.getResource());
453
        IFolder newFolderHandle = createFolderHandle(newFolderPath);
448
		IFolder newFolderHandle = createFolderHandle(newFolderPath);
454
        IStatus status = linkedResourceGroup
449
		IStatus status = linkedResourceGroup
455
                .validateLinkLocation(newFolderHandle);
450
				.validateLinkLocation(newFolderHandle);
456
451
457
        if (status.getSeverity() == IStatus.ERROR) {
452
		if (status.getSeverity() == IStatus.ERROR) {
458
            if (firstLinkCheck) {
453
			if (firstLinkCheck) {
459
				setMessage(status.getMessage());
454
				setMessage(status.getMessage());
460
			} else {
455
			} else {
461
				setErrorMessage(status.getMessage());
456
				setErrorMessage(status.getMessage());
462
			}
457
			}
463
        } else if (status.getSeverity() == IStatus.WARNING) {
458
		} else if (status.getSeverity() == IStatus.WARNING) {
464
            setMessage(status.getMessage(), WARNING);
459
			setMessage(status.getMessage(), WARNING);
465
            setErrorMessage(null);
460
			setErrorMessage(null);
466
        }
461
		}
467
        return status;
462
		return status;
468
    }
463
	}
469
464
470
    /**
465
	/**
471
     * Returns whether this page's controls currently all contain valid 
466
	 * Returns whether this page's controls currently all contain valid values.
472
     * values.
467
	 * 
473
     *
468
	 * @return <code>true</code> if all controls are valid, and
474
     * @return <code>true</code> if all controls are valid, and
469
	 *         <code>false</code> if at least one is invalid
475
     *   <code>false</code> if at least one is invalid
470
	 */
476
     */
471
	protected boolean validatePage() {
477
    protected boolean validatePage() {
472
		boolean valid = true;
478
        boolean valid = true;
473
479
474
		if (!resourceGroup.areAllValuesValid()) {
480
        if (!resourceGroup.areAllValuesValid()) {
475
			// if blank name then fail silently
481
            // if blank name then fail silently
476
			if (resourceGroup.getProblemType() == ResourceAndContainerGroup.PROBLEM_RESOURCE_EMPTY
482
            if (resourceGroup.getProblemType() == ResourceAndContainerGroup.PROBLEM_RESOURCE_EMPTY
477
					|| resourceGroup.getProblemType() == ResourceAndContainerGroup.PROBLEM_CONTAINER_EMPTY) {
483
                    || resourceGroup.getProblemType() == ResourceAndContainerGroup.PROBLEM_CONTAINER_EMPTY) {
478
				setMessage(resourceGroup.getProblemMessage());
484
                setMessage(resourceGroup.getProblemMessage());
479
				setErrorMessage(null);
485
                setErrorMessage(null);
480
			} else {
486
            } else {
481
				setErrorMessage(resourceGroup.getProblemMessage());
487
                setErrorMessage(resourceGroup.getProblemMessage());
482
			}
488
            }
483
			valid = false;
489
            valid = false;
484
		}
490
        }
485
491
486
		IStatus linkedResourceStatus = null;
492
        IStatus linkedResourceStatus = null;
487
		if (valid) {
493
        if (valid) {
488
			linkedResourceStatus = validateLinkedResource();
494
            linkedResourceStatus = validateLinkedResource();
489
			if (linkedResourceStatus.getSeverity() == IStatus.ERROR) {
495
            if (linkedResourceStatus.getSeverity() == IStatus.ERROR) {
496
				valid = false;
490
				valid = false;
497
			}
491
			}
498
        }
492
		}
499
        // validateLinkedResource sets messages itself
493
		// validateLinkedResource sets messages itself
500
        if (valid
494
		if (valid
501
                && (linkedResourceStatus == null || linkedResourceStatus.isOK())) {
495
				&& (linkedResourceStatus == null || linkedResourceStatus.isOK())) {
502
            setMessage(null);
496
			setMessage(null);
503
            setErrorMessage(null);
497
			setErrorMessage(null);
504
        }
498
		}
505
        return valid;
499
		return valid;
506
    }
500
	}
507
501
508
}
502
}
509
(-)src/org/eclipse/ui/internal/ide/undo/UndoMessages.java (+23 lines)
Lines 36-41 Link Here
36
	public static String AbstractWorkspaceOperation_RedoSideEffectsWarningMessage;
36
	public static String AbstractWorkspaceOperation_RedoSideEffectsWarningMessage;
37
	public static String AbstractWorkspaceOperation_ErrorInvalidMessage;
37
	public static String AbstractWorkspaceOperation_ErrorInvalidMessage;
38
	public static String AbstractWorkspaceOperation_GenericWarningMessage;
38
	public static String AbstractWorkspaceOperation_GenericWarningMessage;
39
	
40
	public static String AbstractResourcesOperation_ResourcesDoNotExist;
41
	public static String AbstractResourcesOperation_NotEnoughInfo;
42
	public static String AbstractResourcesOperation_InvalidRestoreInfo;
43
	public static String AbstractResourcesOperation_DeleteResourcesProgress;
44
	public static String AbstractResourcesOperation_CreateResourcesProgress;
45
	public static String AbstractResourcesOperation_CopyingResourcesProgress;
46
	public static String AbstractResourcesOperation_MovingResources;
47
	public static String AbstractResourcesOperation_outOfSyncError;
48
	public static String AbstractResourcesOperation_outOfSyncQuestion;
49
	public static String AbstractResourcesOperation_deletionMessageTitle;
50
	public static String AbstractResourcesOperation_deletionExceptionMessage;
51
52
	public static String DeleteResourcesOperation_DeletingProjectContentWarning;
53
	public static String CreateProjectOperation_caseVariantExistsError;
54
	
55
	public static String ProjectDescription_NewProjectProgress;
56
	public static String FileDescription_NewFileProgress;
57
	public static String FileDescription_SavingUndoInfoProgress;
58
	public static String FileDescription_ContentsCouldNotBeRestored;
59
	public static String FolderDescription_NewFolderProgress;
60
	public static String FolderDescription_SavingUndoInfoProgress;
61
	
39
62
40
	public static String MarkerOperation_ResourceDoesNotExist;
63
	public static String MarkerOperation_ResourceDoesNotExist;
41
	public static String MarkerOperation_MarkerDoesNotExist;
64
	public static String MarkerOperation_MarkerDoesNotExist;
(-)src/org/eclipse/ui/internal/ide/undo/messages.properties (+23 lines)
Lines 20-25 Link Here
20
AbstractWorkspaceOperation_UndoSideEffectsWarningMessage=Undoing "{0}" may have undesirable side effects.
20
AbstractWorkspaceOperation_UndoSideEffectsWarningMessage=Undoing "{0}" may have undesirable side effects.
21
AbstractWorkspaceOperation_RedoSideEffectsWarningMessage=Redoing "{0}" may have undesirable side effects.
21
AbstractWorkspaceOperation_RedoSideEffectsWarningMessage=Redoing "{0}" may have undesirable side effects.
22
22
23
AbstractResourcesOperation_ResourcesDoNotExist=Cannot complete operation because resources no longer exist.
24
AbstractResourcesOperation_NotEnoughInfo=There is not enough information to complete the resource operation.
25
AbstractResourcesOperation_InvalidRestoreInfo=There is no longer enough information to restore the resource.
26
AbstractResourcesOperation_DeleteResourcesProgress=Deleting resources...
27
AbstractResourcesOperation_CreateResourcesProgress=Creating resources...
28
AbstractResourcesOperation_CopyingResourcesProgress=Copying resources...
29
AbstractResourcesOperation_MovingResources=Moving resources...
30
AbstractResourcesOperation_outOfSyncError = Resource is out of sync with the file system. Refresh and try again.
31
AbstractResourcesOperation_outOfSyncQuestion = Resource ''{0}'' is out of sync with the file system. Do you want to delete it anyway?
32
AbstractResourcesOperation_deleteMessageTitle = Problems deleting
33
AbstractResourcesOperation_deletionExceptionMessage=Multiple problems occurred while deleting resources.
34
35
DeleteResourcesOperation_DeletingProjectContentWarning=Deleting a project's content will erase all of its file and folder history.  Only the project itself can be restored by undoing this operation.
36
37
CreateProjectOperation_caseVariantExistsError = The underlying file system is case insensitive. There is an existing project which conflicts with ''{0}''.
38
39
ProjectDescription_NewProjectProgress=Creating new project...
40
FileDescription_NewFileProgress=Creating new file...
41
FileDescription_ContentsCouldNotBeRestored=Unexpected error.  File contents could not be restored from local history during undo/redo.
42
FileDescription_SavingUndoInfoProgress=Saving file info...
43
FolderDescription_NewFolderProgress=Creating new folder...
44
FolderDescription_SavingUndoInfoProgress=Saving folder info...
45
	
23
MarkerOperation_ResourceDoesNotExist=Cannot complete operation because resource no longer exists.
46
MarkerOperation_ResourceDoesNotExist=Cannot complete operation because resource no longer exists.
24
MarkerOperation_MarkerDoesNotExist=Cannot complete operation because marker no longer exists.
47
MarkerOperation_MarkerDoesNotExist=Cannot complete operation because marker no longer exists.
25
MarkerOperation_NotEnoughInfo=There is not enough information to perform the marker operation.
48
MarkerOperation_NotEnoughInfo=There is not enough information to perform the marker operation.
(-)extensions/org/eclipse/ui/actions/DeleteResourceAction.java (-210 / +23 lines)
Lines 10-34 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.ui.actions;
11
package org.eclipse.ui.actions;
12
12
13
import java.util.ArrayList;
14
import java.util.List;
13
import java.util.List;
15
14
15
import org.eclipse.core.commands.ExecutionException;
16
import org.eclipse.core.resources.IProject;
16
import org.eclipse.core.resources.IProject;
17
import org.eclipse.core.resources.IResource;
17
import org.eclipse.core.resources.IResource;
18
import org.eclipse.core.resources.IResourceRuleFactory;
18
import org.eclipse.core.resources.IResourceRuleFactory;
19
import org.eclipse.core.resources.IResourceStatus;
20
import org.eclipse.core.resources.IWorkspace;
21
import org.eclipse.core.resources.IWorkspaceRunnable;
22
import org.eclipse.core.resources.ResourcesPlugin;
19
import org.eclipse.core.resources.ResourcesPlugin;
23
import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
20
import org.eclipse.core.runtime.IAdaptable;
24
import org.eclipse.core.resources.mapping.ResourceChangeValidator;
25
import org.eclipse.core.runtime.CoreException;
26
import org.eclipse.core.runtime.IProgressMonitor;
21
import org.eclipse.core.runtime.IProgressMonitor;
27
import org.eclipse.core.runtime.IStatus;
22
import org.eclipse.core.runtime.IStatus;
28
import org.eclipse.core.runtime.MultiStatus;
29
import org.eclipse.core.runtime.OperationCanceledException;
30
import org.eclipse.core.runtime.Status;
23
import org.eclipse.core.runtime.Status;
31
import org.eclipse.core.runtime.SubProgressMonitor;
32
import org.eclipse.core.runtime.jobs.ISchedulingRule;
24
import org.eclipse.core.runtime.jobs.ISchedulingRule;
33
import org.eclipse.core.runtime.jobs.Job;
25
import org.eclipse.core.runtime.jobs.Job;
34
import org.eclipse.core.runtime.jobs.MultiRule;
26
import org.eclipse.core.runtime.jobs.MultiRule;
Lines 47-53 Link Here
47
import org.eclipse.swt.widgets.Control;
39
import org.eclipse.swt.widgets.Control;
48
import org.eclipse.swt.widgets.Shell;
40
import org.eclipse.swt.widgets.Shell;
49
import org.eclipse.ui.PlatformUI;
41
import org.eclipse.ui.PlatformUI;
50
import org.eclipse.ui.ide.IDE;
42
import org.eclipse.ui.ide.undo.DeleteResourcesOperation;
51
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
43
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
52
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
44
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
53
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
45
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
Lines 207-217 Link Here
207
	private boolean deleteContent = false;
199
	private boolean deleteContent = false;
208
200
209
	/**
201
	/**
210
	 * Whether or not to automatically delete out of sync resources
211
	 */
212
	private boolean forceOutOfSyncDelete = false;
213
214
	/**
215
	 * Flag that allows testing mode ... it won't pop up the project delete
202
	 * Flag that allows testing mode ... it won't pop up the project delete
216
	 * dialog, and will return "delete all content".
203
	 * dialog, and will return "delete all content".
217
	 */
204
	 */
Lines 317-360 Link Here
317
	}
304
	}
318
305
319
	/**
306
	/**
320
	 * Creates and returns a result status appropriate for the given list of
321
	 * exceptions.
322
	 * 
323
	 * @param exceptions
324
	 *            The list of exceptions that occurred (may be empty)
325
	 * @return The result status for the deletion
326
	 */
327
	private IStatus createResult(List exceptions) {
328
		if (exceptions.isEmpty()) {
329
			return Status.OK_STATUS;
330
		}
331
		final int exceptionCount = exceptions.size();
332
		if (exceptionCount == 1) {
333
			return ((CoreException) exceptions.get(0)).getStatus();
334
		}
335
		CoreException[] children = (CoreException[]) exceptions
336
				.toArray(new CoreException[exceptionCount]);
337
		boolean outOfSync = false;
338
		for (int i = 0; i < children.length; i++) {
339
			if (children[i].getStatus().getCode() == IResourceStatus.OUT_OF_SYNC_LOCAL) {
340
				outOfSync = true;
341
				break;
342
			}
343
		}
344
		String title = outOfSync ? IDEWorkbenchMessages.DeleteResourceAction_outOfSyncError
345
				: IDEWorkbenchMessages.DeleteResourceAction_deletionExceptionMessage;
346
		final MultiStatus multi = new MultiStatus(
347
				IDEWorkbenchPlugin.IDE_WORKBENCH, 0, title, null);
348
		for (int i = 0; i < exceptionCount; i++) {
349
			CoreException exception = children[i];
350
			IStatus status = exception.getStatus();
351
			multi.add(new Status(status.getSeverity(), status.getPlugin(),
352
					status.getCode(), status.getMessage(), exception));
353
		}
354
		return multi;
355
	}
356
357
	/**
358
	 * Asks the user to confirm a delete operation.
307
	 * Asks the user to confirm a delete operation.
359
	 * 
308
	 * 
360
	 * @param resources
309
	 * @param resources
Lines 363-375 Link Here
363
	 *         <code>false</code> if the deletion should be abandoned
312
	 *         <code>false</code> if the deletion should be abandoned
364
	 */
313
	 */
365
	private boolean confirmDelete(IResource[] resources) {
314
	private boolean confirmDelete(IResource[] resources) {
366
		if (validateDelete(resources)) {
315
		if (containsOnlyProjects(resources)) {
367
			if (containsOnlyProjects(resources)) {
316
			return confirmDeleteProjects(resources);
368
				return confirmDeleteProjects(resources);
369
			}
370
			return confirmDeleteNonProjects(resources);
371
		}
317
		}
372
		return false;
318
		return confirmDeleteNonProjects(resources);
319
		
373
	}
320
	}
374
321
375
	/**
322
	/**
Lines 430-511 Link Here
430
		return code == 0; // YES
377
		return code == 0; // YES
431
	}
378
	}
432
379
433
	/**
434
	 * Deletes the given resources.
435
	 */
436
	private void delete(IResource[] resourcesToDelete, IProgressMonitor monitor)
437
			throws CoreException {
438
		final List exceptions = new ArrayList();
439
		forceOutOfSyncDelete = false;
440
		monitor.beginTask("", resourcesToDelete.length); //$NON-NLS-1$
441
		try {
442
			for (int i = 0; i < resourcesToDelete.length; ++i) {
443
				if (monitor.isCanceled()) {
444
					throw new OperationCanceledException();
445
				}
446
				try {
447
					delete(resourcesToDelete[i], new SubProgressMonitor(
448
							monitor, 1,
449
							SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
450
				} catch (CoreException e) {
451
					exceptions.add(e);
452
				}
453
			}
454
			IStatus result = createResult(exceptions);
455
			if (!result.isOK()) {
456
				throw new CoreException(result);
457
			}
458
		} finally {
459
			monitor.done();
460
		}
461
	}
462
380
463
	/**
381
464
	 * Deletes the given resource.
465
	 */
466
	private void delete(IResource resourceToDelete, IProgressMonitor monitor)
467
			throws CoreException {
468
		boolean force = false; // don't force deletion of out-of-sync resources
469
		try {
470
			if (resourceToDelete.getType() == IResource.PROJECT) {
471
				// if it's a project, ask whether content should be deleted too
472
				IProject project = (IProject) resourceToDelete;
473
				project.delete(deleteContent, force, monitor);
474
			} else {
475
				// if it's not a project, just delete it
476
				resourceToDelete.delete(IResource.KEEP_HISTORY, monitor);
477
			}
478
		} catch (CoreException exception) {
479
			if (resourceToDelete.getType() == IResource.FILE) {
480
				IStatus[] children = exception.getStatus().getChildren();
481
482
				if (children.length == 1
483
						&& children[0].getCode() == IResourceStatus.OUT_OF_SYNC_LOCAL) {
484
					if (forceOutOfSyncDelete) {
485
						resourceToDelete.delete(IResource.KEEP_HISTORY
486
								| IResource.FORCE, monitor);
487
					} else {
488
						int result = queryDeleteOutOfSync(resourceToDelete);
489
490
						if (result == IDialogConstants.YES_ID) {
491
							resourceToDelete.delete(IResource.KEEP_HISTORY
492
									| IResource.FORCE, monitor);
493
						} else if (result == IDialogConstants.YES_TO_ALL_ID) {
494
							forceOutOfSyncDelete = true;
495
							resourceToDelete.delete(IResource.KEEP_HISTORY
496
									| IResource.FORCE, monitor);
497
						} else if (result == IDialogConstants.CANCEL_ID) {
498
							throw new OperationCanceledException();
499
						}
500
					}
501
				} else {
502
					throw exception;
503
				}
504
			} else {
505
				throw exception;
506
			}
507
		}
508
	}
509
382
510
	/**
383
	/**
511
	 * Return an array of the currently selected resources.
384
	 * Return an array of the currently selected resources.
Lines 593-609 Link Here
593
				IDEWorkbenchMessages.DeleteResourceAction_jobName) {
466
				IDEWorkbenchMessages.DeleteResourceAction_jobName) {
594
			public IStatus run(IProgressMonitor monitor) {
467
			public IStatus run(IProgressMonitor monitor) {
595
				try {
468
				try {
596
					ResourcesPlugin.getWorkspace().run(
469
					DeleteResourcesOperation op = 
597
							new IWorkspaceRunnable() {
470
						new DeleteResourcesOperation(resourcesToDelete, getText(), deleteContent);
598
								public void run(IProgressMonitor monitor)
471
					op.setModelProviderIds(getModelProviderIds());
599
										throws CoreException {
472
					return PlatformUI.getWorkbench().getOperationSupport()
600
									delete(resourcesToDelete, monitor);
473
					.getOperationHistory().execute(op, monitor, new IAdaptable() {
601
								}
474
	   					public Object getAdapter(Class clazz) {
602
							}, null, IWorkspace.AVOID_UPDATE, monitor);
475
	   						if (clazz == Shell.class) {
603
				} catch (CoreException e) {
476
	   							return shell;
604
					return e.getStatus();
477
	   						}
478
	   						return null;
479
	   					}
480
	   				});
481
				} catch (ExecutionException e) {
482
					IDEWorkbenchPlugin.log(e.getMessage(), e);
483
					return new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, e.getMessage(),e);
605
				}
484
				}
606
				return Status.OK_STATUS;
607
			}
485
			}
608
486
609
			/*
487
			/*
Lines 678-748 Link Here
678
	}
556
	}
679
557
680
	/**
558
	/**
681
	 * Ask the user whether the given resource should be deleted despite being
682
	 * out of sync with the file system.
683
	 * 
684
	 * @param resource
685
	 *            the out of sync resource
686
	 * @return One of the IDialogConstants constants indicating which of the
687
	 *         Yes, Yes to All, No, Cancel options has been selected by the
688
	 *         user.
689
	 */
690
	private int queryDeleteOutOfSync(IResource resource) {
691
		final MessageDialog dialog = new MessageDialog(
692
				shell,
693
				IDEWorkbenchMessages.DeleteResourceAction_messageTitle,
694
				null,
695
				NLS
696
						.bind(
697
								IDEWorkbenchMessages.DeleteResourceAction_outOfSyncQuestion,
698
								resource.getName()), MessageDialog.QUESTION,
699
				new String[] { IDialogConstants.YES_LABEL,
700
						IDialogConstants.YES_TO_ALL_LABEL,
701
						IDialogConstants.NO_LABEL,
702
						IDialogConstants.CANCEL_LABEL }, 0);
703
		shell.getDisplay().syncExec(new Runnable() {
704
			public void run() {
705
				dialog.open();
706
			}
707
		});
708
		int result = dialog.getReturnCode();
709
		if (result == 0) {
710
			return IDialogConstants.YES_ID;
711
		}
712
		if (result == 1) {
713
			return IDialogConstants.YES_TO_ALL_ID;
714
		}
715
		if (result == 2) {
716
			return IDialogConstants.NO_ID;
717
		}
718
		return IDialogConstants.CANCEL_ID;
719
	}
720
721
	/**
722
	 * Validates the operation against the model providers.
723
	 * 
724
	 * @param resources
725
	 *            the resources to be deleted
726
	 * @return whether the operation should proceed
727
	 */
728
	private boolean validateDelete(IResource[] resources) {
729
		IResourceChangeDescriptionFactory factory = ResourceChangeValidator
730
				.getValidator().createDeltaFactory();
731
		for (int i = 0; i < resources.length; i++) {
732
			IResource resource = resources[i];
733
			factory.delete(resource);
734
		}
735
		return IDE.promptToConfirm(shell,
736
				IDEWorkbenchMessages.DeleteResourceAction_confirm,
737
				IDEWorkbenchMessages.DeleteResourceAction_warning, factory
738
						.getDelta(), getModelProviderIds(), false /*
739
																	 * no need
740
																	 * to
741
																	 * syncExec
742
																	 */);
743
	}
744
745
	/**
746
	 * Returns the model provider ids that are known to the client that
559
	 * Returns the model provider ids that are known to the client that
747
	 * instantiated this operation.
560
	 * instantiated this operation.
748
	 * 
561
	 * 
(-)extensions/org/eclipse/ui/actions/MoveProjectAction.java (-67 / +30 lines)
Lines 12-33 Link Here
12
12
13
import java.lang.reflect.InvocationTargetException;
13
import java.lang.reflect.InvocationTargetException;
14
14
15
import org.eclipse.core.commands.ExecutionException;
15
import org.eclipse.core.resources.IProject;
16
import org.eclipse.core.resources.IProject;
16
import org.eclipse.core.resources.IProjectDescription;
17
import org.eclipse.core.resources.IResource;
17
import org.eclipse.core.resources.IResource;
18
import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
18
import org.eclipse.core.runtime.IAdaptable;
19
import org.eclipse.core.resources.mapping.ResourceChangeValidator;
20
import org.eclipse.core.runtime.CoreException;
21
import org.eclipse.core.runtime.IPath;
19
import org.eclipse.core.runtime.IPath;
22
import org.eclipse.core.runtime.IProgressMonitor;
20
import org.eclipse.core.runtime.IProgressMonitor;
23
import org.eclipse.core.runtime.OperationCanceledException;
24
import org.eclipse.core.runtime.Path;
21
import org.eclipse.core.runtime.Path;
25
import org.eclipse.jface.dialogs.ErrorDialog;
22
import org.eclipse.jface.operation.IRunnableWithProgress;
26
import org.eclipse.osgi.util.NLS;
23
import org.eclipse.osgi.util.NLS;
27
import org.eclipse.swt.widgets.Shell;
24
import org.eclipse.swt.widgets.Shell;
28
import org.eclipse.ui.PlatformUI;
25
import org.eclipse.ui.PlatformUI;
29
import org.eclipse.ui.dialogs.ProjectLocationMoveDialog;
26
import org.eclipse.ui.dialogs.ProjectLocationMoveDialog;
30
import org.eclipse.ui.ide.IDE;
27
import org.eclipse.ui.ide.undo.MoveResourcesOperation;
31
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
28
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
32
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
29
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
33
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
30
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
Lines 44-51 Link Here
44
41
45
	private static String PROBLEMS_TITLE = IDEWorkbenchMessages.MoveProjectAction_dialogTitle;
42
	private static String PROBLEMS_TITLE = IDEWorkbenchMessages.MoveProjectAction_dialogTitle;
46
43
47
	private static String MOVE_PROGRESS_TITLE = IDEWorkbenchMessages.MoveProjectAction_progressMessage;
48
49
	/**
44
	/**
50
	 * The id of this action.
45
	 * The id of this action.
51
	 */
46
	 */
Lines 69-74 Link Here
69
	 * Return the title of the errors dialog.
64
	 * Return the title of the errors dialog.
70
	 * 
65
	 * 
71
	 * @return java.lang.String
66
	 * @return java.lang.String
67
	 * 
68
	 * @deprecated As of 3.3, the error handling is performed by the undoable 
69
	 * operation which handles the move.
72
	 */
70
	 */
73
	protected String getErrorsTitle() {
71
	protected String getErrorsTitle() {
74
		return PROBLEMS_TITLE;
72
		return PROBLEMS_TITLE;
Lines 88-122 Link Here
88
	 */
86
	 */
89
	boolean performMove(final IProject project, final String projectName,
87
	boolean performMove(final IProject project, final String projectName,
90
			final IPath newLocation) {
88
			final IPath newLocation) {
91
		WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
89
		
92
			public void execute(IProgressMonitor monitor) {
90
		IRunnableWithProgress op =  new IRunnableWithProgress() {
93
				try {
91
    		public void run(IProgressMonitor monitor) {
94
					if (monitor.isCanceled()) {
92
    			MoveResourcesOperation op = new MoveResourcesOperation(new IResource[] {project}, newLocation, getText());
95
						throw new OperationCanceledException();
93
    			op.setModelProviderIds(getModelProviderIds());
96
					}
94
    			try {
97
					
95
    				PlatformUI.getWorkbench().getOperationSupport()
98
					monitor.setTaskName(MOVE_PROGRESS_TITLE);
96
    						.getOperationHistory().execute(op, monitor, new IAdaptable() {
99
					//Get a copy of the current description and modify it
97
    		   					public Object getAdapter(Class clazz) {
100
					IProjectDescription newDescription = createDescription(
98
    		   						if (clazz == Shell.class) {
101
							project, projectName, newLocation);
99
    		   							return shell;
102
100
    		   						}
103
					project.move(newDescription, IResource.FORCE
101
    		   						return null;
104
							| IResource.SHALLOW, monitor);
102
    		   					}
105
103
    		   				});
106
				} catch (CoreException e) {
104
    			} catch (ExecutionException e) {
107
					recordError(e); // log error
105
    				IDEWorkbenchPlugin.log(e.getMessage(), e);
108
				} finally {
106
    			}
109
					monitor.done();
107
    		}
110
				}
108
    	};
111
			}
109
		
112
		};
113
114
		try {
110
		try {
115
			new ProgressMonitorJobsDialog(shell).run(true, true, op);
111
			new ProgressMonitorJobsDialog(shell).run(true, true, op);
116
		} catch (InterruptedException e) {
112
		} catch (InterruptedException e) {
117
			return false;
113
			return false;
118
		} catch (InvocationTargetException e) {
114
		} catch (InvocationTargetException e) {
119
			// CoreExceptions are collected above, but unexpected runtime
115
			// CoreExceptions are collected by the operation, but unexpected runtime
120
			// exceptions and errors may still occur.
116
			// exceptions and errors may still occur.
121
			IDEWorkbenchPlugin.log(getClass(),
117
			IDEWorkbenchPlugin.log(getClass(),
122
                    "performMove()", e.getTargetException()); //$NON-NLS-1$
118
                    "performMove()", e.getTargetException()); //$NON-NLS-1$
Lines 160-199 Link Here
160
156
161
		String projectName = (String) destinationPaths[0];
157
		String projectName = (String) destinationPaths[0];
162
		IPath newLocation = new Path((String) destinationPaths[1]);
158
		IPath newLocation = new Path((String) destinationPaths[1]);
163
164
		if (!validateMove(project, projectName)) {
165
			return;
166
		}
167
		
159
		
168
		boolean completed = performMove(project, projectName, newLocation);
160
		performMove(project, projectName, newLocation);
169
170
		if (!completed) {
171
			return; // not appropriate to show errors
172
		}
173
174
		// If errors occurred, open an Error dialog
175
		if (errorStatus != null) {
176
			ErrorDialog
177
					.openError(this.shell, PROBLEMS_TITLE, null, errorStatus);
178
			errorStatus = null;
179
		}
180
	}
181
	
182
	/**
183
	 * Validates the operation against the model providers.
184
	 *
185
	 * @param project the project to move
186
	 * @param newName the new name
187
	 * @return whether the operation should proceed
188
	 * @since 3.2
189
	 */
190
    private boolean validateMove(IProject project, String newName) {
191
    	if (project.getName().equals(newName)) {
192
    		// Only the location changed
193
    		return true;
194
    	}
195
    	IResourceChangeDescriptionFactory factory = ResourceChangeValidator.getValidator().createDeltaFactory();
196
    	factory.move(project, new Path(newName));
197
		return IDE.promptToConfirm(shell, IDEWorkbenchMessages.CopyProjectAction_confirm, NLS.bind(IDEWorkbenchMessages.CopyProjectAction_warning, project.getName()), factory.getDelta(), getModelProviderIds(), false /* no need to syncExec */);
198
	}
161
	}
199
}
162
}
(-)extensions/org/eclipse/ui/actions/CopyProjectAction.java (-12 / +4 lines)
Lines 23-29 Link Here
23
import org.eclipse.core.runtime.OperationCanceledException;
23
import org.eclipse.core.runtime.OperationCanceledException;
24
import org.eclipse.core.runtime.Path;
24
import org.eclipse.core.runtime.Path;
25
import org.eclipse.core.runtime.Platform;
25
import org.eclipse.core.runtime.Platform;
26
import org.eclipse.jface.dialogs.ErrorDialog;
27
import org.eclipse.jface.dialogs.MessageDialog;
26
import org.eclipse.jface.dialogs.MessageDialog;
28
import org.eclipse.jface.viewers.IStructuredSelection;
27
import org.eclipse.jface.viewers.IStructuredSelection;
29
import org.eclipse.osgi.util.NLS;
28
import org.eclipse.osgi.util.NLS;
Lines 135-140 Link Here
135
    /**
134
    /**
136
     * Return the title of the errors dialog.
135
     * Return the title of the errors dialog.
137
     * @return java.lang.String
136
     * @return java.lang.String
137
     * 
138
     * @deprecated As of 3.3, the undoable operation created by this action
139
     * handles error dialogs.
138
     */
140
     */
139
    protected String getErrorsTitle() {
141
    protected String getErrorsTitle() {
140
        return PROBLEMS_TITLE;
142
        return PROBLEMS_TITLE;
Lines 243-260 Link Here
243
			return;
245
			return;
244
		}
246
		}
245
247
246
        boolean completed = performCopy(project, newName, newLocation);
248
        performCopy(project, newName, newLocation);
247
248
        if (!completed) {
249
			return; // not appropriate to show errors
250
		}
251
249
252
        // If errors occurred, open an Error dialog
253
        if (errorStatus != null) {
254
            ErrorDialog.openError(this.shell, getErrorsTitle(), null,
255
                    errorStatus);
256
            errorStatus = null;
257
        }
258
    }
250
    }
259
251
260
	/**
252
	/**
(-)extensions/org/eclipse/ui/actions/WorkspaceAction.java (-363 / +422 lines)
Lines 28-33 Link Here
28
import org.eclipse.core.runtime.jobs.Job;
28
import org.eclipse.core.runtime.jobs.Job;
29
import org.eclipse.jface.dialogs.ErrorDialog;
29
import org.eclipse.jface.dialogs.ErrorDialog;
30
import org.eclipse.jface.dialogs.MessageDialog;
30
import org.eclipse.jface.dialogs.MessageDialog;
31
import org.eclipse.jface.operation.IRunnableWithProgress;
31
import org.eclipse.jface.viewers.IStructuredSelection;
32
import org.eclipse.jface.viewers.IStructuredSelection;
32
import org.eclipse.osgi.util.NLS;
33
import org.eclipse.osgi.util.NLS;
33
import org.eclipse.swt.widgets.Shell;
34
import org.eclipse.swt.widgets.Shell;
Lines 37-413 Link Here
37
import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;
38
import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;
38
39
39
/**
40
/**
40
 * The abstract superclass for actions which invoke commands 
41
 * The abstract superclass for actions which invoke commands implemented in
41
 * implemented in org.eclipse.core.* on a set of selected resources.
42
 * org.eclipse.core.* on a set of selected resources.
42
 * 
43
 * 
43
 * It iterates over all selected resources; errors are collected and
44
 * It iterates over all selected resources; errors are collected and displayed
44
 * displayed to the user via a problems dialog at the end of the operation.
45
 * to the user via a problems dialog at the end of the operation. User requests
45
 * User requests to cancel the operation are passed along to the core.
46
 * to cancel the operation are passed along to the core.
46
 * <p>
47
 * <p>
47
 * Subclasses must implement the following methods:
48
 * Subclasses must implement the following methods:
48
 * <ul>
49
 * <ul>
49
 *   <li><code>invokeOperation</code> - to perform the operation on one of the 
50
 * <li><code>invokeOperation</code> - to perform the operation on one of the
50
 *      selected resources</li>
51
 * selected resources</li>
51
 *   <li><code>getOperationMessage</code> - to furnish a title for the progress
52
 * <li><code>getOperationMessage</code> - to furnish a title for the progress
52
 *      dialog</li>
53
 * dialog</li>
53
 * </ul>
54
 * </ul>
54
 * </p>
55
 * </p>
55
 * <p>
56
 * <p>
56
 * Subclasses may override the following methods:
57
 * Subclasses may override the following methods:
57
 * <ul>
58
 * <ul>
58
 *   <li><code>shouldPerformResourcePruning</code> - reimplement to turn off</li>
59
 * <li><code>shouldPerformResourcePruning</code> - reimplement to turn off</li>
59
 *   <li><code>updateSelection</code> - extend to refine enablement criteria</li>
60
 * <li><code>updateSelection</code> - extend to refine enablement criteria</li>
60
 *   <li><code>getProblemsTitle</code> - reimplement to furnish a title for the
61
 * <li><code>getProblemsTitle</code> - reimplement to furnish a title for the
61
 *      problems dialog</li>
62
 * problems dialog</li>
62
 *   <li><code>getProblemsMessage</code> - reimplement to furnish a message for 
63
 * <li><code>getProblemsMessage</code> - reimplement to furnish a message for
63
 *      the problems dialog</li>
64
 * the problems dialog</li>
64
 *   <li><code>run</code> - extend to </li>
65
 * <li><code>run</code> - extend to </li>
65
 * </ul>
66
 * </ul>
66
 * </p>
67
 * </p>
67
 */
68
 */
68
public abstract class WorkspaceAction extends SelectionListenerAction {
69
public abstract class WorkspaceAction extends SelectionListenerAction {
69
    /**
70
	/**
70
     * The shell in which to show the progress and problems dialog.
71
	 * The shell in which to show the progress and problems dialog.
71
     */
72
	 */
72
    private final Shell shell;
73
	private final Shell shell;
73
74
74
    /**
75
	/**
75
     * Creates a new action with the given text.
76
	 * Creates a new action with the given text.
76
     *
77
	 * 
77
     * @param shell the shell (for the modal progress dialog and error messages)
78
	 * @param shell
78
     * @param text the string used as the text for the action, 
79
	 *            the shell (for the modal progress dialog and error messages)
79
     *   or <code>null</code> if there is no text
80
	 * @param text
80
     */
81
	 *            the string used as the text for the action, or
81
    protected WorkspaceAction(Shell shell, String text) {
82
	 *            <code>null</code> if there is no text
82
        super(text);
83
	 */
83
        if (shell == null) {
84
	protected WorkspaceAction(Shell shell, String text) {
84
            throw new IllegalArgumentException();
85
		super(text);
85
        }
86
		if (shell == null) {
86
        this.shell = shell;
87
			throw new IllegalArgumentException();
87
    }
88
		}
88
89
		this.shell = shell;
89
    /**
90
	}
90
     * Opens an error dialog to display the given message.
91
91
     * <p>
92
	/**
92
     * Note that this method must be called from UI thread.
93
	 * Opens an error dialog to display the given message.
93
     * </p>
94
	 * <p>
94
     *
95
	 * Note that this method must be called from UI thread.
95
     * @param message the message
96
	 * </p>
96
     */
97
	 * 
97
    void displayError(String message) {
98
	 * @param message
98
        if (message == null) {
99
	 *            the message
99
            message = IDEWorkbenchMessages.WorkbenchAction_internalError;
100
	 */
100
        }
101
	void displayError(String message) {
101
        MessageDialog.openError(shell, getProblemsTitle(), message);
102
		if (message == null) {
102
    }
103
			message = IDEWorkbenchMessages.WorkbenchAction_internalError;
103
104
		}
104
    /**
105
		MessageDialog.openError(shell, getProblemsTitle(), message);
105
     * Runs <code>invokeOperation</code> on each of the selected resources, reporting
106
	}
106
     * progress and fielding cancel requests from the given progress monitor.
107
107
     * <p>
108
	/**
108
     * Note that if an action is running in the background, the same action instance
109
	 * Runs <code>invokeOperation</code> on each of the selected resources,
109
     * can be executed multiple times concurrently.  This method must not access
110
	 * reporting progress and fielding cancel requests from the given progress
110
     * or modify any mutable state on action class.
111
	 * monitor.
111
     *
112
	 * <p>
112
     * @param monitor a progress monitor
113
	 * Note that if an action is running in the background, the same action
113
     * @return The result of the execution
114
	 * instance can be executed multiple times concurrently. This method must
114
     */
115
	 * not access or modify any mutable state on action class.
115
    final IStatus execute(List resources, IProgressMonitor monitor) {
116
	 * 
116
    	MultiStatus errors = null;
117
	 * @param monitor
117
        //1FTIMQN: ITPCORE:WIN - clients required to do too much iteration work
118
	 *            a progress monitor
118
        if (shouldPerformResourcePruning()) {
119
	 * @return The result of the execution
119
            resources = pruneResources(resources);
120
	 */
120
        }
121
	final IStatus execute(List resources, IProgressMonitor monitor) {
121
        // 1FV0B3Y: ITPUI:ALL - sub progress monitors granularity issues
122
		MultiStatus errors = null;
122
        monitor.beginTask("", resources.size() * 1000); //$NON-NLS-1$
123
		// 1FTIMQN: ITPCORE:WIN - clients required to do too much iteration work
123
        // Fix for bug 31768 - Don't provide a task name in beginTask
124
		if (shouldPerformResourcePruning()) {
124
        // as it will be appended to each subTask message. Need to
125
			resources = pruneResources(resources);
125
        // call setTaskName as its the only was to assure the task name is
126
		}
126
        // set in the monitor (see bug 31824)
127
		// 1FV0B3Y: ITPUI:ALL - sub progress monitors granularity issues
127
        monitor.setTaskName(getOperationMessage());
128
		monitor.beginTask("", resources.size() * 1000); //$NON-NLS-1$
128
        Iterator resourcesEnum = resources.iterator();
129
		// Fix for bug 31768 - Don't provide a task name in beginTask
129
        try {
130
		// as it will be appended to each subTask message. Need to
130
            while (resourcesEnum.hasNext()) {
131
		// call setTaskName as its the only was to assure the task name is
131
                IResource resource = (IResource) resourcesEnum.next();
132
		// set in the monitor (see bug 31824)
132
                try {
133
		monitor.setTaskName(getOperationMessage());
133
                    // 1FV0B3Y: ITPUI:ALL - sub progress monitors granularity issues
134
		Iterator resourcesEnum = resources.iterator();
134
                    invokeOperation(resource, new SubProgressMonitor(monitor,
135
		try {
135
                            1000));
136
			while (resourcesEnum.hasNext()) {
136
                } catch (CoreException e) {
137
				IResource resource = (IResource) resourcesEnum.next();
137
                    errors = recordError(errors, e);
138
				try {
138
                }
139
					// 1FV0B3Y: ITPUI:ALL - sub progress monitors granularity
139
                if (monitor.isCanceled()) {
140
					// issues
141
					invokeOperation(resource, new SubProgressMonitor(monitor,
142
							1000));
143
				} catch (CoreException e) {
144
					errors = recordError(errors, e);
145
				}
146
				if (monitor.isCanceled()) {
140
					throw new OperationCanceledException();
147
					throw new OperationCanceledException();
141
				}
148
				}
142
            }
143
            return errors == null ? Status.OK_STATUS : errors;
144
        } finally {
145
            monitor.done();
146
        }
147
    }
148
149
    /**
150
     * Returns the string to display for this action's operation.
151
     * <p>
152
     * Note that this hook method is invoked in a non-UI thread.
153
     * </p>
154
     * <p>
155
     * Subclasses must implement this method.
156
     * </p>
157
     *
158
     * @return the message
159
     * 
160
     * @since 3.1
161
     */
162
    protected abstract String getOperationMessage();
163
164
    /**
165
     * Returns the string to display for this action's problems dialog.
166
     * <p>
167
     * The <code>WorkspaceAction</code> implementation of this method returns a
168
     * vague message (localized counterpart of something like "The following 
169
     * problems occurred."). Subclasses may reimplement to provide something more
170
     * suited to the particular action.
171
     * </p>
172
     *
173
     * @return the problems message
174
     * 
175
     * @since 3.1
176
     */
177
    protected String getProblemsMessage() {
178
        return IDEWorkbenchMessages.WorkbenchAction_problemsMessage;
179
    }
180
181
    /**
182
     * Returns the title for this action's problems dialog.
183
     * <p>
184
     * The <code>WorkspaceAction</code> implementation of this method returns a
185
     * generic title (localized counterpart of "Problems"). Subclasses may 
186
     * reimplement to provide something more suited to the particular action.
187
     * </p>
188
     *
189
     * @return the problems dialog title
190
     * 
191
     * @since 3.1
192
     */
193
    protected String getProblemsTitle() {
194
        return IDEWorkbenchMessages.WorkspaceAction_problemsTitle;
195
    }
196
197
    /**
198
     * Returns the shell for this action. This shell is used for the modal progress
199
     * and error dialogs.
200
     *
201
     * @return the shell
202
     */
203
    Shell getShell() {
204
        return shell;
205
    }
206
207
    /**
208
     * Performs this action's operation on each of the selected resources, reporting
209
     * progress to, and fielding cancel requests from, the given progress monitor.
210
     * <p>
211
     * Note that this method is invoked in a non-UI thread.
212
     * </p>
213
     * <p>
214
     * Subclasses must implement this method.
215
     * </p>
216
     *
217
     * @param resource one of the selected resources
218
     * @param monitor a progress monitor
219
     * @exception CoreException if the operation fails
220
     * 
221
     * @since 3.1
222
     */
223
    protected abstract void invokeOperation(IResource resource, IProgressMonitor monitor)
224
            throws CoreException;
225
226
    /**
227
     * Returns whether the given resource is a descendent of any of the resources
228
     * in the given list.
229
     *
230
     * @param resources the list of resources (element type: <code>IResource</code>)
231
     * @param child the resource to check
232
     * @return <code>true</code> if <code>child</code> is a descendent of any of the
233
     *   elements of <code>resources</code>
234
     */
235
    boolean isDescendent(List resources, IResource child) {
236
        IResource parent = child.getParent();
237
        return parent != null
238
                && (resources.contains(parent) || isDescendent(resources,
239
                        parent));
240
    }
241
242
    /**
243
     * Performs pruning on the given list of resources, as described in 
244
     * <code>shouldPerformResourcePruning</code>.
245
     *
246
     * @param resourceCollection the list of resources (element type: 
247
     *    <code>IResource</code>)
248
     * @return the list of resources (element type: <code>IResource</code>)
249
     *		after pruning. 
250
     * @see #shouldPerformResourcePruning
251
     */
252
    List pruneResources(List resourceCollection) {
253
        List prunedList = new ArrayList(resourceCollection);
254
        Iterator elementsEnum = prunedList.iterator();
255
        while (elementsEnum.hasNext()) {
256
            IResource currentResource = (IResource) elementsEnum.next();
257
            if (isDescendent(prunedList, currentResource)) {
258
				elementsEnum.remove(); //Removes currentResource
259
			}
149
			}
260
        }
150
			return errors == null ? Status.OK_STATUS : errors;
261
        return prunedList;
151
		} finally {
262
    }
152
			monitor.done();
263
153
		}
264
    /**
154
	}
265
     * Records the core exception to be displayed to the user
155
266
     * once the action is finished.
156
	/**
267
     *
157
	 * Returns the string to display for this action's operation.
268
     * @param error a <code>CoreException</code>
158
	 * <p>
269
     */
159
	 * Note that this hook method is invoked in a non-UI thread.
270
    MultiStatus recordError(MultiStatus errors, CoreException error) {
160
	 * </p>
271
        if (errors == null) {
161
	 * <p>
162
	 * Subclasses must implement this method.
163
	 * </p>
164
	 * 
165
	 * @return the message
166
	 * 
167
	 * @since 3.1
168
	 */
169
	protected abstract String getOperationMessage();
170
171
	/**
172
	 * Returns the string to display for this action's problems dialog.
173
	 * <p>
174
	 * The <code>WorkspaceAction</code> implementation of this method returns
175
	 * a vague message (localized counterpart of something like "The following
176
	 * problems occurred."). Subclasses may reimplement to provide something
177
	 * more suited to the particular action.
178
	 * </p>
179
	 * 
180
	 * @return the problems message
181
	 * 
182
	 * @since 3.1
183
	 */
184
	protected String getProblemsMessage() {
185
		return IDEWorkbenchMessages.WorkbenchAction_problemsMessage;
186
	}
187
188
	/**
189
	 * Returns the title for this action's problems dialog.
190
	 * <p>
191
	 * The <code>WorkspaceAction</code> implementation of this method returns
192
	 * a generic title (localized counterpart of "Problems"). Subclasses may
193
	 * reimplement to provide something more suited to the particular action.
194
	 * </p>
195
	 * 
196
	 * @return the problems dialog title
197
	 * 
198
	 * @since 3.1
199
	 */
200
	protected String getProblemsTitle() {
201
		return IDEWorkbenchMessages.WorkspaceAction_problemsTitle;
202
	}
203
204
	/**
205
	 * Returns the shell for this action. This shell is used for the modal
206
	 * progress and error dialogs.
207
	 * 
208
	 * @return the shell
209
	 */
210
	Shell getShell() {
211
		return shell;
212
	}
213
214
	/**
215
	 * Performs this action's operation on each of the selected resources,
216
	 * reporting progress to, and fielding cancel requests from, the given
217
	 * progress monitor.
218
	 * <p>
219
	 * Note that this method is invoked in a non-UI thread.
220
	 * </p>
221
	 * <p>
222
	 * Subclasses must implement this method.
223
	 * <p>
224
	 * @deprecated Since 3.3, subclasses should instead implement the method
225
	 * {@link #createOperation(IStatus[])} and provide an empty implementation
226
	 * for this method.
227
	 * </p>
228
	 * 
229
	 * @param resource
230
	 *            one of the selected resources
231
	 * @param monitor
232
	 *            a progress monitor
233
	 * @exception CoreException
234
	 *                if the operation fails
235
	 * 
236
	 * @since 3.1
237
	 */
238
	protected abstract void invokeOperation(IResource resource,
239
			IProgressMonitor monitor) throws CoreException;
240
241
	/**
242
	 * Returns whether the given resource is a descendent of any of the
243
	 * resources in the given list.
244
	 * 
245
	 * @param resources
246
	 *            the list of resources (element type: <code>IResource</code>)
247
	 * @param child
248
	 *            the resource to check
249
	 * @return <code>true</code> if <code>child</code> is a descendent of
250
	 *         any of the elements of <code>resources</code>
251
	 */
252
	boolean isDescendent(List resources, IResource child) {
253
		IResource parent = child.getParent();
254
		return parent != null
255
				&& (resources.contains(parent) || isDescendent(resources,
256
						parent));
257
	}
258
259
	/**
260
	 * Performs pruning on the given list of resources, as described in
261
	 * <code>shouldPerformResourcePruning</code>.
262
	 * 
263
	 * @param resourceCollection
264
	 *            the list of resources (element type: <code>IResource</code>)
265
	 * @return the list of resources (element type: <code>IResource</code>)
266
	 *         after pruning.
267
	 * @see #shouldPerformResourcePruning
268
	 */
269
	List pruneResources(List resourceCollection) {
270
		List prunedList = new ArrayList(resourceCollection);
271
		Iterator elementsEnum = prunedList.iterator();
272
		while (elementsEnum.hasNext()) {
273
			IResource currentResource = (IResource) elementsEnum.next();
274
			if (isDescendent(prunedList, currentResource)) {
275
				elementsEnum.remove(); // Removes currentResource
276
			}
277
		}
278
		return prunedList;
279
	}
280
281
	/**
282
	 * Records the core exception to be displayed to the user once the action is
283
	 * finished.
284
	 * 
285
	 * @param error
286
	 *            a <code>CoreException</code>
287
	 */
288
	MultiStatus recordError(MultiStatus errors, CoreException error) {
289
		if (errors == null) {
272
			errors = new MultiStatus(IDEWorkbenchPlugin.IDE_WORKBENCH,
290
			errors = new MultiStatus(IDEWorkbenchPlugin.IDE_WORKBENCH,
273
                    IStatus.ERROR, getProblemsMessage(), null);
291
					IStatus.ERROR, getProblemsMessage(), null);
292
		}
293
		errors.merge(error.getStatus());
294
		return errors;
295
	}
296
297
	/**
298
	 * The <code>CoreWrapperAction</code> implementation of this
299
	 * <code>IAction</code> method uses a <code>ProgressMonitorDialog</code>
300
	 * to run the operation. The operation calls <code>execute</code> (which,
301
	 * in turn, calls <code>invokeOperation</code>). Afterwards, any
302
	 * <code>CoreException</code>s encountered while running the operation
303
	 * are reported to the user via a problems dialog.
304
	 * <p>
305
	 * Subclasses may extend this method.
306
	 * </p>
307
	 */
308
	public void run() {
309
		IStatus[] errorStatus = new IStatus[1];
310
		try {
311
			new ProgressMonitorJobsDialog(shell).run(true, true,
312
					createOperation(errorStatus));
313
		} catch (InterruptedException e) {
314
			return;
315
		} catch (InvocationTargetException e) {
316
			// we catch CoreException in execute(), but unexpected runtime
317
			// exceptions or errors may still occur
318
			String msg = NLS.bind(
319
					IDEWorkbenchMessages.WorkspaceAction_logTitle, getClass()
320
							.getName(), e.getTargetException());
321
			IDEWorkbenchPlugin.log(msg, StatusUtil.newStatus(IStatus.ERROR,
322
					msg, e.getTargetException()));
323
			displayError(e.getTargetException().getMessage());
324
		}
325
		// If errors occurred, open an Error dialog & build a multi status error
326
		// for it
327
		if (errorStatus[0] != null && !errorStatus[0].isOK()) {
328
			ErrorDialog.openError(shell, getProblemsTitle(), null, // no
329
					// special
330
					// message
331
					errorStatus[0]);
274
		}
332
		}
275
        errors.merge(error.getStatus());
333
	}
276
        return errors;
334
277
    }
335
	/**
278
336
	 * Returns whether this action should attempt to optimize the resources
279
    /**
337
	 * being operated on. This kind of pruning makes sense when the operation
280
     * The <code>CoreWrapperAction</code> implementation of this <code>IAction</code>
338
	 * has depth infinity semantics (when the operation is applied explicitly to
281
     * method uses a <code>ProgressMonitorDialog</code> to run the operation. The
339
	 * a resource then it is also applied implicitly to all the resource's
282
     * operation calls <code>execute</code> (which, in turn, calls 
340
	 * descendents).
283
     * <code>invokeOperation</code>). Afterwards, any <code>CoreException</code>s
341
	 * <p>
284
     * encountered while running the operation are reported to the user via a
342
	 * The <code>WorkspaceAction</code> implementation of this method returns
285
     * problems dialog.
343
	 * <code>true</code>. Subclasses should reimplement to return
286
     * <p>
344
	 * <code>false</code> if pruning is not required.
287
     * Subclasses may extend this method.
345
	 * </p>
288
     * </p>
346
	 * 
289
     */
347
	 * @return <code>true</code> if pruning should be performed, and
290
    public void run() {
348
	 *         <code>false</code> if pruning is not desired
291
    	final IStatus[] errorStatus = new IStatus[1];
349
	 * 
292
        try {
350
	 * @since 3.1
293
            WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
351
	 */
294
                public void execute(IProgressMonitor monitor) {
352
	protected boolean shouldPerformResourcePruning() {
295
                    errorStatus[0] = WorkspaceAction.this.execute(getActionResources(), monitor);
353
		return true;
296
                }
354
	}
297
            };
355
298
            new ProgressMonitorJobsDialog(shell).run(true, true, op);
356
	/**
299
        } catch (InterruptedException e) {
357
	 * The <code>WorkspaceAction</code> implementation of this
300
            return;
358
	 * <code>SelectionListenerAction</code> method ensures that this action is
301
        } catch (InvocationTargetException e) {
359
	 * disabled if any of the selected resources are inaccessible. Subclasses
302
            // we catch CoreException in execute(), but unexpected runtime exceptions or errors may still occur
360
	 * may extend to react to selection changes; however, if the super method
303
            String msg = NLS.bind(IDEWorkbenchMessages.WorkspaceAction_logTitle, getClass().getName(), e.getTargetException());
361
	 * returns <code>false</code>, the overriding method should also return
304
            IDEWorkbenchPlugin.log(msg, StatusUtil.newStatus(IStatus.ERROR,
362
	 * <code>false</code>.
305
                    msg, e.getTargetException()));
363
	 */
306
            displayError(e.getTargetException().getMessage());
364
	protected boolean updateSelection(IStructuredSelection selection) {
307
        }
365
		if (!super.updateSelection(selection) || selection.isEmpty()) {
308
        // If errors occurred, open an Error dialog & build a multi status error for it
366
			return false;
309
        if (errorStatus[0] != null && !errorStatus[0].isOK()) {
367
		}
310
            ErrorDialog.openError(shell, getProblemsTitle(), null, // no special message
368
		for (Iterator i = getSelectedResources().iterator(); i.hasNext();) {
311
                    errorStatus[0]);
369
			IResource r = (IResource) i.next();
312
        }
370
			if (!r.isAccessible()) {
313
    }
371
				return false;
314
372
			}
315
    /**
373
		}
316
     * Returns whether this action should attempt to optimize the resources being
374
		return true;
317
     * operated on. This kind of pruning makes sense when the operation has depth
375
	}
318
     * infinity semantics (when the operation is applied explicitly to a resource
376
319
     * then it is also applied implicitly to all the resource's descendents).
377
	/**
320
     * <p>
378
	 * Returns the elements that the action is to be performed on. By default
321
     * The <code>WorkspaceAction</code> implementation of this method returns
379
	 * return the selected resources.
322
     * <code>true</code>. Subclasses should reimplement to return <code>false</code>
380
	 * <p>
323
     * if pruning is not required.
381
	 * Subclasses may override this method.
324
     * </p>
382
	 * 
325
     *
383
	 * @return list of resource elements (element type: <code>IResource</code>)
326
     * @return <code>true</code> if pruning should be performed, 
384
	 */
327
     *   and <code>false</code> if pruning is not desired
385
	protected List getActionResources() {
328
     *   
386
		return getSelectedResources();
329
     * @since 3.1
387
	}
330
     */
388
331
    protected boolean shouldPerformResourcePruning() {
389
	/**
332
        return true;
390
	 * Run the action in the background rather than with the progress dialog.
333
    }
391
	 * 
334
392
	 * @param rule
335
    /**
393
	 *            The rule to apply to the background job or <code>null</code>
336
     * The <code>WorkspaceAction</code> implementation of this
394
	 *            if there isn't one.
337
     * <code>SelectionListenerAction</code> method ensures that this action is
395
	 */
338
     * disabled if any of the selected resources are inaccessible. Subclasses may
396
	public void runInBackground(ISchedulingRule rule) {
339
     * extend to react to selection changes; however, if the super method returns
397
		runInBackground(rule, (Object[]) null);
340
     * <code>false</code>, the overriding method should also return <code>false</code>.
398
	}
341
     */
399
342
    protected boolean updateSelection(IStructuredSelection selection) {
400
	/**
343
        if (!super.updateSelection(selection) || selection.isEmpty()) {
401
	 * Run the action in the background rather than with the progress dialog.
344
            return false;
402
	 * 
345
        }
403
	 * @param rule
346
        for (Iterator i = getSelectedResources().iterator(); i.hasNext();) {
404
	 *            The rule to apply to the background job or <code>null</code>
347
            IResource r = (IResource) i.next();
405
	 *            if there isn't one.
348
            if (!r.isAccessible()) {
406
	 * @param jobFamily
349
                return false;
407
	 *            a single family that the job should belong to or
350
            }
408
	 *            <code>null</code> if none.
351
        }
409
	 * 
352
        return true;
410
	 * @since 3.1
353
    }
411
	 */
354
412
	public void runInBackground(ISchedulingRule rule, Object jobFamily) {
355
    /**
413
		if (jobFamily == null) {
356
     * Returns the elements that the action is to be performed on.
414
			runInBackground(rule, (Object[]) null);
357
     * By default return the selected resources.
358
     * <p>
359
     * Subclasses may override this method.
360
     *
361
     * @return list of resource elements (element type: <code>IResource</code>)
362
     */
363
    protected List getActionResources() {
364
        return getSelectedResources();
365
    }
366
367
    /**
368
     * Run the action in the background rather than with the
369
     * progress dialog.
370
     * @param rule The rule to apply to the background job or
371
     * <code>null</code> if there isn't one.
372
     */
373
    public void runInBackground(ISchedulingRule rule) {
374
    	runInBackground(rule, (Object []) null);
375
    }
376
 
377
    /**
378
     * Run the action in the background rather than with the
379
     * progress dialog.
380
     * @param rule The rule to apply to the background job or
381
     * <code>null</code> if there isn't one.
382
     * @param jobFamily a single family that the job should 
383
     * belong to or <code>null</code> if none.
384
     * 
385
     * @since 3.1
386
     */
387
    public void runInBackground(ISchedulingRule rule, Object jobFamily) {
388
    	if (jobFamily == null) {
389
			runInBackground(rule, (Object []) null);
390
		} else {
415
		} else {
391
			runInBackground(rule, new Object[] {jobFamily});
416
			runInBackground(rule, new Object[] { jobFamily });
392
		}
417
		}
393
    }
418
	}
394
    
419
395
    /**
420
	/**
396
     * Run the action in the background rather than with the
421
	 * Run the action in the background rather than with the progress dialog.
397
     * progress dialog.
422
	 * 
398
     * @param rule The rule to apply to the background job or
423
	 * @param rule
399
     * <code>null</code> if there isn't one.
424
	 *            The rule to apply to the background job or <code>null</code>
400
     * @param jobFamilies the families the job should belong 
425
	 *            if there isn't one.
401
     * to or <code>null</code> if none.
426
	 * @param jobFamilies
402
     * 
427
	 *            the families the job should belong to or <code>null</code>
403
     * @since 3.1
428
	 *            if none.
404
     */
429
	 * 
405
    public void runInBackground(ISchedulingRule rule, final Object [] jobFamilies) {
430
	 * @since 3.1
406
    	//obtain a copy of the selected resources before the job is forked
431
	 */
407
    	final List resources = new ArrayList(getActionResources());
432
	public void runInBackground(ISchedulingRule rule, final Object[] jobFamilies) {
408
        Job job = new WorkspaceJob(removeMnemonics(getText())) {
433
		// obtain a copy of the selected resources before the job is forked
409
        	
434
		final List resources = new ArrayList(getActionResources());
410
        	/* (non-Javadoc)
435
		Job job = new WorkspaceJob(removeMnemonics(getText())) {
436
437
			/*
438
			 * (non-Javadoc)
439
			 * 
411
			 * @see org.eclipse.core.runtime.jobs.Job#belongsTo(java.lang.Object)
440
			 * @see org.eclipse.core.runtime.jobs.Job#belongsTo(java.lang.Object)
412
			 */
441
			 */
413
			public boolean belongsTo(Object family) {
442
			public boolean belongsTo(Object family) {
Lines 421-438 Link Here
421
				}
450
				}
422
				return false;
451
				return false;
423
			}
452
			}
424
			
453
425
            /* (non-Javadoc)
454
			/*
426
             * @see org.eclipse.core.resources.WorkspaceJob#runInWorkspace(org.eclipse.core.runtime.IProgressMonitor)
455
			 * (non-Javadoc)
427
             */
456
			 * 
428
            public IStatus runInWorkspace(IProgressMonitor monitor) {
457
			 * @see org.eclipse.core.resources.WorkspaceJob#runInWorkspace(org.eclipse.core.runtime.IProgressMonitor)
429
                return WorkspaceAction.this.execute(resources, monitor);
458
			 */
430
            }
459
			public IStatus runInWorkspace(IProgressMonitor monitor) {
431
        };
460
				return WorkspaceAction.this.execute(resources, monitor);
432
        if (rule != null) {
461
			}
462
		};
463
		if (rule != null) {
433
			job.setRule(rule);
464
			job.setRule(rule);
434
		}
465
		}
435
        job.setUser(true);
466
		job.setUser(true);
436
        job.schedule();
467
		job.schedule();
437
    }
468
	}
469
470
	/**
471
	 * Returns the operation to perform when this action runs. The returned
472
	 * operation must be an {@link IRunnableWithProgress} that will perform the
473
	 * action's work. The default implementation returns an operation that will
474
	 * iterate over the selected resources and call
475
	 * {@link #invokeOperation(IResource, IProgressMonitor)} for each resource.
476
	 * Subclasses must either implement
477
	 * {@link #invokeOperation(IResource, IProgressMonitor)} or override this
478
	 * method to provide a different operation. Subclasses typically override
479
	 * this method when an undoable operation is to be provided.
480
	 * 
481
	 * @param errorStatus
482
	 *            an array of error status objects to which the result of
483
	 *            running the operation should be added.
484
	 * 
485
	 * @return the operation to perform when this action runs.
486
	 * @since 3.3
487
	 */
488
	protected IRunnableWithProgress createOperation(final IStatus[] errorStatus) {
489
		return new WorkspaceModifyOperation() {
490
			public void execute(IProgressMonitor monitor) {
491
				errorStatus[0] = WorkspaceAction.this.execute(
492
						getActionResources(), monitor);
493
			}
494
		};
495
	}
496
438
}
497
}
(-)extensions/org/eclipse/ui/actions/RenameResourceAction.java (-138 / +44 lines)
Lines 10-40 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.ui.actions;
11
package org.eclipse.ui.actions;
12
12
13
import com.ibm.icu.text.MessageFormat;
14
import java.util.ArrayList;
13
import java.util.ArrayList;
15
import java.util.List;
14
import java.util.List;
16
15
17
import org.eclipse.core.resources.IFile;
16
import org.eclipse.core.commands.ExecutionException;
18
import org.eclipse.core.resources.IProject;
19
import org.eclipse.core.resources.IProjectDescription;
20
import org.eclipse.core.resources.IResource;
17
import org.eclipse.core.resources.IResource;
21
import org.eclipse.core.resources.IWorkspace;
18
import org.eclipse.core.resources.IWorkspace;
22
import org.eclipse.core.resources.IWorkspaceRoot;
23
import org.eclipse.core.resources.ResourceAttributes;
19
import org.eclipse.core.resources.ResourceAttributes;
24
import org.eclipse.core.resources.ResourcesPlugin;
20
import org.eclipse.core.runtime.IAdaptable;
25
import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
26
import org.eclipse.core.resources.mapping.ResourceChangeValidator;
27
import org.eclipse.core.runtime.CoreException;
28
import org.eclipse.core.runtime.IPath;
21
import org.eclipse.core.runtime.IPath;
29
import org.eclipse.core.runtime.IProgressMonitor;
22
import org.eclipse.core.runtime.IProgressMonitor;
30
import org.eclipse.core.runtime.IStatus;
23
import org.eclipse.core.runtime.IStatus;
31
import org.eclipse.core.runtime.SubProgressMonitor;
32
import org.eclipse.jface.dialogs.IInputValidator;
24
import org.eclipse.jface.dialogs.IInputValidator;
33
import org.eclipse.jface.dialogs.InputDialog;
25
import org.eclipse.jface.dialogs.InputDialog;
34
import org.eclipse.jface.dialogs.MessageDialog;
26
import org.eclipse.jface.dialogs.MessageDialog;
27
import org.eclipse.jface.operation.IRunnableWithProgress;
35
import org.eclipse.jface.viewers.IStructuredSelection;
28
import org.eclipse.jface.viewers.IStructuredSelection;
36
import org.eclipse.jface.window.Window;
29
import org.eclipse.jface.window.Window;
37
import org.eclipse.osgi.util.NLS;
38
import org.eclipse.swt.SWT;
30
import org.eclipse.swt.SWT;
39
import org.eclipse.swt.custom.TreeEditor;
31
import org.eclipse.swt.custom.TreeEditor;
40
import org.eclipse.swt.events.FocusAdapter;
32
import org.eclipse.swt.events.FocusAdapter;
Lines 49-59 Link Here
49
import org.eclipse.swt.widgets.Tree;
41
import org.eclipse.swt.widgets.Tree;
50
import org.eclipse.swt.widgets.TreeItem;
42
import org.eclipse.swt.widgets.TreeItem;
51
import org.eclipse.ui.PlatformUI;
43
import org.eclipse.ui.PlatformUI;
52
import org.eclipse.ui.ide.IDE;
44
import org.eclipse.ui.ide.undo.MoveResourcesOperation;
53
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
45
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
54
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
46
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
55
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
47
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
56
48
49
import com.ibm.icu.text.MessageFormat;
50
57
/**
51
/**
58
 * Standard action for renaming the selected resources.
52
 * Standard action for renaming the selected resources.
59
 * <p>
53
 * <p>
Lines 97-108 Link Here
97
91
98
    private static final String CHECK_RENAME_MESSAGE = IDEWorkbenchMessages.RenameResourceAction_readOnlyCheck;
92
    private static final String CHECK_RENAME_MESSAGE = IDEWorkbenchMessages.RenameResourceAction_readOnlyCheck;
99
93
100
    private static String RESOURCE_EXISTS_TITLE = IDEWorkbenchMessages.RenameResourceAction_resourceExists;
101
102
    private static String RESOURCE_EXISTS_MESSAGE = IDEWorkbenchMessages.RenameResourceAction_overwriteQuestion;
103
104
    private static String RENAMING_MESSAGE = IDEWorkbenchMessages.RenameResourceAction_progressMessage;
105
106
    /**
94
    /**
107
     * Creates a new action. Using this constructor directly will rename using a
95
     * Creates a new action. Using this constructor directly will rename using a
108
     * dialog rather than the inline editor of a ResourceNavigator.
96
     * dialog rather than the inline editor of a ResourceNavigator.
Lines 129-165 Link Here
129
        this.treeEditor = new TreeEditor(tree);
117
        this.treeEditor = new TreeEditor(tree);
130
    }
118
    }
131
119
132
    /**
120
   /**
133
     * Check if the user wishes to overwrite the supplied resource
134
     * @returns true if there is no collision or delete was successful
135
     * @param shell the shell to create the dialog in 
136
     * @param destination - the resource to be overwritten
137
     */
138
    private boolean checkOverwrite(final Shell shell,
139
            final IResource destination) {
140
141
        final boolean[] result = new boolean[1];
142
143
        //Run it inside of a runnable to make sure we get to parent off of the shell as we are not
144
        //in the UI thread.
145
146
        Runnable query = new Runnable() {
147
            public void run() {
148
                String pathName = destination.getFullPath().makeRelative()
149
                        .toString();
150
                result[0] = MessageDialog.openQuestion(shell,
151
                        RESOURCE_EXISTS_TITLE, MessageFormat.format(
152
                                RESOURCE_EXISTS_MESSAGE,
153
                                new Object[] { pathName }));
154
            }
155
156
        };
157
158
        shell.getDisplay().syncExec(query);
159
        return result[0];
160
    }
161
162
    /**
163
     * Check if the supplied resource is read only or null. If it is then ask the user if they want
121
     * Check if the supplied resource is read only or null. If it is then ask the user if they want
164
     * to continue. Return true if the resource is not read only or if the user has given
122
     * to continue. Return true if the resource is not read only or if the user has given
165
     * permission.
123
     * permission.
Lines 181-187 Link Here
181
        
139
        
182
        return true;
140
        return true;
183
    }
141
    }
184
185
    Composite createParent() {
142
    Composite createParent() {
186
        Tree tree = getTree();
143
        Tree tree = getTree();
187
        Composite result = new Composite(tree, SWT.NONE);
144
        Composite result = new Composite(tree, SWT.NONE);
Lines 341-407 Link Here
341
298
342
    /* (non-Javadoc)
299
    /* (non-Javadoc)
343
     * Method declared on WorkspaceAction.
300
     * Method declared on WorkspaceAction.
301
     * Since 3.3, this method is not used, but an implementation is still
302
     * provided for compatibility.  All work is now done in the operation
303
     * created in createOperation(IStatus[]).
344
     */
304
     */
345
    protected void invokeOperation(IResource resource, IProgressMonitor monitor)
305
    protected void invokeOperation(IResource resource, IProgressMonitor monitor) {
346
            throws CoreException {
347
348
    	if (!validateMove(resource, newPath)) {
349
    		return;
350
    	}
351
        monitor.beginTask(RENAMING_MESSAGE, 100);
352
        IWorkspaceRoot workspaceRoot = resource.getWorkspace().getRoot();
353
354
        IResource newResource = workspaceRoot.findMember(newPath);
355
        if (newResource != null) {
356
            if (checkOverwrite(getShell(), newResource)) {
357
                if (resource.getType() == IResource.FILE
358
                        && newResource.getType() == IResource.FILE) {
359
                    IFile file = (IFile) resource;
360
                    IFile newFile = (IFile) newResource;
361
                    if (validateEdit(file, newFile, getShell())) {
362
                        IProgressMonitor subMonitor = new SubProgressMonitor(
363
                                monitor, 50);
364
                        newFile.setContents(file.getContents(),
365
                                IResource.KEEP_HISTORY, subMonitor);
366
                        file.delete(IResource.KEEP_HISTORY, subMonitor);
367
                    }
368
                    monitor.worked(100);
369
                    return;
370
                } 
371
                newResource.delete(IResource.KEEP_HISTORY,
372
                        new SubProgressMonitor(monitor, 50));
373
            } else {
374
                monitor.worked(100);
375
                return;
376
            }
377
        }
378
        if (resource.getType() == IResource.PROJECT) {
379
            IProject project = (IProject) resource;
380
            IProjectDescription description = project.getDescription();
381
            description.setName(newPath.segment(0));
382
            project.move(description, IResource.FORCE | IResource.SHALLOW,
383
                    monitor);
384
        } else {
385
			resource.move(newPath, IResource.KEEP_HISTORY | IResource.SHALLOW,
386
                    new SubProgressMonitor(monitor, 50));
387
		}
388
    }
306
    }
389
307
390
	/**
308
	/**
391
	 * Validates the operation against the model providers.
392
	 *
393
	 * @param resource the resource to move
394
	 * @param path the new path
395
	 * @return whether the operation should proceed
396
	 * @since 3.2
397
	 */
398
    private boolean validateMove(IResource resource, IPath path) {
399
    	IResourceChangeDescriptionFactory factory = ResourceChangeValidator.getValidator().createDeltaFactory();
400
    	factory.move(resource, path);
401
		return IDE.promptToConfirm(getShell(), IDEWorkbenchMessages.RenameResourceAction_confirm, NLS.bind(IDEWorkbenchMessages.RenameResourceAction_warning, resource.getName()), factory.getDelta(), modelProviderIds, true /* syncExec */);
402
	}
403
404
	/**
405
     * Return the new name to be given to the target resource.
309
     * Return the new name to be given to the target resource.
406
     *
310
     *
407
     * @return java.lang.String
311
     * @return java.lang.String
Lines 475-481 Link Here
475
            if (currentResource == null || !currentResource.exists()) {
379
            if (currentResource == null || !currentResource.exists()) {
476
				return;
380
				return;
477
			}
381
			}
478
            //Do a quick read only and null check
382
			//Do a quick read only and null check
479
            if (!checkReadOnlyAndNull(currentResource)) {
383
            if (!checkReadOnlyAndNull(currentResource)) {
480
				return;
384
				return;
481
			}
385
			}
Lines 500-508 Link Here
500
        if (!checkReadOnlyAndNull(currentResource)) {
404
        if (!checkReadOnlyAndNull(currentResource)) {
501
			return;
405
			return;
502
		}
406
		}
503
504
        queryNewResourceNameInline(currentResource);
407
        queryNewResourceNameInline(currentResource);
505
506
    }
408
    }
507
    
409
    
508
    /**
410
    /**
Lines 612-644 Link Here
612
        textActionHandler = actionHandler;
514
        textActionHandler = actionHandler;
613
    }
515
    }
614
516
615
    /**
517
616
     * Validates the destination file if it is read-only and additionally 
617
     * the source file if both are read-only.
618
     * Returns true if both files could be made writeable.
619
     * 
620
     * @param source source file
621
     * @param destination destination file
622
     * @param shell ui context for the validation
623
     * @return boolean <code>true</code> both files could be made writeable.
624
     * 	<code>false</code> either one or both files were not made writeable  
625
     */
626
    boolean validateEdit(IFile source, IFile destination, Shell shell) {
627
        if (destination.isReadOnly()) {
628
            IWorkspace workspace = ResourcesPlugin.getWorkspace();
629
            IStatus status;
630
            if (source.isReadOnly()) {
631
				status = workspace.validateEdit(new IFile[] { source,
632
                        destination }, shell);
633
			} else {
634
				status = workspace.validateEdit(new IFile[] { destination },
635
                        shell);
636
			}
637
            return status.isOK();
638
        }
639
        return true;
640
    }
641
    
642
    /**
518
    /**
643
     * Returns the model provider ids that are known to the client
519
     * Returns the model provider ids that are known to the client
644
     * that instantiated this operation.
520
     * that instantiated this operation.
Lines 663-667 Link Here
663
	public void setModelProviderIds(String[] modelProviderIds) {
539
	public void setModelProviderIds(String[] modelProviderIds) {
664
		this.modelProviderIds = modelProviderIds;
540
		this.modelProviderIds = modelProviderIds;
665
	}
541
	}
666
542
	
543
	/*
544
	 * (non-Javadoc)
545
	 * @see org.eclipse.ui.actions.WorkspaceAction#createOperation(org.eclipse.core.runtime.IStatus[])
546
	 * 
547
	 * Overridden to create and execute an undoable operation that 
548
	 * performs the rename.
549
	 * @since 3.3
550
	 */
551
    protected IRunnableWithProgress createOperation(final IStatus [] errorStatus) {
552
    	return new IRunnableWithProgress() {
553
    		public void run(IProgressMonitor monitor) {
554
    			IResource [] resources = (IResource [])getSelectedResources().toArray(new IResource [getSelectedResources().size()]);
555
    			MoveResourcesOperation op = new MoveResourcesOperation(resources, newPath, getText());
556
    			op.setModelProviderIds(getModelProviderIds());
557
    			try {
558
    				errorStatus[0] = PlatformUI.getWorkbench().getOperationSupport()
559
    						.getOperationHistory().execute(op, monitor, new IAdaptable() {
560
    		   					public Object getAdapter(Class clazz) {
561
    		   						if (clazz == Shell.class) {
562
    		   							return getShell();
563
    		   						}
564
    		   						return null;
565
    		   					}
566
    		   				});
567
    			} catch (ExecutionException e) {
568
    				IDEWorkbenchPlugin.log(e.getMessage(), e);
569
    			}
570
    		}
571
    	};
572
    }
667
}
573
}
(-)src/org/eclipse/ui/ide/undo/MarkerDescription.java (-75 lines)
Removed Link Here
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.ide.undo;
13
14
import java.util.Map;
15
16
import org.eclipse.core.resources.IMarker;
17
import org.eclipse.core.resources.IResource;
18
import org.eclipse.core.runtime.CoreException;
19
20
/**
21
 * MarkerDescription is a lightweight description of a marker that can be used
22
 * to describe a marker to be created or updated.
23
 * 
24
 * This class is not intended to be instantiated or used by clients.
25
 * 
26
 * <strong>EXPERIMENTAL</strong> This class or interface has been added as part
27
 * of a work in progress. This API may change at any given time. Please do not
28
 * use this API without consulting with the Platform/UI team.
29
 * 
30
 * @since 3.3
31
 * 
32
 */
33
class MarkerDescription {
34
	String type;
35
36
	Map attributes;
37
38
	IResource resource;
39
40
	/*
41
	 * Create a marker description from the specified marker.
42
	 */
43
	MarkerDescription(IMarker marker) throws CoreException {
44
		this.type = marker.getType();
45
		this.attributes = marker.getAttributes();
46
		this.resource = marker.getResource();
47
48
	}
49
50
	/*
51
	 * Create a marker description from the specified marker type, attributes,
52
	 * and resource.
53
	 */
54
	MarkerDescription(String type, Map attributes, IResource resource) {
55
		this.type = type;
56
		this.attributes = attributes;
57
		this.resource = resource;
58
	}
59
60
	/*
61
	 * Create a marker from the marker description.
62
	 */
63
	protected IMarker createMarker() throws CoreException {
64
		IMarker marker = resource.createMarker(type);
65
		marker.setAttributes(attributes);
66
		return marker;
67
	}
68
69
	/*
70
	 * Update an existing marker using the attributes in the marker description.
71
	 */
72
	protected void updateMarker(IMarker marker) throws CoreException {
73
		marker.setAttributes(attributes);
74
	}
75
}
(-)src/org/eclipse/ui/ide/undo/AbstractMarkersOperation.java (-2 / +3 lines)
Lines 21-26 Link Here
21
import org.eclipse.core.runtime.IProgressMonitor;
21
import org.eclipse.core.runtime.IProgressMonitor;
22
import org.eclipse.core.runtime.IStatus;
22
import org.eclipse.core.runtime.IStatus;
23
import org.eclipse.core.runtime.Status;
23
import org.eclipse.core.runtime.Status;
24
import org.eclipse.ui.internal.ide.undo.MarkerDescription;
24
import org.eclipse.ui.internal.ide.undo.UndoMessages;
25
import org.eclipse.ui.internal.ide.undo.UndoMessages;
25
26
26
/**
27
/**
Lines 183-189 Link Here
183
			if (markerDescriptions != null) {
184
			if (markerDescriptions != null) {
184
				resources = new IResource[markerDescriptions.length];
185
				resources = new IResource[markerDescriptions.length];
185
				for (int i = 0; i < markerDescriptions.length; i++) {
186
				for (int i = 0; i < markerDescriptions.length; i++) {
186
					resources[i] = markerDescriptions[i].resource;
187
					resources[i] = markerDescriptions[i].getResource();
187
				}
188
				}
188
			}
189
			}
189
		} else {
190
		} else {
Lines 212-218 Link Here
212
			if (markerDescriptions != null) {
213
			if (markerDescriptions != null) {
213
				types = new String[markerDescriptions.length];
214
				types = new String[markerDescriptions.length];
214
				for (int i = 0; i < markerDescriptions.length; i++) {
215
				for (int i = 0; i < markerDescriptions.length; i++) {
215
					types[i] = markerDescriptions[i].type;
216
					types[i] = markerDescriptions[i].getType();
216
				}
217
				}
217
			}
218
			}
218
		} else {
219
		} else {
(-)src/org/eclipse/ui/ide/undo/AbstractWorkspaceOperation.java (-70 / +141 lines)
Lines 59-69 Link Here
59
59
60
	private static String ELLIPSIS = "..."; //$NON-NLS-1$
60
	private static String ELLIPSIS = "..."; //$NON-NLS-1$
61
61
62
	private static int EXECUTE = 1;
62
	protected static int EXECUTE = 1;
63
63
64
	private static int UNDO = 2;
64
	protected static int UNDO = 2;
65
65
66
	private static int REDO = 3;
66
	protected static int REDO = 3;
67
67
68
	protected IResource[] resources;
68
	protected IResource[] resources;
69
69
Lines 137-143 Link Here
137
	public boolean canExecute() {
137
	public boolean canExecute() {
138
		return isValid();
138
		return isValid();
139
	}
139
	}
140
	
140
141
	/*
141
	/*
142
	 * (non-Javadoc)
142
	 * (non-Javadoc)
143
	 * 
143
	 * 
Lines 173-197 Link Here
173
				public void run(IProgressMonitor monitor) throws CoreException {
173
				public void run(IProgressMonitor monitor) throws CoreException {
174
					doExecute(monitor, info);
174
					doExecute(monitor, info);
175
				}
175
				}
176
			}, null);
176
			}, null, IWorkspace.AVOID_UPDATE, null);
177
		} catch (final CoreException e) {
177
		} catch (final CoreException e) {
178
			final boolean[] propagateException = new boolean[1];
178
			getShell(info).getDisplay().syncExec(new Runnable() {
179
			getShell(info).getDisplay().syncExec(new Runnable() {
179
				public void run() {
180
				public void run() {
180
					ErrorDialog
181
					propagateException[0] = handleCoreException(
181
							.openError(
182
							e,
182
									getShell(info),
183
							getShell(info),
183
									NLS
184
							NLS
184
											.bind(
185
									.bind(
185
													UndoMessages.AbstractWorkspaceOperation_ExecuteErrorTitle,
186
											UndoMessages.AbstractWorkspaceOperation_ExecuteErrorTitle,
186
													getLabel()), null, e
187
											getLabel()));
187
											.getStatus());
188
188
189
				}
189
				}
190
190
191
			});
191
			});
192
			throw new ExecutionException(NLS.bind(
192
			if (propagateException[0]) {
193
					UndoMessages.AbstractWorkspaceOperation_ExecuteErrorTitle,
193
				throw new ExecutionException(
194
					getLabel()), e);
194
						NLS
195
								.bind(
196
										UndoMessages.AbstractWorkspaceOperation_ExecuteErrorTitle,
197
										getLabel()), e);
198
			}
195
		}
199
		}
196
		isValid = true;
200
		isValid = true;
197
		return Status.OK_STATUS;
201
		return Status.OK_STATUS;
Lines 215-237 Link Here
215
				}
219
				}
216
			}, null);
220
			}, null);
217
		} catch (final CoreException e) {
221
		} catch (final CoreException e) {
222
			final boolean[] propagateException = new boolean[1];
218
			getShell(info).getDisplay().syncExec(new Runnable() {
223
			getShell(info).getDisplay().syncExec(new Runnable() {
219
				public void run() {
224
				public void run() {
220
					ErrorDialog
225
					propagateException[0] = handleCoreException(
221
							.openError(
226
							e,
222
									getShell(info),
227
							getShell(info),
223
									NLS
228
							NLS
224
											.bind(
229
									.bind(
225
													UndoMessages.AbstractWorkspaceOperation_RedoErrorTitle,
230
											UndoMessages.AbstractWorkspaceOperation_RedoErrorTitle,
226
													getLabel()), null, e
231
											getLabel()));
227
											.getStatus());
228
229
				}
232
				}
230
233
231
			});
234
			});
232
			throw new ExecutionException(NLS.bind(
235
			if (propagateException[0]) {
233
					UndoMessages.AbstractWorkspaceOperation_RedoErrorTitle,
236
				throw new ExecutionException(NLS.bind(
234
					getLabel()), e);
237
						UndoMessages.AbstractWorkspaceOperation_RedoErrorTitle,
238
						getLabel()), e);
239
			}
235
		}
240
		}
236
		isValid = true;
241
		isValid = true;
237
		return Status.OK_STATUS;
242
		return Status.OK_STATUS;
Lines 255-277 Link Here
255
				}
260
				}
256
			}, null);
261
			}, null);
257
		} catch (final CoreException e) {
262
		} catch (final CoreException e) {
263
			final boolean[] propagateException = new boolean[1];
258
			getShell(info).getDisplay().syncExec(new Runnable() {
264
			getShell(info).getDisplay().syncExec(new Runnable() {
259
				public void run() {
265
				public void run() {
260
					ErrorDialog
266
					propagateException[0] = handleCoreException(
261
							.openError(
267
							e,
262
									getShell(info),
268
							getShell(info),
263
									NLS
269
							NLS
264
											.bind(
270
									.bind(
265
													UndoMessages.AbstractWorkspaceOperation_UndoErrorTitle,
271
											UndoMessages.AbstractWorkspaceOperation_UndoErrorTitle,
266
													getLabel()), null, e
272
											getLabel()));
267
											.getStatus());
268
273
269
				}
274
				}
270
275
271
			});
276
			});
272
			throw new ExecutionException(NLS.bind(
277
			if (propagateException[0]) {
273
					UndoMessages.AbstractWorkspaceOperation_UndoErrorTitle,
278
				throw new ExecutionException(NLS.bind(
274
					getLabel()), e);
279
						UndoMessages.AbstractWorkspaceOperation_UndoErrorTitle,
280
						getLabel()), e);
281
			}
275
		}
282
		}
276
		isValid = true;
283
		isValid = true;
277
		return Status.OK_STATUS;
284
		return Status.OK_STATUS;
Lines 306-313 Link Here
306
	/**
313
	/**
307
	 * Return whether the proposed operation is valid. The default
314
	 * Return whether the proposed operation is valid. The default
308
	 * implementation simply checks to see if the flag has been marked as
315
	 * implementation simply checks to see if the flag has been marked as
309
	 * invalid, relying on subclasses to mark the flag invalid when
316
	 * invalid, relying on subclasses to mark the flag invalid when appropriate.
310
	 * appropriate.
311
	 * 
317
	 * 
312
	 */
318
	 */
313
	protected boolean isValid() {
319
	protected boolean isValid() {
Lines 331-348 Link Here
331
	public Object[] getAffectedObjects() {
337
	public Object[] getAffectedObjects() {
332
		return resources;
338
		return resources;
333
	}
339
	}
334
	
340
335
	/*
341
	/*
336
	 * Return a status indicating the projected outcome of executing the receiver.
342
	 * Return a status indicating the projected outcome of executing the
337
	 * 
343
	 * receiver. This method is not called by the operation history, but instead
338
	 * This method computes the validity of execution by computing the resource
344
	 * is used by clients (such as implementers of {@link IOperationApprover2})
339
	 * delta that would be generated on execution, and checking whether any
345
	 * who wish to perform advanced validation of an operation before attempting
340
	 * registered model providers are affected by the operation. This method is
346
	 * to execute it.
341
	 * not called by the operation history, but instead is used by clients (such
347
	 * 
342
	 * as implementers of {@link IOperationApprover2}) who wish to perform
348
	 * If an ERROR status is returned, the operation will not proceed and the
343
	 * advanced validation of an operation before attempting to execute it. If the
349
	 * user notified if deemed necessary by the caller. The validity flag on the
344
	 * execute is not valid, then the validity flag on the operation should be
350
	 * operation should be marked as invalid. If an OK status is returned, the
345
	 * marked invalid.
351
	 * operation will proceed. The caller must interpret any other returned
352
	 * status severity, and may choose to prompt the user as to how to proceed.
353
	 * 
354
	 * If there are multiple conditions that result in an ambiguous status
355
	 * severity, it is best for the implementor of this method to consult the
356
	 * user as to how to proceed for each one, and return an OK or ERROR status
357
	 * that accurately reflects the user's wishes, or to return a multi-status
358
	 * that accurately describes all of the issues at hand, so that the caller
359
	 * may potentially consult the user.
360
	 * 
361
	 * This implementation computes the validity of execution by computing the
362
	 * resource delta that would be generated on execution, and checking whether
363
	 * any registered model providers are affected by the operation.
346
	 * 
364
	 * 
347
	 * @see org.eclipse.core.commands.operations.IAdvancedUndoableOperation#computeUndoableStatus(org.eclipse.core.runtime.IProgressMonitor)
365
	 * @see org.eclipse.core.commands.operations.IAdvancedUndoableOperation#computeUndoableStatus(org.eclipse.core.runtime.IProgressMonitor)
348
	 */
366
	 */
Lines 371-385 Link Here
371
389
372
	/*
390
	/*
373
	 * Return a status indicating the projected outcome of undoing the receiver.
391
	 * Return a status indicating the projected outcome of undoing the receiver.
374
	 * 
392
	 * This method is not called by the operation history, but instead is used
375
	 * This method computes the validity of an undo by computing the resource
393
	 * by clients (such as implementers of {@link IOperationApprover2}) who
376
	 * delta that would be generated on undo, and checking whether any
394
	 * wish to perform advanced validation of an operation before attempting to
377
	 * registered model providers are affected by the operation. This method is
395
	 * undo it.
378
	 * not called by the operation history, but instead is used by clients (such
396
	 * 
379
	 * as implementers of {@link IOperationApprover}) who wish to perform
397
	 * If an ERROR status is returned, the undo will not proceed and the user
380
	 * advanced validation of an operation before attempting to undo it. If the
398
	 * notified if deemed necessary by the caller. The validity flag on the
381
	 * undo is not valid, then the validity flag on the operation should be
399
	 * operation should be marked as invalid. If an OK status is returned, the
382
	 * marked invalid.
400
	 * undo will proceed. The caller must interpret any other returned status
401
	 * severity, and may choose to prompt the user as to how to proceed.
402
	 * 
403
	 * If there are multiple conditions that result in an ambiguous status
404
	 * severity, it is best for the implementor of this method to consult the
405
	 * user as to how to proceed for each one, and return an OK or ERROR status
406
	 * that accurately reflects the user's wishes, or to return a multi-status
407
	 * that accurately describes all of the issues at hand, so that the caller
408
	 * may potentially consult the user.
409
	 * 
410
	 * This implementation computes the validity of undo by computing the
411
	 * resource delta that would be generated on undo, and checking whether any
412
	 * registered model providers are affected by the operation. *
383
	 * 
413
	 * 
384
	 * @see org.eclipse.core.commands.operations.IAdvancedUndoableOperation#computeUndoableStatus(org.eclipse.core.runtime.IProgressMonitor)
414
	 * @see org.eclipse.core.commands.operations.IAdvancedUndoableOperation#computeUndoableStatus(org.eclipse.core.runtime.IProgressMonitor)
385
	 */
415
	 */
Lines 408-422 Link Here
408
438
409
	/*
439
	/*
410
	 * Return a status indicating the projected outcome of redoing the receiver.
440
	 * Return a status indicating the projected outcome of redoing the receiver.
411
	 * 
441
	 * This method is not called by the operation history, but instead is used
412
	 * This method computes the validity of a redo by computing the resource
442
	 * by clients (such as implementers of {@link IOperationApprover2}) who
413
	 * delta that would be generated on redo, and checking whether any
443
	 * wish to perform advanced validation of an operation before attempting to
414
	 * registered model providers are affected by the operation. This method is
444
	 * redo it.
415
	 * not called by the operation history, but instead is used by clients (such
445
	 * 
416
	 * as implementers of {@link IOperationApprover}) who wish to perform
446
	 * If an ERROR status is returned, the redo will not proceed and the user
417
	 * advanced validation of an operation before attempting to redo it. If the
447
	 * notified if deemed necessary by the caller. The validity flag on the
418
	 * redo is not valid, then the validity flag on the operation should be
448
	 * operation should be marked as invalid. If an OK status is returned, the
419
	 * marked invalid.
449
	 * redo will proceed. The caller must interpret any other returned status
450
	 * severity, and may choose to prompt the user as to how to proceed.
451
	 * 
452
	 * If there are multiple conditions that result in an ambiguous status
453
	 * severity, it is best for the implementor of this method to consult the
454
	 * user as to how to proceed for each one, and return an OK or ERROR status
455
	 * that accurately reflects the user's wishes, or to return a multi-status
456
	 * that accurately describes all of the issues at hand, so that the caller
457
	 * may potentially consult the user.
458
	 * 
459
	 * This implementation computes the validity of redo by computing the
460
	 * resource delta that would be generated on redo, and checking whether any
461
	 * registered model providers are affected by the operation.
420
	 * 
462
	 * 
421
	 * @see org.eclipse.core.commands.operations.IAdvancedUndoableOperation#computeUndoableStatus(org.eclipse.core.runtime.IProgressMonitor)
463
	 * @see org.eclipse.core.commands.operations.IAdvancedUndoableOperation#computeUndoableStatus(org.eclipse.core.runtime.IProgressMonitor)
422
	 */
464
	 */
Lines 512-515 Link Here
512
		}
554
		}
513
		return true;
555
		return true;
514
	}
556
	}
557
558
	/**
559
	 * Handle the core exception that occurred while trying to execute, undo, or
560
	 * redo the operation, returning a boolean to indicate whether this
561
	 * exception should cuase a {@link ExecutionException} to be thrown.
562
	 * 
563
	 * It is safe to access UI in this method. The default implementation is to
564
	 * show an error dialog, but callers may choose to swallow certain
565
	 * exceptions or show them differently.
566
	 * 
567
	 * If the only difference in handling the exception is to show a different
568
	 * error message, callers should override
569
	 * {@link #getErrorMessage(CoreException)} instead.
570
	 */
571
	protected boolean handleCoreException(CoreException e, Shell shell,
572
			String errorTitle) {
573
		ErrorDialog.openError(shell, errorTitle, getErrorMessage(e), e
574
				.getStatus());
575
		return true;
576
	}
577
578
	/**
579
	 * Return the specific error message to use when the specified core
580
	 * exception occurs, or <code>null</code> to indicate that the the
581
	 * exception's message should be used.
582
	 */
583
	protected String getErrorMessage(CoreException e) {
584
		return null;
585
	}
515
}
586
}
(-)src/org/eclipse/ui/ide/undo/CreateMarkersOperation.java (+1 lines)
Lines 19-24 Link Here
19
import org.eclipse.core.runtime.IProgressMonitor;
19
import org.eclipse.core.runtime.IProgressMonitor;
20
import org.eclipse.core.runtime.IStatus;
20
import org.eclipse.core.runtime.IStatus;
21
import org.eclipse.core.runtime.NullProgressMonitor;
21
import org.eclipse.core.runtime.NullProgressMonitor;
22
import org.eclipse.ui.internal.ide.undo.MarkerDescription;
22
23
23
/**
24
/**
24
 * A CreateMarkersOperation represents an undoable operation for creating one or
25
 * A CreateMarkersOperation represents an undoable operation for creating one or
(-)src/org/eclipse/ui/internal/wizards/newresource/ResourceMessages.java (-1 lines)
Lines 34-40 Link Here
34
	public static String NewProject_errorOpeningWindow;
34
	public static String NewProject_errorOpeningWindow;
35
	public static String NewProject_errorMessage;
35
	public static String NewProject_errorMessage;
36
	public static String NewProject_internalError;
36
	public static String NewProject_internalError;
37
	public static String NewProject_caseVariantExistsError;
38
	public static String NewProject_perspSwitchTitle;
37
	public static String NewProject_perspSwitchTitle;
39
	/**
38
	/**
40
	 * Combines a perspective name and text for introducing a perspective switch
39
	 * Combines a perspective name and text for introducing a perspective switch
(-)src/org/eclipse/ui/internal/wizards/newresource/messages.properties (-1 lines)
Lines 31-37 Link Here
31
NewProject_errorOpeningWindow = Problems Opening Window
31
NewProject_errorOpeningWindow = Problems Opening Window
32
NewProject_errorMessage = Creation Problems
32
NewProject_errorMessage = Creation Problems
33
NewProject_internalError = Internal error: {0}
33
NewProject_internalError = Internal error: {0}
34
NewProject_caseVariantExistsError = The underlying file system is case insensitive. There is an existing project which conflicts with ''{0}''.
35
NewProject_perspSwitchTitle = Open Associated Perspective?
34
NewProject_perspSwitchTitle = Open Associated Perspective?
36
NewProject_perspSwitchMessage = This kind of project is associated with the {0} perspective.  Do you want to open this perspective now?
35
NewProject_perspSwitchMessage = This kind of project is associated with the {0} perspective.  Do you want to open this perspective now?
37
NewProject_perspSwitchMessageWithDesc = This kind of project is associated with the {0} perspective.\n\n{1}\n\nDo you want to open this perspective now?
36
NewProject_perspSwitchMessageWithDesc = This kind of project is associated with the {0} perspective.\n\n{1}\n\nDo you want to open this perspective now?
(-)src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java (-8 / +3 lines)
Lines 160-166 Link Here
160
	public static String MoveProjectAction_text;
160
	public static String MoveProjectAction_text;
161
	public static String MoveProjectAction_toolTip;
161
	public static String MoveProjectAction_toolTip;
162
	public static String MoveProjectAction_moveTitle;
162
	public static String MoveProjectAction_moveTitle;
163
	public static String MoveProjectAction_progressMessage;
164
	public static String MoveProjectAction_dialogTitle;
163
	public static String MoveProjectAction_dialogTitle;
165
	public static String MoveProjectAction_internalError;
164
	public static String MoveProjectAction_internalError;
166
165
Lines 177-186 Link Here
177
	public static String RenameResourceAction_inputDialogMessage;
176
	public static String RenameResourceAction_inputDialogMessage;
178
	public static String RenameResourceAction_checkTitle;
177
	public static String RenameResourceAction_checkTitle;
179
	public static String RenameResourceAction_readOnlyCheck;
178
	public static String RenameResourceAction_readOnlyCheck;
180
	public static String RenameResourceAction_resourceExists;
181
	public static String RenameResourceAction_nameExists;
179
	public static String RenameResourceAction_nameExists;
182
	public static String RenameResourceAction_overwriteQuestion;
183
	public static String RenameResourceAction_progressMessage;
184
	public static String RenameResourceAction_problemTitle;
180
	public static String RenameResourceAction_problemTitle;
185
	public static String RenameResourceAction_progress;
181
	public static String RenameResourceAction_progress;
186
	public static String RenameResourceAction_nameMustBeDifferent;
182
	public static String RenameResourceAction_nameMustBeDifferent;
Lines 202-211 Link Here
202
	public static String DeleteResourceAction_confirmLinkedResource1;
198
	public static String DeleteResourceAction_confirmLinkedResource1;
203
	public static String DeleteResourceAction_confirmLinkedResourceN;
199
	public static String DeleteResourceAction_confirmLinkedResourceN;
204
	public static String DeleteResourceAction_readOnlyQuestion;
200
	public static String DeleteResourceAction_readOnlyQuestion;
205
	public static String DeleteResourceAction_messageTitle;
206
	public static String DeleteResourceAction_outOfSyncError;
207
	public static String DeleteResourceAction_outOfSyncQuestion;
208
	public static String DeleteResourceAction_deletionExceptionMessage;
209
	public static String DeleteResourceAction_jobName;
201
	public static String DeleteResourceAction_jobName;
210
	public static String DeleteResourceAction_checkJobName;
202
	public static String DeleteResourceAction_checkJobName;
211
203
Lines 366-371 Link Here
366
	public static String WizardNewFolderCreationPage_progress;
358
	public static String WizardNewFolderCreationPage_progress;
367
	public static String WizardNewFolderCreationPage_errorTitle;
359
	public static String WizardNewFolderCreationPage_errorTitle;
368
	public static String WizardNewFolderCreationPage_internalErrorTitle;
360
	public static String WizardNewFolderCreationPage_internalErrorTitle;
361
	public static String WizardNewFolderCreationPage_title;
369
	public static String WizardNewFolder_internalError;
362
	public static String WizardNewFolder_internalError;
370
363
371
	// --- New File ---
364
	// --- New File ---
Lines 375-380 Link Here
375
	public static String WizardNewFileCreationPage_file;
368
	public static String WizardNewFileCreationPage_file;
376
	public static String WizardNewFileCreationPage_internalErrorTitle;
369
	public static String WizardNewFileCreationPage_internalErrorTitle;
377
	public static String WizardNewFileCreationPage_internalErrorMessage;
370
	public static String WizardNewFileCreationPage_internalErrorMessage;
371
	public static String WizardNewFileCreationPage_title;
372
378
373
379
	// --- Linked Resource ---
374
	// --- Linked Resource ---
380
	public static String WizardNewLinkPage_linkFileButton;
375
	public static String WizardNewLinkPage_linkFileButton;
(-)src/org/eclipse/ui/internal/ide/messages.properties (-8 / +2 lines)
Lines 160-166 Link Here
160
MoveProjectAction_text = Mo&ve...
160
MoveProjectAction_text = Mo&ve...
161
MoveProjectAction_toolTip = Move Project
161
MoveProjectAction_toolTip = Move Project
162
MoveProjectAction_moveTitle = Move Project
162
MoveProjectAction_moveTitle = Move Project
163
MoveProjectAction_progressMessage = Moving
164
MoveProjectAction_dialogTitle = Move Problems
163
MoveProjectAction_dialogTitle = Move Problems
165
MoveProjectAction_internalError = Internal error: {0}
164
MoveProjectAction_internalError = Internal error: {0}
166
165
Lines 179-188 Link Here
179
RenameResourceAction_inputDialogMessage = Enter the new resource name:
178
RenameResourceAction_inputDialogMessage = Enter the new resource name:
180
RenameResourceAction_checkTitle = Check Rename
179
RenameResourceAction_checkTitle = Check Rename
181
RenameResourceAction_readOnlyCheck = ''{0}'' is read only. Do you still wish to rename it?
180
RenameResourceAction_readOnlyCheck = ''{0}'' is read only. Do you still wish to rename it?
182
RenameResourceAction_resourceExists = Resource Exists
183
RenameResourceAction_nameExists = A resource with that name already exists
181
RenameResourceAction_nameExists = A resource with that name already exists
184
RenameResourceAction_overwriteQuestion = ''{0}'' exists. Do you wish to overwrite?
185
RenameResourceAction_progressMessage = Renaming...
186
RenameResourceAction_problemTitle = Rename Problems
182
RenameResourceAction_problemTitle = Rename Problems
187
RenameResourceAction_progress = Renaming:
183
RenameResourceAction_progress = Renaming:
188
RenameResourceAction_nameMustBeDifferent = You must use a different name
184
RenameResourceAction_nameMustBeDifferent = You must use a different name
Lines 206-215 Link Here
206
DeleteResourceAction_confirmLinkedResource1 = Are you sure you want to delete linked resource ''{0}''?\nOnly the workspace link will be deleted. Link target will remain unchanged.
202
DeleteResourceAction_confirmLinkedResource1 = Are you sure you want to delete linked resource ''{0}''?\nOnly the workspace link will be deleted. Link target will remain unchanged.
207
DeleteResourceAction_confirmLinkedResourceN = Are you sure you want to delete these {0} resources?\n\nSelection contains linked resources.\nOnly the workspace links will be deleted. Link targets will remain unchanged.
203
DeleteResourceAction_confirmLinkedResourceN = Are you sure you want to delete these {0} resources?\n\nSelection contains linked resources.\nOnly the workspace links will be deleted. Link targets will remain unchanged.
208
DeleteResourceAction_readOnlyQuestion = ''{0}'' is read only. Do you still wish to delete it?
204
DeleteResourceAction_readOnlyQuestion = ''{0}'' is read only. Do you still wish to delete it?
209
DeleteResourceAction_messageTitle = Problems deleting
210
DeleteResourceAction_outOfSyncError = Resource is out of sync with the file system. Refresh and try again.
211
DeleteResourceAction_outOfSyncQuestion = Resource ''{0}'' is out of sync with the file system. Do you want to delete it anyway?
212
DeleteResourceAction_deletionExceptionMessage=Multiple problems occurred while deleting resources.
213
DeleteResourceAction_checkJobName = Checking resources
205
DeleteResourceAction_checkJobName = Checking resources
214
DeleteResourceAction_jobName = Deleting resources
206
DeleteResourceAction_jobName = Deleting resources
215
207
Lines 386-391 Link Here
386
WizardNewFolderCreationPage_progress = Creating
378
WizardNewFolderCreationPage_progress = Creating
387
WizardNewFolderCreationPage_errorTitle = Creation Problems
379
WizardNewFolderCreationPage_errorTitle = Creation Problems
388
WizardNewFolderCreationPage_internalErrorTitle = Creation problems
380
WizardNewFolderCreationPage_internalErrorTitle = Creation problems
381
WizardNewFolderCreationPage_title = New Folder
389
WizardNewFolder_internalError = Internal error: {0}
382
WizardNewFolder_internalError = Internal error: {0}
390
383
391
# --- New File ---
384
# --- New File ---
Lines 395-400 Link Here
395
WizardNewFileCreationPage_file = file
388
WizardNewFileCreationPage_file = file
396
WizardNewFileCreationPage_internalErrorTitle = Creation problems
389
WizardNewFileCreationPage_internalErrorTitle = Creation problems
397
WizardNewFileCreationPage_internalErrorMessage = Internal error: {0}
390
WizardNewFileCreationPage_internalErrorMessage = Internal error: {0}
391
WizardNewFileCreationPage_title = New File
398
392
399
# --- Linked Resource ---
393
# --- Linked Resource ---
400
WizardNewLinkPage_linkFileButton = &Link to file on the file system
394
WizardNewLinkPage_linkFileButton = &Link to file on the file system
(-)src/org/eclipse/ui/wizards/newresource/BasicNewProjectResourceWizard.java (-74 / +37 lines)
Lines 19-47 Link Here
19
import java.util.Set;
19
import java.util.Set;
20
import java.util.StringTokenizer;
20
import java.util.StringTokenizer;
21
21
22
import org.eclipse.core.commands.ExecutionException;
22
import org.eclipse.core.resources.IProject;
23
import org.eclipse.core.resources.IProject;
23
import org.eclipse.core.resources.IProjectDescription;
24
import org.eclipse.core.resources.IProjectDescription;
24
import org.eclipse.core.resources.IResource;
25
import org.eclipse.core.resources.IResourceStatus;
26
import org.eclipse.core.resources.IWorkspace;
25
import org.eclipse.core.resources.IWorkspace;
27
import org.eclipse.core.resources.ResourcesPlugin;
26
import org.eclipse.core.resources.ResourcesPlugin;
28
import org.eclipse.core.runtime.CoreException;
27
import org.eclipse.core.runtime.IAdaptable;
29
import org.eclipse.core.runtime.IConfigurationElement;
28
import org.eclipse.core.runtime.IConfigurationElement;
30
import org.eclipse.core.runtime.IExecutableExtension;
29
import org.eclipse.core.runtime.IExecutableExtension;
31
import org.eclipse.core.runtime.IProgressMonitor;
30
import org.eclipse.core.runtime.IProgressMonitor;
32
import org.eclipse.core.runtime.IStatus;
31
import org.eclipse.core.runtime.IStatus;
33
import org.eclipse.core.runtime.OperationCanceledException;
34
import org.eclipse.core.runtime.Status;
32
import org.eclipse.core.runtime.Status;
35
import org.eclipse.core.runtime.SubProgressMonitor;
36
import org.eclipse.jface.dialogs.ErrorDialog;
33
import org.eclipse.jface.dialogs.ErrorDialog;
37
import org.eclipse.jface.dialogs.IDialogConstants;
34
import org.eclipse.jface.dialogs.IDialogConstants;
38
import org.eclipse.jface.dialogs.IDialogSettings;
35
import org.eclipse.jface.dialogs.IDialogSettings;
39
import org.eclipse.jface.dialogs.MessageDialog;
36
import org.eclipse.jface.dialogs.MessageDialog;
40
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
37
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
38
import org.eclipse.jface.operation.IRunnableWithProgress;
41
import org.eclipse.jface.preference.IPreferenceStore;
39
import org.eclipse.jface.preference.IPreferenceStore;
42
import org.eclipse.jface.resource.ImageDescriptor;
40
import org.eclipse.jface.resource.ImageDescriptor;
43
import org.eclipse.jface.viewers.IStructuredSelection;
41
import org.eclipse.jface.viewers.IStructuredSelection;
44
import org.eclipse.osgi.util.NLS;
42
import org.eclipse.osgi.util.NLS;
43
import org.eclipse.swt.widgets.Shell;
45
import org.eclipse.ui.IPerspectiveDescriptor;
44
import org.eclipse.ui.IPerspectiveDescriptor;
46
import org.eclipse.ui.IPerspectiveRegistry;
45
import org.eclipse.ui.IPerspectiveRegistry;
47
import org.eclipse.ui.IPluginContribution;
46
import org.eclipse.ui.IPluginContribution;
Lines 51-57 Link Here
51
import org.eclipse.ui.IWorkbenchWindow;
50
import org.eclipse.ui.IWorkbenchWindow;
52
import org.eclipse.ui.PlatformUI;
51
import org.eclipse.ui.PlatformUI;
53
import org.eclipse.ui.WorkbenchException;
52
import org.eclipse.ui.WorkbenchException;
54
import org.eclipse.ui.actions.WorkspaceModifyOperation;
55
import org.eclipse.ui.activities.IActivityManager;
53
import org.eclipse.ui.activities.IActivityManager;
56
import org.eclipse.ui.activities.IIdentifier;
54
import org.eclipse.ui.activities.IIdentifier;
57
import org.eclipse.ui.activities.IWorkbenchActivitySupport;
55
import org.eclipse.ui.activities.IWorkbenchActivitySupport;
Lines 59-64 Link Here
59
import org.eclipse.ui.dialogs.WizardNewProjectCreationPage;
57
import org.eclipse.ui.dialogs.WizardNewProjectCreationPage;
60
import org.eclipse.ui.dialogs.WizardNewProjectReferencePage;
58
import org.eclipse.ui.dialogs.WizardNewProjectReferencePage;
61
import org.eclipse.ui.ide.IDE;
59
import org.eclipse.ui.ide.IDE;
60
import org.eclipse.ui.ide.undo.CreateProjectOperation;
62
import org.eclipse.ui.internal.IPreferenceConstants;
61
import org.eclipse.ui.internal.IPreferenceConstants;
63
import org.eclipse.ui.internal.WorkbenchPlugin;
62
import org.eclipse.ui.internal.WorkbenchPlugin;
64
import org.eclipse.ui.internal.ide.IDEInternalPreferences;
63
import org.eclipse.ui.internal.ide.IDEInternalPreferences;
Lines 196-207 Link Here
196
        }
195
        }
197
196
198
        // create the new project operation
197
        // create the new project operation
199
        WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
198
        IRunnableWithProgress op = new IRunnableWithProgress() {
200
            protected void execute(IProgressMonitor monitor)
199
    		public void run(IProgressMonitor monitor) {
201
                    throws CoreException {
200
    			CreateProjectOperation op = new CreateProjectOperation(
202
                createProject(description, newProjectHandle, monitor);
201
    					description, ResourceMessages.NewProject_windowTitle);
203
            }
202
    			try {
203
    				PlatformUI.getWorkbench().getOperationSupport()
204
    						.getOperationHistory().execute(op, monitor, new IAdaptable() {
205
    		   					public Object getAdapter(Class clazz) {
206
    		   						if (clazz == Shell.class) {
207
    		   							return getShell();
208
    		   						}
209
    		   						return null;
210
    		   					}
211
    		   				});
212
    			} catch (ExecutionException e) {
213
    				IDEWorkbenchPlugin.log(e.getMessage(), e);
214
    			}
215
    		}
216
    	
204
        };
217
        };
218
                
205
219
206
        // run the new project creation operation
220
        // run the new project creation operation
207
        try {
221
        try {
Lines 209-242 Link Here
209
        } catch (InterruptedException e) {
223
        } catch (InterruptedException e) {
210
            return null;
224
            return null;
211
        } catch (InvocationTargetException e) {
225
        } catch (InvocationTargetException e) {
212
            // ie.- one of the steps resulted in a core exception
226
            Throwable t = e.getTargetException();        
213
            Throwable t = e.getTargetException();
227
            // Exceptions are handled in the operation, but unexpected runtime
214
            if (t instanceof CoreException) {
228
            // exceptions and errors may still occur.
215
                if (((CoreException) t).getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) {
229
            IDEWorkbenchPlugin.getDefault().getLog().log(
216
                    MessageDialog
230
                    new Status(IStatus.ERROR,
217
                            .openError(
231
                            IDEWorkbenchPlugin.IDE_WORKBENCH, 0, t
218
                                    getShell(),
232
                                    .toString(), t));
219
                                    ResourceMessages.NewProject_errorMessage, 
233
            MessageDialog.openError(
220
                                    NLS.bind(ResourceMessages.NewProject_caseVariantExistsError, newProjectHandle.getName()) 
234
                    getShell(),
221
                            );
235
                    ResourceMessages.NewProject_errorMessage,
222
                } else {
236
                    NLS.bind(ResourceMessages.NewProject_internalError, t.getMessage()));
223
                    ErrorDialog.openError(getShell(), ResourceMessages.NewProject_errorMessage,
237
224
                            null, // no special message
225
                            ((CoreException) t).getStatus());
226
                }
227
            } else {
228
                // CoreExceptions are handled above, but unexpected runtime
229
                // exceptions and errors may still occur.
230
                IDEWorkbenchPlugin.getDefault().getLog().log(
231
                        new Status(IStatus.ERROR,
232
                                IDEWorkbenchPlugin.IDE_WORKBENCH, 0, t
233
                                        .toString(), t));
234
                MessageDialog
235
                        .openError(
236
                                getShell(),
237
                                ResourceMessages.NewProject_errorMessage,
238
                                NLS.bind(ResourceMessages.NewProject_internalError, t.getMessage()));
239
            }
240
            return null;
238
            return null;
241
        }
239
        }
242
240
Lines 246-286 Link Here
246
    }
244
    }
247
245
248
    /**
246
    /**
249
     * Creates a project resource given the project handle and description.
250
     * 
251
     * @param description
252
     *            the project description to create a project resource for
253
     * @param projectHandle
254
     *            the project handle to create a project resource for
255
     * @param monitor
256
     *            the progress monitor to show visual progress with
257
     * 
258
     * @exception CoreException
259
     *                if the operation fails
260
     * @exception OperationCanceledException
261
     *                if the operation is canceled
262
     */
263
    void createProject(IProjectDescription description, IProject projectHandle,
264
            IProgressMonitor monitor) throws CoreException,
265
            OperationCanceledException {
266
        try {
267
            monitor.beginTask("", 2000);//$NON-NLS-1$
268
269
            projectHandle.create(description, new SubProgressMonitor(monitor,
270
                    1000));
271
272
            if (monitor.isCanceled()) {
273
				throw new OperationCanceledException();
274
			}
275
276
            projectHandle.open(IResource.BACKGROUND_REFRESH, new SubProgressMonitor(monitor, 1000));
277
278
        } finally {
279
            monitor.done();
280
        }
281
    }
282
283
    /**
284
     * Returns the newly created project.
247
     * Returns the newly created project.
285
     * 
248
     * 
286
     * @return the created project, or <code>null</code> if project not
249
     * @return the created project, or <code>null</code> if project not
(-)src/org/eclipse/ui/internal/ide/undo/FileDescription.java (+137 lines)
Added Link Here
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 java.io.InputStream;
15
import java.io.StringBufferInputStream;
16
17
import org.eclipse.core.resources.IFile;
18
import org.eclipse.core.resources.IFileState;
19
import org.eclipse.core.resources.IResource;
20
import org.eclipse.core.resources.IWorkspaceRoot;
21
import org.eclipse.core.runtime.Assert;
22
import org.eclipse.core.runtime.CoreException;
23
import org.eclipse.core.runtime.IPath;
24
import org.eclipse.core.runtime.IProgressMonitor;
25
import org.eclipse.core.runtime.OperationCanceledException;
26
import org.eclipse.core.runtime.SubProgressMonitor;
27
28
/**
29
 * FileDescription is a lightweight description that describes a file to be
30
 * created.
31
 * 
32
 * This class is not intended to be instantiated or used by clients.
33
 * 
34
 * @since 3.3
35
 * 
36
 */
37
public class FileDescription extends ResourceDescription {
38
39
	String name;
40
41
	IPath location;
42
43
	private IFileState fileState;
44
45
	public FileDescription(IFile file) {
46
		super(file);
47
		this.name = file.getName();
48
		if (file.isLinked()) {
49
			location = file.getLocation();
50
		}
51
52
	}
53
54
	/*
55
	 * Create a file description from the specified file handle. The handle does
56
	 * not exist, so no information should be derived from it. If a location
57
	 * path is specified, this folder should represent a link to another
58
	 * location. The IFileState describes any state that should be used when the
59
	 * file resource is created.
60
	 */
61
	public FileDescription(IFile file, IPath linkLocation, IFileState fileState) {
62
		super(file);
63
		this.name = file.getName();
64
		this.location = linkLocation;
65
		this.fileState = fileState;
66
	}
67
68
	public void recordLastHistory(IResource resource,
69
			IProgressMonitor monitor) throws CoreException {
70
		Assert.isLegal(resource.getType() != IResource.FILE);
71
72
		if (location != null) {
73
			// file is linked, no need to record any history
74
			return;
75
		}
76
		IFileState[] states = ((IFile) resource).getHistory(monitor);
77
		if (states.length > 0) {
78
			this.fileState = states[0];
79
		}
80
	}
81
82
	/*
83
	 * (non-Javadoc)
84
	 * @see org.eclipse.ui.internal.ide.undo.ResourceDescription#createResourceHandle()
85
	 */
86
	public IResource createResourceHandle() {
87
		IWorkspaceRoot workspaceRoot = parent.getWorkspace().getRoot();
88
		IPath filePath = parent.getFullPath().append(name);
89
		return workspaceRoot.getFile(filePath);
90
	}
91
92
	protected void createExistentResourceFromHandle(IResource resource,
93
			IProgressMonitor monitor) throws CoreException {
94
95
		Assert.isLegal(resource instanceof IFile);
96
		IFile fileHandle = (IFile) resource;
97
		monitor.beginTask(UndoMessages.FileDescription_NewFileProgress, 200);
98
		try {
99
			if (monitor.isCanceled()) {
100
				throw new OperationCanceledException();
101
			}
102
			if (location != null) {
103
				fileHandle.createLink(location, IResource.ALLOW_MISSING_LOCAL,
104
						new SubProgressMonitor(monitor, 200));
105
			} else {
106
				InputStream contents = new StringBufferInputStream(
107
						UndoMessages.FileDescription_ContentsCouldNotBeRestored);
108
				String charset = null;
109
				// Retrieve the contents and charset from the file state.
110
				// Other file state attributes, such as timestamps, have
111
				// already been retrieved from the original IResource object
112
				// and are restored in the superclass.
113
				if (fileState != null && fileState.exists()) {
114
					contents = fileState.getContents();
115
					charset = fileState.getCharset();
116
				}
117
				fileHandle.create(contents, false, new SubProgressMonitor(
118
						monitor, 100));
119
				fileHandle.setCharset(charset, new SubProgressMonitor(monitor,
120
						100));
121
			}
122
			if (monitor.isCanceled()) {
123
				throw new OperationCanceledException();
124
			}
125
		} finally {
126
			monitor.done();
127
		}
128
	}
129
130
	public boolean isValid() {
131
		return super.isValid() && fileState != null && fileState.exists();
132
	}
133
134
	public String getName() {
135
		return name;
136
	}
137
}
(-)src/org/eclipse/ui/ide/undo/DeleteResourcesOperation.java (+117 lines)
Added Link Here
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.ide.undo;
13
14
import org.eclipse.core.resources.IResource;
15
import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
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.ui.internal.ide.undo.UndoMessages;
21
22
/**
23
 * A DeleteResourcesOperation represents an undoable operation for deleting one
24
 * or more resources in the workspace.
25
 * 
26
 * This class is intended to be instantiated and used by clients. It is not
27
 * intended to be subclassed by clients.
28
 * 
29
 * <strong>EXPERIMENTAL</strong> This class or interface has been added as part
30
 * of a work in progress. This API may change at any given time. Please do not
31
 * use this API without consulting with the Platform/UI team.
32
 * 
33
 * @since 3.3
34
 * 
35
 */
36
public class DeleteResourcesOperation extends AbstractResourcesOperation {
37
38
	private boolean deleteContent = false;
39
40
	/**
41
	 * Create a DeleteResourcesOperation
42
	 * 
43
	 * @param resources
44
	 *            the resources to be deleted
45
	 * @param label
46
	 *            the label of the operation
47
	 * @param deleteContent
48
	 *            whether or not we are deleting content for projects
49
	 */
50
	public DeleteResourcesOperation(IResource[] resources, String label,
51
			boolean deleteContent) {
52
		super(resources, label);
53
		this.deleteContent = deleteContent;
54
	}
55
56
	protected void doExecute(IProgressMonitor monitor, IAdaptable uiInfo)
57
			throws CoreException {
58
		delete(monitor, uiInfo, deleteContent);
59
	}
60
61
	protected void doUndo(IProgressMonitor monitor, IAdaptable uiInfo)
62
			throws CoreException {
63
		recreate(monitor, uiInfo);
64
	}
65
66
	protected boolean updateResourceChangeDescriptionFactory(
67
			IResourceChangeDescriptionFactory factory, int operation) {
68
		boolean modified = false;
69
		if (operation == UNDO) {
70
			for (int i = 0; i < resourceDescriptions.length; i++) {
71
				IResource resource = resourceDescriptions[i].createResourceHandle();
72
				factory.create(resource);
73
				modified = true;
74
			}
75
		} else {
76
			for (int i = 0; i < resources.length; i++) {
77
				IResource resource = resources[i];
78
				factory.delete(resource);
79
				modified = true;
80
			}
81
		}
82
		return modified;
83
	}
84
85
	public IStatus computeExecutionStatus(IProgressMonitor monitor) {
86
		IStatus status = super.computeExecutionStatus(monitor);
87
		if (status.isOK()) {
88
			status = computeDeleteStatus();
89
		}
90
		if (status.isOK()) {
91
			// If the resources to be deleted include projects whose content
92
			// is to be deleted, warn the user that the data will be lost.
93
			if (deleteContent) {
94
				status = getWarningStatus(
95
						UndoMessages.DeleteResourcesOperation_DeletingProjectContentWarning,
96
						0);
97
			}
98
		}
99
		return status;
100
	}
101
102
	public IStatus computeUndoableStatus(IProgressMonitor monitor) {
103
		IStatus status = super.computeUndoableStatus(monitor);
104
		if (status.isOK()) {
105
			status = computeCreateStatus(); 
106
		}
107
		return status;
108
	}
109
110
	public IStatus computeRedoableStatus(IProgressMonitor monitor) {
111
		IStatus status = super.computeRedoableStatus(monitor);
112
		if (status.isOK()) {
113
			status = computeDeleteStatus();
114
		}
115
		return status;
116
	}
117
}
(-)src/org/eclipse/ui/internal/ide/undo/MarkerDescription.java (+85 lines)
Added Link Here
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 java.util.Map;
15
16
import org.eclipse.core.resources.IMarker;
17
import org.eclipse.core.resources.IResource;
18
import org.eclipse.core.runtime.CoreException;
19
20
/**
21
 * MarkerDescription is a lightweight description of a marker that can be used
22
 * to describe a marker to be created or updated.
23
 * 
24
 * This class is not intended to be instantiated or used by clients.
25
 * 
26
 * @since 3.3
27
 * 
28
 */
29
public class MarkerDescription {
30
	String type;
31
32
	Map attributes;
33
34
	IResource resource;
35
36
	/*
37
	 * Create a marker description from the specified marker.
38
	 */
39
	public MarkerDescription(IMarker marker) throws CoreException {
40
		this.type = marker.getType();
41
		this.attributes = marker.getAttributes();
42
		this.resource = marker.getResource();
43
44
	}
45
46
	/*
47
	 * Create a marker description from the specified marker type, attributes,
48
	 * and resource.
49
	 */
50
	public MarkerDescription(String type, Map attributes, IResource resource) {
51
		this.type = type;
52
		this.attributes = attributes;
53
		this.resource = resource;
54
	}
55
56
	/*
57
	 * Create a marker from the marker description.
58
	 */
59
	public IMarker createMarker() throws CoreException {
60
		IMarker marker = resource.createMarker(type);
61
		marker.setAttributes(attributes);
62
		return marker;
63
	}
64
65
	/*
66
	 * Update an existing marker using the attributes in the marker description.
67
	 */
68
	public void updateMarker(IMarker marker) throws CoreException {
69
		marker.setAttributes(attributes);
70
	}
71
72
	/*
73
	 * Return the resource associated with this marker.
74
	 */
75
	public IResource getResource() {
76
		return resource;
77
	}
78
	
79
	/*
80
	 * Return the marker type associated with this marker.
81
	 */
82
	public String getType() {
83
		return type;
84
	}
85
}
(-)src/org/eclipse/ui/ide/undo/CreateFileOperation.java (+127 lines)
Added Link Here
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.ide.undo;
13
14
import java.io.InputStream;
15
import java.io.StringBufferInputStream;
16
17
import org.eclipse.core.resources.IFile;
18
import org.eclipse.core.resources.IFileState;
19
import org.eclipse.core.runtime.CoreException;
20
import org.eclipse.core.runtime.IPath;
21
import org.eclipse.ui.internal.ide.undo.ContainerDescription;
22
import org.eclipse.ui.internal.ide.undo.FileDescription;
23
import org.eclipse.ui.internal.ide.undo.ResourceDescription;
24
25
/**
26
 * A CreateFileOperation represents an undoable operation for creating a file in
27
 * the workspace. If a link location is specified, the folder is considered to
28
 * be linked to the file at the specified location. If a link location is not
29
 * specified, the file will be created in the location specified by the handle,
30
 * and the entire containment path of the file will be created if it does not
31
 * exist.
32
 * 
33
 * This class is intended to be instantiated and used by clients. It is not
34
 * intended to be subclassed by clients.
35
 * 
36
 * <strong>EXPERIMENTAL</strong> This class or interface has been added as part
37
 * of a work in progress. This API may change at any given time. Please do not
38
 * use this API without consulting with the Platform/UI team.
39
 * 
40
 * @since 3.3
41
 * 
42
 */
43
public class CreateFileOperation extends AbstractCreateResourcesOperation {
44
45
	/**
46
	 * Create a CreateFileOperation
47
	 * 
48
	 * @param fileHandle
49
	 *            the file to be created
50
	 * @param linkLocation
51
	 *            the location of the file if it is to be linked
52
	 * @param contents
53
	 *            the initial contents of the file, or null if there is to be no
54
	 *            contents
55
	 * @param label
56
	 *            the label of the operation
57
	 */
58
	public CreateFileOperation(IFile fileHandle, IPath linkLocation, InputStream contents, String label) {
59
		super(null, label);
60
		ResourceDescription resourceDescription;
61
		if (linkLocation == null) {
62
			if (fileHandle.getParent().exists()) {
63
				resourceDescription = new FileDescription(fileHandle, null, createFileState(fileHandle, contents));
64
			} else {
65
				// must first ensure descriptions for the parent folders are
66
				// created
67
				ContainerDescription containerDescription = ContainerDescription.fromContainer(fileHandle.getParent());
68
				containerDescription.getFirstLeafFolder().addMember(new FileDescription(fileHandle, null, createFileState(fileHandle, contents)));
69
				resourceDescription = containerDescription;
70
			}
71
		} else {
72
			// create a linked file description
73
			resourceDescription = new FileDescription(fileHandle, linkLocation, createFileState(fileHandle, contents));
74
		}
75
		resourceDescriptions = new ResourceDescription[ ] { resourceDescription };
76
77
	}
78
79
	/*
80
	 * Create a file state that represents the desired contents and attributes
81
	 * of the file to be created. Used to mimic file history when a resource is
82
	 * first created.
83
	 */
84
	private IFileState createFileState(final IFile file,
85
			final InputStream contents) {
86
		return new IFileState() {
87
			public InputStream getContents() {
88
				if (contents != null) {
89
					return contents;
90
				}
91
				return new StringBufferInputStream(""); //$NON-NLS-1$
92
			}
93
94
			public Object getAdapter(Class clazz) {
95
				return null;
96
			}
97
98
			public String getCharset() {
99
				try {
100
					return file.getCharset();
101
				} catch (CoreException e) {
102
					return null;
103
				}
104
			}
105
106
			public IPath getFullPath() {
107
				return file.getFullPath();
108
			}
109
110
			public String getName() {
111
				return file.getName();
112
			}
113
114
			public boolean exists() {
115
				return true;
116
			}
117
118
			public boolean isReadOnly() {
119
				return true;
120
			}
121
122
			public long getModificationTime() {
123
				return file.getLocalTimeStamp();
124
			}
125
		};
126
	}
127
}
(-)src/org/eclipse/ui/internal/ide/undo/FolderDescription.java (+89 lines)
Added Link Here
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.resources.IFolder;
15
import org.eclipse.core.resources.IResource;
16
import org.eclipse.core.resources.IWorkspaceRoot;
17
import org.eclipse.core.runtime.Assert;
18
import org.eclipse.core.runtime.CoreException;
19
import org.eclipse.core.runtime.IPath;
20
import org.eclipse.core.runtime.IProgressMonitor;
21
import org.eclipse.core.runtime.OperationCanceledException;
22
import org.eclipse.core.runtime.SubProgressMonitor;
23
24
/**
25
 * FolderDescription is a lightweight description that describes a folder to be
26
 * created.
27
 * 
28
 * This class is not intended to be instantiated or used by clients.
29
 * 
30
 * @since 3.3
31
 * 
32
 */
33
public class FolderDescription extends ContainerDescription {
34
35
	/*
36
	 * Create a FolderDescription from the specified folder handle. Typically
37
	 * used when the folder handle represents a resource that actually exists,
38
	 * although it will not fail if the resource is non-existent.
39
	 */
40
	public FolderDescription(IFolder folder)  {
41
		super(folder);
42
	}
43
	
44
	/*
45
	 * Create a FolderDescription from the specified folder handle.
46
	 * If the folder to be created should be linked to a different location,
47
	 * specify the location.
48
	 */
49
	public FolderDescription(IFolder folder, IPath linkLocation) {
50
		super(folder);
51
		this.name = folder.getName();
52
		this.location = linkLocation;
53
	}
54
55
	public IResource createResourceHandle() {
56
		IWorkspaceRoot workspaceRoot = getWorkspaceRoot();
57
		IPath folderPath = parent.getFullPath().append(name);
58
		return workspaceRoot.getFolder(folderPath);
59
	}
60
61
	protected void createExistentResourceFromHandle(IResource resource,
62
			IProgressMonitor monitor) throws CoreException {
63
64
		Assert.isLegal(resource instanceof IFolder);
65
		IFolder folderHandle = (IFolder) resource;
66
		try {
67
			monitor.beginTask(UndoMessages.FolderDescription_NewFolderProgress,
68
					200);
69
			if (monitor.isCanceled()) {
70
				throw new OperationCanceledException();
71
			}
72
			if (location != null) {
73
				folderHandle.createLink(location,
74
						IResource.ALLOW_MISSING_LOCAL, new SubProgressMonitor(
75
								monitor, 100));
76
			} else {
77
				folderHandle.create(false, true, new SubProgressMonitor(
78
						monitor, 100));
79
			}
80
			if (monitor.isCanceled()) {
81
				throw new OperationCanceledException();
82
			}
83
			createChildResources(folderHandle, monitor, 100);
84
85
		} finally {
86
			monitor.done();
87
		}
88
	}
89
}
(-)src/org/eclipse/ui/ide/undo/MoveResourcesOperation.java (+160 lines)
Added Link Here
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.ide.undo;
13
14
import org.eclipse.core.resources.IResource;
15
import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
16
import org.eclipse.core.runtime.CoreException;
17
import org.eclipse.core.runtime.IAdaptable;
18
import org.eclipse.core.runtime.IPath;
19
import org.eclipse.core.runtime.IProgressMonitor;
20
import org.eclipse.core.runtime.IStatus;
21
import org.eclipse.core.runtime.Status;
22
import org.eclipse.osgi.util.NLS;
23
import org.eclipse.ui.internal.ide.undo.UndoMessages;
24
25
/**
26
 * A MoveResourcesOperation represents an undoable operation for moving one or
27
 * more resources in the workspace.
28
 * 
29
 * This class is intended to be instantiated and used by clients. It is not
30
 * intended to be subclassed by clients.
31
 * 
32
 * <strong>EXPERIMENTAL</strong> This class or interface has been added as part
33
 * of a work in progress. This API may change at any given time. Please do not
34
 * use this API without consulting with the Platform/UI team.
35
 * 
36
 * @since 3.3
37
 * 
38
 */
39
public class MoveResourcesOperation extends AbstractResourcesOperation {
40
41
	IPath proposedPath;
42
43
	/**
44
	 * Create a MoveResourcesOperation
45
	 * 
46
	 * @param resources
47
	 *            the resources to be renamed
48
	 * @param newPath
49
	 *            the new path for the resource.
50
	 * @param label
51
	 *            the label of the operation
52
	 */
53
	public MoveResourcesOperation(IResource[] resources, IPath newPath,
54
			String label) {
55
		super(resources, label);
56
		proposedPath = newPath;
57
	}
58
59
	protected void doExecute(IProgressMonitor monitor, IAdaptable uiInfo)
60
			throws CoreException {
61
		swapLocation(monitor, uiInfo);
62
	}
63
64
	protected void doUndo(IProgressMonitor monitor, IAdaptable uiInfo)
65
			throws CoreException {
66
		swapLocation(monitor, uiInfo);
67
	}
68
69
	private IPath getProposedPath() {
70
		return proposedPath;
71
	}
72
73
	private void swapLocation(IProgressMonitor monitor, IAdaptable uiInfo)
74
			throws CoreException {
75
		IResource resource = getResource();
76
		IPath currentPath = resource.getFullPath();
77
		move(resource, getProposedPath(), monitor, uiInfo);
78
		proposedPath = currentPath;
79
	}
80
81
	protected boolean updateResourceChangeDescriptionFactory(
82
			IResourceChangeDescriptionFactory factory, int operation) {
83
		IResource resource = getResource();
84
		IPath newPath = getProposedPath();
85
		factory.move(resource, newPath);
86
		return true;
87
	}
88
89
	public IStatus computeExecutionStatus(IProgressMonitor monitor) {
90
		IStatus status = super.computeExecutionStatus(monitor);
91
		if (status.isOK()) {
92
			status = computeMoveStatus();
93
		}
94
		return status;
95
	}
96
97
	public IStatus computeUndoableStatus(IProgressMonitor monitor) {
98
		IStatus status = super.computeUndoableStatus(monitor);
99
		if (status.isOK()) {
100
			status = computeMoveStatus();
101
		}
102
		return status;
103
	}
104
105
	public IStatus computeRedoableStatus(IProgressMonitor monitor) {
106
		IStatus status = super.computeRedoableStatus(monitor);
107
		if (status.isOK()) {
108
			status = computeMoveStatus();
109
		}
110
		return status;
111
	}
112
113
	/*
114
	 * Compute the status for moving the resources.
115
	 * 
116
	 * Note this method may be called on initial moving of a resource, or when a
117
	 * move is undone or redone. Therefore, this method should check conditions
118
	 * that can change over the life of the operation, such as whether moving
119
	 * the file will cause an overwrite. One-time static checks should typically
120
	 * be done by the caller (such as the action that creates the operation) so
121
	 * that the user is not continually prompted or warned about conditions that
122
	 * were acceptable at the time of original execution.
123
	 * 
124
	 * TODO: Note that this currently only operates on the first resource.
125
	 */
126
	private IStatus computeMoveStatus() {
127
		IResource resource = getResource();
128
		// Does the resource still exist?
129
		if (!resource.exists()) {
130
			markInvalid();
131
			return getErrorStatus(UndoMessages.RenameResourceOperation_ResourceDoesNotExist);
132
		}
133
		// Are we really trying to rename it a different name?
134
		IPath proposedPath = getProposedPath();
135
		if (resource.getFullPath().equals(proposedPath)) {
136
			markInvalid();
137
			return getErrorStatus(UndoMessages.RenameResourceOperation_SameName);
138
		}
139
		// Is the proposed name valid?
140
		IStatus status = getWorkspace().validateName(
141
				proposedPath.lastSegment(), resource.getType());
142
		if (status.getSeverity() == IStatus.ERROR) {
143
			markInvalid();
144
		}
145
		if (!status.isOK()) {
146
			return status;
147
		}
148
149
		// Does the newly named resource already exist. If so, we could
150
		// overwrite
151
		IResource newResource = getWorkspace().getRoot().findMember(
152
				proposedPath);
153
		if (newResource != null) {
154
			return getWarningStatus(NLS.bind(
155
					UndoMessages.RenameResourceOperation_ResourceAlreadyExists,
156
					proposedPath.toString()), 0);
157
		}
158
		return Status.OK_STATUS;
159
	}
160
}
(-)src/org/eclipse/ui/ide/undo/AbstractCreateResourcesOperation.java (+105 lines)
Added Link Here
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.ide.undo;
13
14
import org.eclipse.core.resources.IResource;
15
import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
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.ui.internal.ide.undo.ResourceDescription;
21
22
/**
23
 * A CreateResourcesOperation represents an undoable operation for creating
24
 * resources in the workspace.
25
 * 
26
 * This class is not intended to be subclassed by clients.
27
 * 
28
 * <strong>EXPERIMENTAL</strong> This class or interface has been added as part
29
 * of a work in progress. This API may change at any given time. Please do not
30
 * use this API without consulting with the Platform/UI team.
31
 * 
32
 * @since 3.3
33
 * 
34
 */
35
public abstract class AbstractCreateResourcesOperation extends
36
		AbstractResourcesOperation {
37
38
	/**
39
	 * Create a create resources operation
40
	 * 
41
	 * @param resourceDescriptions
42
	 *            the resourceDescriptions describing resources to be created
43
	 * @param label
44
	 *            the label of the operation
45
	 */
46
	AbstractCreateResourcesOperation(ResourceDescription[] resourceDescriptions,
47
			String label) {
48
		super(resourceDescriptions, label);
49
	}
50
51
	protected void doExecute(IProgressMonitor monitor, IAdaptable uiInfo)
52
			throws CoreException {
53
		recreate(monitor, uiInfo);
54
	}
55
56
	protected void doUndo(IProgressMonitor monitor, IAdaptable uiInfo)
57
			throws CoreException {
58
		delete(monitor, uiInfo, false); // never delete content on undo of
59
										// create project
60
	}
61
62
	protected boolean updateResourceChangeDescriptionFactory(
63
			IResourceChangeDescriptionFactory factory, int operation) {
64
		boolean modified = false;
65
		if (operation == UNDO) {
66
			for (int i = 0; i < resources.length; i++) {
67
				IResource resource = resources[i];
68
				factory.delete(resource);
69
				modified = true;
70
			}
71
		} else {
72
			for (int i = 0; i < resourceDescriptions.length; i++) {
73
				IResource resource = resourceDescriptions[i]
74
						.createResourceHandle();
75
				factory.create(resource);
76
				modified = true;
77
			}
78
		}
79
		return modified;
80
	}
81
82
	public IStatus computeExecutionStatus(IProgressMonitor monitor) {
83
		IStatus status = super.computeExecutionStatus(monitor);
84
		if (status.isOK()) {
85
			status = computeCreateStatus();
86
		}
87
		return status;
88
	}
89
90
	public IStatus computeUndoableStatus(IProgressMonitor monitor) {
91
		IStatus status = super.computeUndoableStatus(monitor);
92
		if (status.isOK()) {
93
			status = computeDeleteStatus();
94
		}
95
		return status;
96
	}
97
98
	public IStatus computeRedoableStatus(IProgressMonitor monitor) {
99
		IStatus status = super.computeRedoableStatus(monitor);
100
		if (status.isOK()) {
101
			status = computeCreateStatus();
102
		}
103
		return status;
104
	}
105
}
(-)src/org/eclipse/ui/internal/ide/undo/ResourceDescription.java (+157 lines)
Added Link Here
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.resources.IContainer;
15
import org.eclipse.core.resources.IFile;
16
import org.eclipse.core.resources.IFolder;
17
import org.eclipse.core.resources.IMarker;
18
import org.eclipse.core.resources.IProject;
19
import org.eclipse.core.resources.IResource;
20
import org.eclipse.core.resources.IWorkspaceRoot;
21
import org.eclipse.core.resources.ResourceAttributes;
22
import org.eclipse.core.runtime.CoreException;
23
import org.eclipse.core.runtime.IProgressMonitor;
24
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
25
26
/**
27
 * ResourceDescription is a lightweight description that describes the common
28
 * attributes of a resource to be created.
29
 * 
30
 * This class is not intended to be instantiated or used by clients.
31
 * 
32
 * @since 3.3
33
 * 
34
 */
35
public abstract class ResourceDescription {
36
	IContainer parent;
37
38
	long modificationStamp = IResource.NULL_STAMP;
39
40
	long localTimeStamp = IResource.NULL_STAMP;
41
42
	ResourceAttributes resourceAttributes;
43
44
	MarkerDescription[] markerDescriptions;
45
46
	/**
47
	 * @param resource
48
	 * @return the resource description
49
	 */
50
	public static ResourceDescription fromResource(IResource resource) {
51
		if (resource.getType() == IResource.PROJECT) {
52
			return new ProjectDescription((IProject) resource);
53
		} else if (resource.getType() == IResource.FOLDER) {
54
			return new FolderDescription((IFolder) resource);
55
		} else if (resource.getType() == IResource.FILE) {
56
			return new FileDescription((IFile) resource);
57
		} else {
58
			throw new IllegalArgumentException();
59
		}
60
	}
61
	
62
	protected static IWorkspaceRoot getWorkspaceRoot() {
63
		return IDEWorkbenchPlugin.getPluginWorkspace().getRoot();
64
65
	}
66
67
68
	/*
69
	 * Create a resource description with no initial attributes
70
	 */
71
	protected ResourceDescription() {
72
		super();
73
	}
74
75
	/*
76
	 * Create a resource description from the specified resource.
77
	 */
78
	protected ResourceDescription(IResource resource) {
79
		super();
80
		parent = resource.getParent();
81
		if (resource.exists()) {
82
			modificationStamp = resource.getModificationStamp();
83
			localTimeStamp = resource.getLocalTimeStamp();
84
			resourceAttributes = resource.getResourceAttributes();
85
			try {
86
				IMarker[] markers = resource.findMarkers(null, true,
87
						IResource.DEPTH_INFINITE);
88
				markerDescriptions = new MarkerDescription[markers.length];
89
				for (int i = 0; i < markers.length; i++) {
90
					markerDescriptions[i] = new MarkerDescription(markers[i]);
91
				}
92
			} catch (CoreException e) {
93
				// Eat this exception because it only occurs when the resource
94
				// does not exist and we have already checked this.
95
				// We do not want to throw exceptions on the simple constructor,
96
				// as
97
				// no one has actually tried to do anything yet.
98
			}
99
		}
100
	}
101
102
	/*
103
	 * Create a resource handle that can be used to create a resource from this
104
	 * resource description. This handle can be used to create the actual
105
	 * resource, or to describe the creation to a resource delta factory.
106
	 */
107
	public abstract IResource createResourceHandle();
108
109
	/*
110
	 * Get the name of this resource.
111
	 */
112
	public abstract String getName();
113
114
	/*
115
	 * Create an existent resource from this resource description.
116
	 */
117
	public IResource createResource(IProgressMonitor monitor)
118
			throws CoreException {
119
		IResource resource = createResourceHandle();
120
		createExistentResourceFromHandle(resource, monitor);
121
		if (modificationStamp != IResource.NULL_STAMP) {
122
			resource.revertModificationStamp(modificationStamp);
123
		}
124
		if (localTimeStamp != IResource.NULL_STAMP) {
125
			resource.setLocalTimeStamp(localTimeStamp);
126
		}
127
		if (resourceAttributes != null) {
128
			resource.setResourceAttributes(resourceAttributes);
129
		}
130
		if (markerDescriptions != null) {
131
			for (int i = 0; i < markerDescriptions.length; i++) {
132
				markerDescriptions[i].resource = resource;
133
				markerDescriptions[i].createMarker();
134
			}
135
		}
136
		return resource;
137
	}
138
139
	/*
140
	 * Given a resource handle, create the actual existent resource represented
141
	 * by that handle.
142
	 */
143
	protected abstract void createExistentResourceFromHandle(
144
			IResource resource, IProgressMonitor monitor) throws CoreException;
145
146
	public boolean isValid() {
147
		return parent == null || parent.exists();
148
	}
149
150
	public void recordLastHistory(IResource resource, IProgressMonitor monitor)
151
			throws CoreException {
152
		// Nothing to do by default
153
		monitor.beginTask("", 100); //$NON-NLS-1$
154
		monitor.done();
155
	}
156
157
}
(-)src/org/eclipse/ui/ide/undo/AbstractResourcesOperation.java (+528 lines)
Added Link Here
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.ide.undo;
13
14
import java.util.ArrayList;
15
import java.util.List;
16
17
import org.eclipse.core.resources.IFile;
18
import org.eclipse.core.resources.IProject;
19
import org.eclipse.core.resources.IProjectDescription;
20
import org.eclipse.core.resources.IResource;
21
import org.eclipse.core.resources.IResourceStatus;
22
import org.eclipse.core.resources.IWorkspace;
23
import org.eclipse.core.resources.IWorkspaceRoot;
24
import org.eclipse.core.runtime.CoreException;
25
import org.eclipse.core.runtime.IAdaptable;
26
import org.eclipse.core.runtime.IPath;
27
import org.eclipse.core.runtime.IProgressMonitor;
28
import org.eclipse.core.runtime.IStatus;
29
import org.eclipse.core.runtime.MultiStatus;
30
import org.eclipse.core.runtime.OperationCanceledException;
31
import org.eclipse.core.runtime.Status;
32
import org.eclipse.core.runtime.SubProgressMonitor;
33
import org.eclipse.jface.dialogs.IDialogConstants;
34
import org.eclipse.jface.dialogs.MessageDialog;
35
import org.eclipse.osgi.util.NLS;
36
import org.eclipse.swt.widgets.Shell;
37
import org.eclipse.ui.PlatformUI;
38
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
39
import org.eclipse.ui.internal.ide.undo.FileDescription;
40
import org.eclipse.ui.internal.ide.undo.ResourceDescription;
41
import org.eclipse.ui.internal.ide.undo.UndoMessages;
42
43
/**
44
 * An AbstractResourcesOperation represents an undoable operation that
45
 * manipulates resources. It provides implementations for resource rename,
46
 * delete, creation, and modification. It also assigns the workspace undo
47
 * context as the undo context for operations of this type.
48
 * 
49
 * This class is not intended to be subclassed by clients.
50
 * 
51
 * <strong>EXPERIMENTAL</strong> This class or interface has been added as part
52
 * of a work in progress. This API may change at any given time. Please do not
53
 * use this API without consulting with the Platform/UI team.
54
 * 
55
 * @since 3.3
56
 * 
57
 */
58
public abstract class AbstractResourcesOperation extends
59
		AbstractWorkspaceOperation {
60
61
	/*
62
	 * Delete all of the specified resources, returning resource descriptions
63
	 * that can be used to restore them.
64
	 * 
65
	 * This method is static to ensure "statelessness." Calling instance methods
66
	 * are responsible for maintaining the current state of resources and
67
	 * resource descriptions for the operation.
68
	 */
69
	protected static ResourceDescription[] delete(
70
			IResource[] resourcesToDelete, IProgressMonitor monitor,
71
			IAdaptable uiInfo, boolean deleteContent) throws CoreException {
72
		final List exceptions = new ArrayList();
73
		ResourceDescription[] returnedResourceDescriptions = new ResourceDescription[resourcesToDelete.length];
74
		monitor
75
				.beginTask(
76
						UndoMessages.AbstractResourcesOperation_DeleteResourcesProgress,
77
						100 * resourcesToDelete.length);
78
		try {
79
			for (int i = 0; i < resourcesToDelete.length; ++i) {
80
				if (monitor.isCanceled()) {
81
					throw new OperationCanceledException();
82
				}
83
				try {
84
					IResource resource = resourcesToDelete[i];
85
					returnedResourceDescriptions[i] = delete(resource,
86
							new SubProgressMonitor(monitor, 100), uiInfo,
87
							false, deleteContent);
88
				} catch (CoreException e) {
89
					exceptions.add(e);
90
				}
91
			}
92
			IStatus result = createResult(exceptions);
93
			if (!result.isOK()) {
94
				throw new CoreException(result);
95
			}
96
		} finally {
97
			monitor.done();
98
		}
99
		return returnedResourceDescriptions;
100
	}
101
102
	/*
103
	 * Recreate the resources from the specified resource descriptions.
104
	 * 
105
	 * This method is static to ensure "statelessness." Calling instance methods
106
	 * are responsible for maintaining the current state of resources and
107
	 * resource descriptions for the operation.
108
	 */
109
	protected static IResource[] recreate(
110
			ResourceDescription[] resourcesToRecreate,
111
			IProgressMonitor monitor, IAdaptable uiInfo) throws CoreException {
112
		final List exceptions = new ArrayList();
113
		IResource[] resourcesToReturn = new IResource[resourcesToRecreate.length];
114
		monitor.beginTask("", resourcesToRecreate.length); //$NON-NLS-1$
115
		try {
116
			for (int i = 0; i < resourcesToRecreate.length; ++i) {
117
				if (monitor.isCanceled()) {
118
					throw new OperationCanceledException();
119
				}
120
				try {
121
					resourcesToReturn[i] = resourcesToRecreate[i]
122
							.createResource(new SubProgressMonitor(
123
									monitor,
124
									1,
125
									SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
126
				} catch (CoreException e) {
127
					exceptions.add(e);
128
				}
129
			}
130
			IStatus result = createResult(exceptions);
131
			if (!result.isOK()) {
132
				throw new CoreException(result);
133
			}
134
		} finally {
135
			monitor.done();
136
		}
137
		return resourcesToReturn;
138
	}
139
140
	/*
141
	 * Delete the specified resource, recording enough information about it that
142
	 * it can be restored later. Return a ResourceDescription capable of
143
	 * restoring the resource.
144
	 * 
145
	 * This method is static to ensure "statelessness." Calling instance methods
146
	 * are responsible for maintaining the current state of resources and
147
	 * resource descriptions for the operation.
148
	 */
149
	protected static ResourceDescription delete(IResource resourceToDelete,
150
			IProgressMonitor monitor, IAdaptable uiInfo,
151
			boolean forceOutOfSyncDelete, boolean deleteContent)
152
			throws CoreException {
153
		ResourceDescription resourceDescription = ResourceDescription
154
				.fromResource(resourceToDelete);
155
		try {
156
			if (resourceToDelete.getType() == IResource.PROJECT) {
157
				IProject project = (IProject) resourceToDelete;
158
				project.delete(deleteContent, forceOutOfSyncDelete, monitor);
159
			} else {
160
				// if it's not a project, just delete it
161
				monitor
162
						.beginTask(
163
								UndoMessages.AbstractResourcesOperation_DeleteResourcesProgress,
164
								100);
165
				resourceToDelete.delete(IResource.KEEP_HISTORY,
166
						new SubProgressMonitor(monitor, 50));
167
				resourceDescription.recordLastHistory(resourceToDelete,
168
						new SubProgressMonitor(monitor, 50));
169
				monitor.done();
170
			}
171
		} catch (CoreException exception) {
172
			if (resourceToDelete.getType() == IResource.FILE) {
173
				IStatus[] children = exception.getStatus().getChildren();
174
175
				if (children.length == 1
176
						&& children[0].getCode() == IResourceStatus.OUT_OF_SYNC_LOCAL) {
177
					if (forceOutOfSyncDelete) {
178
						resourceToDelete.delete(IResource.KEEP_HISTORY
179
								| IResource.FORCE, new SubProgressMonitor(
180
								monitor, 1));
181
						resourceDescription.recordLastHistory(resourceToDelete,
182
								new SubProgressMonitor(monitor, 1));
183
					} else {
184
						int result = queryDeleteOutOfSync(resourceToDelete,
185
								uiInfo);
186
187
						if (result == IDialogConstants.YES_ID) {
188
							resourceToDelete.delete(IResource.KEEP_HISTORY
189
									| IResource.FORCE, new SubProgressMonitor(
190
									monitor, 1));
191
							resourceDescription.recordLastHistory(
192
									resourceToDelete, new SubProgressMonitor(
193
											monitor, 1));
194
						} else if (result == IDialogConstants.YES_TO_ALL_ID) {
195
							forceOutOfSyncDelete = true;
196
							resourceToDelete.delete(IResource.KEEP_HISTORY
197
									| IResource.FORCE, new SubProgressMonitor(
198
									monitor, 1));
199
							resourceDescription.recordLastHistory(
200
									resourceToDelete, new SubProgressMonitor(
201
											monitor, 1));
202
203
						} else if (result == IDialogConstants.CANCEL_ID) {
204
							throw new OperationCanceledException();
205
						}
206
					}
207
				} else {
208
					throw exception;
209
				}
210
			} else {
211
				throw exception;
212
			}
213
		}
214
		return resourceDescription;
215
	}
216
217
	/**
218
	 * Ask the user whether the given resource should be deleted despite being
219
	 * out of sync with the file system.
220
	 * 
221
	 * @param resource
222
	 *            the out of sync resource
223
	 * @param uiInfo
224
	 *            an adaptable describing the ui info for this operation
225
	 * @return One of the IDialogConstants constants indicating which of the
226
	 *         Yes, Yes to All, No, Cancel options has been selected by the
227
	 *         user.
228
	 */
229
	private static int queryDeleteOutOfSync(IResource resource,
230
			IAdaptable uiInfo) {
231
		Shell shell = null;
232
		if (uiInfo != null) {
233
			shell = (Shell) uiInfo.getAdapter(Shell.class);
234
		}
235
		if (shell == null) {
236
			shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
237
					.getShell();
238
		}
239
		final MessageDialog dialog = new MessageDialog(
240
				shell,
241
				UndoMessages.AbstractResourcesOperation_deletionMessageTitle,
242
				null,
243
				NLS
244
						.bind(
245
								UndoMessages.AbstractResourcesOperation_outOfSyncQuestion,
246
								resource.getName()), MessageDialog.QUESTION,
247
				new String[] { IDialogConstants.YES_LABEL,
248
						IDialogConstants.YES_TO_ALL_LABEL,
249
						IDialogConstants.NO_LABEL,
250
						IDialogConstants.CANCEL_LABEL }, 0);
251
		shell.getDisplay().syncExec(new Runnable() {
252
			public void run() {
253
				dialog.open();
254
			}
255
		});
256
		int result = dialog.getReturnCode();
257
		if (result == 0) {
258
			return IDialogConstants.YES_ID;
259
		}
260
		if (result == 1) {
261
			return IDialogConstants.YES_TO_ALL_ID;
262
		}
263
		if (result == 2) {
264
			return IDialogConstants.NO_ID;
265
		}
266
		return IDialogConstants.CANCEL_ID;
267
	}
268
269
	/**
270
	 * Creates and returns a result status appropriate for the given list of
271
	 * exceptions.
272
	 * 
273
	 * @param exceptions
274
	 *            The list of exceptions that occurred (may be empty)
275
	 * @return The result status for the deletion
276
	 */
277
	private static IStatus createResult(List exceptions) {
278
		if (exceptions.isEmpty()) {
279
			return Status.OK_STATUS;
280
		}
281
		final int exceptionCount = exceptions.size();
282
		if (exceptionCount == 1) {
283
			return ((CoreException) exceptions.get(0)).getStatus();
284
		}
285
		CoreException[] children = (CoreException[]) exceptions
286
				.toArray(new CoreException[exceptionCount]);
287
		boolean outOfSync = false;
288
		for (int i = 0; i < children.length; i++) {
289
			if (children[i].getStatus().getCode() == IResourceStatus.OUT_OF_SYNC_LOCAL) {
290
				outOfSync = true;
291
				break;
292
			}
293
		}
294
		String title = outOfSync ? UndoMessages.AbstractResourcesOperation_outOfSyncError
295
				: UndoMessages.AbstractResourcesOperation_deletionExceptionMessage;
296
		final MultiStatus multi = new MultiStatus(
297
				IDEWorkbenchPlugin.IDE_WORKBENCH, 0, title, null);
298
		for (int i = 0; i < exceptionCount; i++) {
299
			CoreException exception = children[i];
300
			IStatus status = exception.getStatus();
301
			multi.add(new Status(status.getSeverity(), status.getPlugin(),
302
					status.getCode(), status.getMessage(), exception));
303
		}
304
		return multi;
305
	}
306
307
	ResourceDescription[] resourceDescriptions;
308
309
	/**
310
	 * Create an Abstract Resources Operation
311
	 * 
312
	 * @param resources
313
	 *            the resources to be modified
314
	 * @param label
315
	 *            the label of the operation
316
	 */
317
	AbstractResourcesOperation(IResource[] resources, String label) {
318
		super(label);
319
		this.addContext(WorkspaceUndoSupport.getWorkspaceUndoContext());
320
321
		setTargetResources(resources);
322
	}
323
324
	/**
325
	 * Create an Abstract Resources Operation
326
	 * 
327
	 * @param resourceDescriptions
328
	 *            the resourceDescriptions describing resources to be created
329
	 * @param label
330
	 *            the label of the operation
331
	 */
332
	AbstractResourcesOperation(ResourceDescription[] resourceDescriptions,
333
			String label) {
334
		super(label);
335
		this.addContext(WorkspaceUndoSupport.getWorkspaceUndoContext());
336
		this.resourceDescriptions = resourceDescriptions;
337
	}
338
339
	/*
340
	 * Return the first resource in the list of resources. Used by subclasses
341
	 * that only operate on a single resource.
342
	 */
343
	protected IResource getResource() {
344
		if (resources == null || resources.length == 0) {
345
			return null;
346
		}
347
		return resources[0];
348
	}
349
350
	protected void delete(IProgressMonitor monitor, IAdaptable uiInfo,
351
			boolean deleteContent) throws CoreException {
352
		resourceDescriptions = AbstractResourcesOperation.delete(resources,
353
				monitor, uiInfo, deleteContent);
354
		resources = new IResource[0];
355
	}
356
357
	protected void recreate(IProgressMonitor monitor, IAdaptable uiInfo)
358
			throws CoreException {
359
		resources = AbstractResourcesOperation.recreate(resourceDescriptions,
360
				monitor, uiInfo);
361
		resourceDescriptions = new ResourceDescription[0];
362
	}
363
364
	protected void move(IResource resource, IPath newPath,
365
			IProgressMonitor monitor, IAdaptable uiInfo) throws CoreException {
366
		monitor.beginTask(
367
				UndoMessages.AbstractResourcesOperation_MovingResources, 400);
368
		IWorkspaceRoot workspaceRoot = resource.getWorkspace().getRoot();
369
		// Are there any files to be restored after the move?
370
		ResourceDescription[] resourcesToRestore = null;
371
		if (resourceDescriptions != null) {
372
			resourcesToRestore = new ResourceDescription[resourceDescriptions.length];
373
			System.arraycopy(resourceDescriptions, 0, resourcesToRestore, 0,
374
					resourceDescriptions.length);
375
		}
376
		// Now we consider resourceDescriptions to describe the resources
377
		// to be restored later if this move is reversed.
378
		resourceDescriptions = null;
379
		// Some moves are optimized and recorded as complete in this flag
380
		boolean moved = false;
381
382
		IResource newResource = workspaceRoot.findMember(newPath);
383
		// If it already exists, we must overwrite it.
384
		if (newResource != null) {
385
			if (resource.getType() == IResource.FILE
386
					&& newResource.getType() == IResource.FILE) {
387
				// File on file overwrite is optimized as a reset of the
388
				// target file's contents
389
				IFile file = (IFile) resource;
390
				IFile existingFile = (IFile) newResource;
391
				if (validateEdit(file, existingFile, getShell(uiInfo))) {
392
					// Remember the state of the existing file so it can be
393
					// restored.
394
					FileDescription fileDescription = new FileDescription(
395
							existingFile);
396
					resourceDescriptions = new ResourceDescription[1];
397
					resourceDescriptions[0] = fileDescription;
398
					// Reset the contents to that of the file being moved
399
					existingFile.setContents(file.getContents(),
400
							IResource.KEEP_HISTORY, new SubProgressMonitor(
401
									monitor, 100));
402
					fileDescription.recordLastHistory(existingFile,
403
							new SubProgressMonitor(monitor, 100));
404
					// Now delete the file that was renamed
405
					file.delete(IResource.KEEP_HISTORY, new SubProgressMonitor(
406
							monitor, 100));
407
				}
408
				moved = true;
409
			} else {
410
				// Any other overwrite is simply a delete followed by the move
411
				resourceDescriptions = delete(new IResource[] { newResource },
412
						new SubProgressMonitor(monitor, 100), uiInfo, true);
413
			}
414
		} else {
415
			monitor.worked(100);
416
		}
417
		// Overwrites have been handled. If there is still a move to do, do so
418
		// now.
419
		if (!moved) {
420
			if (resource.getType() == IResource.PROJECT) {
421
				IProject project = (IProject) resource;
422
				IProjectDescription description = project.getDescription();
423
				description.setName(newPath.segment(0));
424
				project.move(description, IResource.FORCE | IResource.SHALLOW,
425
						new SubProgressMonitor(monitor, 200));
426
			} else {
427
				resource.move(newPath, IResource.KEEP_HISTORY
428
						| IResource.SHALLOW, new SubProgressMonitor(monitor,
429
						200));
430
431
			}
432
		}
433
434
		// Are there any previously overwritten resources to restore?
435
		if (resourcesToRestore != null) {
436
			for (int i = 0; i < resourcesToRestore.length; i++) {
437
				resourcesToRestore[i].createResource(new SubProgressMonitor(
438
						monitor, 100 / resourcesToRestore.length));
439
			}
440
		}
441
		setTargetResources(new IResource[] { getWorkspace().getRoot()
442
				.findMember(newPath) });
443
444
		monitor.done();
445
	}
446
447
	/**
448
	 * Validates the destination file if it is read-only and additionally the
449
	 * source file if both are read-only. Returns true if both files could be
450
	 * made writeable.
451
	 * 
452
	 * @param source
453
	 *            source file
454
	 * @param destination
455
	 *            destination file
456
	 * @param shell
457
	 *            ui context for the validation
458
	 * @return boolean <code>true</code> both files could be made writeable.
459
	 *         <code>false</code> either one or both files were not made
460
	 *         writeable
461
	 */
462
	protected boolean validateEdit(IFile source, IFile destination, Shell shell) {
463
		if (destination.isReadOnly()) {
464
			IWorkspace workspace = getWorkspace();
465
			IStatus status;
466
			if (source.isReadOnly()) {
467
				status = workspace.validateEdit(new IFile[] { source,
468
						destination }, shell);
469
			} else {
470
				status = workspace.validateEdit(new IFile[] { destination },
471
						shell);
472
			}
473
			return status.isOK();
474
		}
475
		return true;
476
	}
477
478
	/*
479
	 * Compute the status for creating resources from the descriptions.
480
	 * 
481
	 * Note this method may be called on initial creation of a resource, or when
482
	 * a create or delete operation is being undone or redone. Therefore, this
483
	 * method should check conditions that can change over the life of the
484
	 * operation, such as the existence of the information needed to carry out
485
	 * the operation. One-time static checks should typically be done by the
486
	 * caller (such as the action that creates the operation) so that the user
487
	 * is not continually prompted or warned about conditions that were
488
	 * acceptable at the time of original execution.
489
	 */
490
	protected IStatus computeCreateStatus() {
491
		if (resourceDescriptions == null || resourceDescriptions.length == 0) {
492
			markInvalid();
493
			return getErrorStatus(UndoMessages.AbstractResourcesOperation_NotEnoughInfo);
494
		}
495
		for (int i = 0; i < resourceDescriptions.length; i++) {
496
			if (!resourceDescriptions[i].isValid()) {
497
				markInvalid();
498
				return getErrorStatus(UndoMessages.AbstractResourcesOperation_InvalidRestoreInfo);
499
			}
500
		}
501
		return Status.OK_STATUS;
502
	}
503
504
	/*
505
	 * Compute the status for deleting resources.
506
	 * 
507
	 * Note this method may be called on initial deletion of a resource, or when
508
	 * a create or delete operation is being undone or redone. Therefore, this
509
	 * method should check conditions that can change over the life of the
510
	 * operation, such as the existence of the resources to be deleted. One-time
511
	 * static checks should typically be done by the caller (such as the action
512
	 * that creates the operation) so that the user is not continually prompted
513
	 * or warned about conditions that were acceptable at the time of original
514
	 * execution.
515
	 */
516
517
	protected IStatus computeDeleteStatus() {
518
		if (resources == null || resources.length == 0) {
519
			markInvalid();
520
			return getErrorStatus(UndoMessages.AbstractResourcesOperation_NotEnoughInfo);
521
		}
522
		if (!resourcesExist()) {
523
			markInvalid();
524
			return getErrorStatus(UndoMessages.AbstractResourcesOperation_ResourcesDoNotExist);
525
		}
526
		return Status.OK_STATUS;
527
	}
528
}
(-)src/org/eclipse/ui/ide/undo/CreateFolderOperation.java (+61 lines)
Added Link Here
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.ide.undo;
13
14
import org.eclipse.core.resources.IFolder;
15
import org.eclipse.core.runtime.IPath;
16
import org.eclipse.ui.internal.ide.undo.ContainerDescription;
17
import org.eclipse.ui.internal.ide.undo.FolderDescription;
18
import org.eclipse.ui.internal.ide.undo.ResourceDescription;
19
20
/**
21
 * A CreateFolderOperation represents an undoable operation for creating a
22
 * folder in the workspace. If a link location is specified, the folder is
23
 * considered to be linked to the specified location. If a link location is not
24
 * specified, the folder will be created in the location specified by the
25
 * handle, and the entire containment path of the folder will be created if it
26
 * does not exist.
27
 * 
28
 * This class is intended to be instantiated and used by clients. It is not
29
 * intended to be subclassed by clients.
30
 * 
31
 * <strong>EXPERIMENTAL</strong> This class or interface has been added as part
32
 * of a work in progress. This API may change at any given time. Please do not
33
 * use this API without consulting with the Platform/UI team.
34
 * 
35
 * @since 3.3
36
 * 
37
 */
38
public class CreateFolderOperation extends AbstractCreateResourcesOperation {
39
40
	/**
41
	 * Create a CreateFolderOperation
42
	 * 
43
	 * @param folderHandle
44
	 *            the folder to be created
45
	 * @param linkLocation
46
	 *            the location of the folder if it is to be linked
47
	 * @param label
48
	 *            the label of the operation
49
	 */
50
	public CreateFolderOperation(IFolder folderHandle, IPath linkLocation, String label) {
51
		super(null, label);
52
		ContainerDescription containerDescription;
53
		if (linkLocation == null) {
54
			containerDescription = ContainerDescription.fromContainer(folderHandle);
55
		} else {
56
			// create a linked folder description
57
			containerDescription = new FolderDescription(folderHandle, linkLocation);
58
		}
59
		resourceDescriptions = new ResourceDescription[ ] {containerDescription};
60
	}
61
}
(-)src/org/eclipse/ui/internal/ide/undo/ContainerDescription.java (+208 lines)
Added Link Here
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.resources.IContainer;
15
import org.eclipse.core.resources.IFile;
16
import org.eclipse.core.resources.IFolder;
17
import org.eclipse.core.resources.IResource;
18
import org.eclipse.core.resources.IWorkspaceRoot;
19
import org.eclipse.core.runtime.CoreException;
20
import org.eclipse.core.runtime.IPath;
21
import org.eclipse.core.runtime.IProgressMonitor;
22
import org.eclipse.core.runtime.Path;
23
import org.eclipse.core.runtime.SubProgressMonitor;
24
25
/**
26
 * ContainerDescription is a lightweight description that describes a container
27
 * to be created.
28
 * 
29
 * This class is not intended to be instantiated or used by clients.
30
 * 
31
 * @since 3.3
32
 * 
33
 */
34
public abstract class ContainerDescription extends ResourceDescription {
35
36
	String name;
37
38
	IPath location;
39
40
	private ResourceDescription[] members;
41
42
	/*
43
	 * Create a container description from the specified container handle that
44
	 * can be used to create the container. The returned ContainerDescription
45
	 * should represent any non-existing parents in addition to the specified
46
	 * container.
47
	 */
48
49
	public static ContainerDescription fromContainer(IContainer container) {
50
		IPath fullPath = container.getFullPath();
51
		ContainerDescription firstCreatedParent = null;
52
		ContainerDescription currentContainerDescription = null;
53
54
        // Does the container exist already? If so, then the parent exists and
55
		// we use the normal creation constructor.
56
        IWorkspaceRoot root = getWorkspaceRoot();
57
        IContainer currentContainer = (IContainer) root.findMember(fullPath);
58
        if (container != null) {
59
			return (ContainerDescription)ResourceDescription.fromResource(container);
60
		}
61
62
        // Create container descriptions for any uncreated parents in the given
63
        // path.
64
        currentContainer = root;
65
        for (int i = 0; i < fullPath.segmentCount(); i++) {
66
            String currentSegment = fullPath.segment(i);
67
            IResource resource = currentContainer.findMember(currentSegment);
68
            if (resource != null) {
69
            	// parent already exists, no need to create a description for it
70
            	currentContainer = (IContainer)resource;
71
            } else {
72
                if (i == 0) {
73
                	// parent does not exist and it is a project
74
                    firstCreatedParent = new ProjectDescription(root.getProject(currentSegment));
75
                    currentContainerDescription = firstCreatedParent;
76
                } else {
77
                	IFolder folderHandle = currentContainer.getFolder(new Path(currentSegment));
78
                    ContainerDescription currentFolder = new FolderDescription(folderHandle);
79
                    currentContainer = folderHandle;
80
                    if (currentContainerDescription != null) {
81
                    	currentContainerDescription.addMember(currentFolder);
82
                    }
83
                    currentContainerDescription = currentFolder;
84
                    if (firstCreatedParent == null) {
85
                    	firstCreatedParent = currentFolder;
86
                    }
87
                }
88
            }
89
        }
90
        return firstCreatedParent;
91
	}
92
93
	/*
94
	 * Create a ContainerDescription with no state.
95
	 */
96
	public ContainerDescription() {
97
98
	}
99
100
	/*
101
	 * Create a ContainerDescription from the specified container handle.
102
	 * Typically used when the container handle represents a resource that
103
	 * actually exists, although it will not fail if the resource is
104
	 * non-existent.
105
	 */
106
	public ContainerDescription(IContainer container) {
107
		super(container);
108
		this.name = container.getName();
109
		if (container.isLinked()) {
110
			this.location = container.getLocation();
111
		}
112
		try {
113
			if (container.exists()) {
114
				IResource[] resourceMembers = container.members();
115
				members = new ResourceDescription[resourceMembers.length];
116
				for (int i = 0; i < resourceMembers.length; i++) {
117
					members[i] = ResourceDescription
118
							.fromResource(resourceMembers[i]);
119
				}
120
			}
121
		} catch (CoreException e) {
122
			// Eat this exception because it only occurs when the resource
123
			// does not exist and we have already checked this.
124
			// We do not want to throw exceptions on the simple constructor, as
125
			// no one has actually tried to do anything yet.
126
		}
127
	}
128
129
	public IResource createResourceHandle() {
130
		IWorkspaceRoot workspaceRoot = parent.getWorkspace().getRoot();
131
		IPath folderPath = parent.getFullPath().append(name);
132
		return workspaceRoot.getFolder(folderPath);
133
	}
134
135
	protected void createChildResources(IContainer parentHandle,
136
			IProgressMonitor monitor, int ticks) throws CoreException {
137
138
		// restore any children
139
		if (members != null && members.length > 0) {
140
			for (int i = 0; i < members.length; i++) {
141
				members[i].parent = parentHandle;
142
				members[i].createResource(new SubProgressMonitor(monitor, ticks
143
						/ members.length));
144
			}
145
		}
146
	}
147
148
	public void recordLastHistory(IResource resource, IProgressMonitor monitor)
149
			throws CoreException {
150
		monitor.beginTask(
151
				UndoMessages.FolderDescription_SavingUndoInfoProgress, 100);
152
		for (int i = 0; i < members.length; i++) {
153
			if (members[i] instanceof FileDescription) {
154
				IPath path = resource.getFullPath().append(
155
						((FileDescription) members[i]).name);
156
				IFile fileHandle = resource.getWorkspace().getRoot().getFile(
157
						path);
158
				members[i].recordLastHistory(fileHandle,
159
						new SubProgressMonitor(monitor, 100 / members.length));
160
			} else if (members[i] instanceof FolderDescription) {
161
				IPath path = resource.getFullPath().append(
162
						((FolderDescription) members[i]).name);
163
				IFolder folderHandle = resource.getWorkspace().getRoot()
164
						.getFolder(path);
165
				members[i].recordLastHistory(folderHandle,
166
						new SubProgressMonitor(monitor, 100 / members.length));
167
			}
168
		}
169
		monitor.done();
170
	}
171
172
	public String getName() {
173
		return name;
174
	}
175
176
	/*
177
	 * Return the first folder found that has no child folders.
178
	 */
179
	public ContainerDescription getFirstLeafFolder() {
180
		// If there are no members, this is a leaf
181
		if (members == null || members.length == 0) {
182
			return this;
183
		}
184
		// Traverse the members and find the first potential leaf
185
		for (int i = 0; i < members.length; i++) {
186
			if (members[i] instanceof ContainerDescription) {
187
				return ((ContainerDescription) members[i]).getFirstLeafFolder();
188
			}
189
		}
190
		// No child folders were found, this is a leaf
191
		return this;
192
	}
193
194
	/*
195
	 * Add the specified resource description as a member of this resource
196
	 * description
197
	 */
198
	public void addMember(ResourceDescription member) {
199
		if (members == null) {
200
			members = new ResourceDescription[] { member };
201
		} else {
202
			ResourceDescription[] expandedMembers = new ResourceDescription[members.length + 1];
203
			System.arraycopy(members, 0, expandedMembers, 0, members.length);
204
			expandedMembers[members.length] = member;
205
			members = expandedMembers;
206
		}
207
	}
208
}
(-)src/org/eclipse/ui/ide/undo/CreateProjectOperation.java (+65 lines)
Added Link Here
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.ide.undo;
13
14
import org.eclipse.core.resources.IProjectDescription;
15
import org.eclipse.core.resources.IResourceStatus;
16
import org.eclipse.core.runtime.CoreException;
17
import org.eclipse.osgi.util.NLS;
18
import org.eclipse.ui.internal.ide.undo.ProjectDescription;
19
import org.eclipse.ui.internal.ide.undo.UndoMessages;
20
21
/**
22
 * A CreateProjectOperation represents an undoable operation for creating a
23
 * project in the workspace.
24
 * 
25
 * This class is intended to be instantiated and used by clients. It is not
26
 * intended to be subclassed by clients.
27
 * 
28
 * <strong>EXPERIMENTAL</strong> This class or interface has been added as part
29
 * of a work in progress. This API may change at any given time. Please do not
30
 * use this API without consulting with the Platform/UI team.
31
 * 
32
 * @since 3.3
33
 * 
34
 */
35
public class CreateProjectOperation extends AbstractCreateResourcesOperation {
36
37
	/**
38
	 * Create a CreateProjectOperation
39
	 * 
40
	 * @param projectDescription
41
	 *            the project to be created
42
	 * @param label
43
	 *            the label of the operation
44
	 */
45
	public CreateProjectOperation(IProjectDescription projectDescription,
46
			String label) {
47
		super(new ProjectDescription[] { new ProjectDescription(
48
				projectDescription) }, label);
49
	}
50
	
51
	/**
52
	 * Return the specific error message to use when the specified core
53
	 * exception occurs, or <code>null</code> to indicate that the the
54
	 * exception's message should be used.
55
	 */
56
	protected String getErrorMessage(CoreException e) {
57
		if (e.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) {
58
			if (resourceDescriptions != null && resourceDescriptions.length==1) {
59
				ProjectDescription project = (ProjectDescription)resourceDescriptions[0];
60
				return NLS.bind(UndoMessages.CreateProjectOperation_caseVariantExistsError, project.getName());
61
			}
62
		}
63
		return super.getErrorMessage(e);
64
	}	
65
}
(-)src/org/eclipse/ui/internal/ide/undo/ProjectDescription.java (+91 lines)
Added Link Here
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.resources.IProject;
15
import org.eclipse.core.resources.IProjectDescription;
16
import org.eclipse.core.resources.IResource;
17
import org.eclipse.core.resources.ResourcesPlugin;
18
import org.eclipse.core.runtime.Assert;
19
import org.eclipse.core.runtime.CoreException;
20
import org.eclipse.core.runtime.IProgressMonitor;
21
import org.eclipse.core.runtime.OperationCanceledException;
22
import org.eclipse.core.runtime.SubProgressMonitor;
23
24
/**
25
 * ProjectDescription is a lightweight description that describes a project to
26
 * be created.
27
 * 
28
 * This class is not intended to be instantiated or used by clients.
29
 * 
30
 * @since 3.3
31
 * 
32
 */
33
public class ProjectDescription extends ContainerDescription {
34
35
	private IProjectDescription projectDescription;
36
37
	/*
38
	 * Create a project description from a specified project. Used only when the
39
	 * project exists and is open.
40
	 */
41
	public ProjectDescription(IProject project) {
42
		super(project);
43
		Assert.isLegal(project.exists() && project.isOpen());
44
		try {
45
			this.projectDescription = project.getDescription();
46
		} catch (CoreException e) {
47
			// Eat this exception because it only occurs when the project
48
			// does not exist or is not open, and we have already checked this.
49
			// We do not want to throw exceptions on the simple constructor, as
50
			// no one has actually tried to do anything yet.
51
		}
52
	}
53
54
	/*
55
	 * Create a project description from a specified IProjectDescription. Used
56
	 * when the project does not yet exist.
57
	 */
58
	public ProjectDescription(IProjectDescription projectDescription) {
59
		super();
60
		this.projectDescription = projectDescription;
61
	}
62
63
	public IResource createResourceHandle() {
64
		return ResourcesPlugin.getWorkspace().getRoot().getProject(getName());
65
	}
66
67
	protected void createExistentResourceFromHandle(IResource resource,
68
			IProgressMonitor monitor) throws CoreException {
69
		Assert.isLegal(resource instanceof IProject);
70
		IProject projectHandle = (IProject) resource;
71
		monitor.beginTask(UndoMessages.ProjectDescription_NewProjectProgress,
72
				200);
73
		if (projectDescription == null) {
74
			projectHandle.create(new SubProgressMonitor(monitor, 100));
75
		} else {
76
			projectHandle.create(projectDescription, new SubProgressMonitor(
77
					monitor, 100));
78
		}
79
80
		if (monitor.isCanceled()) {
81
			throw new OperationCanceledException();
82
		}
83
		projectHandle.open(IResource.BACKGROUND_REFRESH,
84
				new SubProgressMonitor(monitor, 100));
85
		monitor.done();
86
	}
87
88
	public String getName() {
89
		return projectDescription.getName();
90
	}
91
}

Return to bug 123674