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 (-7 / +31 lines)
Lines 36-49 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
	public static String AbstractResourcesOperation_overwriteTitle;
52
	public static String AbstractResourcesOperation_overwriteError;
53
	public static String AbstractResourcesOperation_overwriteQuestion;
54
	
55
	public static String MoveOrCopyResourceOperation_SameNameOrLocation;
56
	public static String MoveOrCopyResourceOperation_ResourceDoesNotExist;
57
	public static String MoveOrCopyResourceOperation_ReadOnly;
58
59
	public static String DeleteResourcesOperation_DeletingProjectContentWarning;
60
	public static String CreateProjectOperation_caseVariantExistsError;
61
	
62
	public static String ProjectDescription_NewProjectProgress;
63
	public static String FileDescription_NewFileProgress;
64
	public static String FileDescription_SavingUndoInfoProgress;
65
	public static String FileDescription_ContentsCouldNotBeRestored;
66
	public static String FolderDescription_NewFolderProgress;
67
	public static String FolderDescription_SavingUndoInfoProgress;
68
	
39
69
40
	public static String MarkerOperation_ResourceDoesNotExist;
70
	public static String MarkerOperation_ResourceDoesNotExist;
41
	public static String MarkerOperation_MarkerDoesNotExist;
71
	public static String MarkerOperation_MarkerDoesNotExist;
42
	public static String MarkerOperation_NotEnoughInfo;
72
	public static String MarkerOperation_NotEnoughInfo;	
43
	
44
	public static String RenameResourceOperation_SameName;
45
	public static String RenameResourceOperation_NameAlreadyExists;
46
	public static String RenameResourceOperation_ResourceDoesNotExist;
47
	public static String RenameResourceOperation_ReadOnly;
48
	public static String RenameResourceOperation_ResourceAlreadyExists;
49
}
73
}
(-)src/org/eclipse/ui/internal/ide/undo/messages.properties (-5 / +31 lines)
Lines 20-31 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_deletionMessageTitle = Problems deleting
33
AbstractResourcesOperation_deletionExceptionMessage=Multiple problems occurred while deleting resources.
34
AbstractResourcesOperation_overwriteTitle = Resource already exists
35
AbstractResourcesOperation_overwriteError = Could not complete operation without overwriting resources.
36
AbstractResourcesOperation_overwriteQuestion = Resource ''{0}'' already exists. Do you want to overwrite it?
37
38
39
40
DeleteResourcesOperation_DeletingProjectContentWarning=Deleting project content will erase all of the file and folder history for the project.  Undo will not restore the content.
41
42
CreateProjectOperation_caseVariantExistsError = The underlying file system is case insensitive. There is an existing project which conflicts with ''{0}''.
43
44
ProjectDescription_NewProjectProgress=Creating new project...
45
FileDescription_NewFileProgress=Creating new file...
46
FileDescription_ContentsCouldNotBeRestored=Unexpected error.  File contents could not be restored from local history during undo/redo.
47
FileDescription_SavingUndoInfoProgress=Saving file info...
48
FolderDescription_NewFolderProgress=Creating new folder...
49
FolderDescription_SavingUndoInfoProgress=Saving folder info...
50
	
23
MarkerOperation_ResourceDoesNotExist=Cannot complete operation because resource no longer exists.
51
MarkerOperation_ResourceDoesNotExist=Cannot complete operation because resource no longer exists.
24
MarkerOperation_MarkerDoesNotExist=Cannot complete operation because marker no longer exists.
52
MarkerOperation_MarkerDoesNotExist=Cannot complete operation because marker no longer exists.
25
MarkerOperation_NotEnoughInfo=There is not enough information to perform the marker operation.
53
MarkerOperation_NotEnoughInfo=There is not enough information to perform the marker operation.
26
54
27
RenameResourceOperation_ReadOnly=The resource {0} is read only.
55
MoveOrCopyResourceOperation_ReadOnly=The resource {0} is read only.
28
RenameResourceOperation_SameName=Resource must be renamed to a different name.
56
MoveOrCopyResourceOperation_SameNameOrLocation=Resource cannot be moved or copied to the same location and name.
29
RenameResourceOperation_NameAlreadyExists=A resource with that name already exists.
57
MoveOrCopyResourceOperation_ResourceDoesNotExist=Resource no longer exists in the workspace.
30
RenameResourceOperation_ResourceDoesNotExist=Resource no longer exists in the workspace.
31
RenameResourceOperation_ResourceAlreadyExists=A resource named {0} already exists.  It will be overwritten.
(-)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 (-84 / +174 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 71-76 Link Here
71
71
72
	String[] modelProviderIds;
72
	String[] modelProviderIds;
73
73
74
	/*
75
	 * Return the shell described by the specified adaptable, or the active
76
	 * shell if no shell has been specified in the adaptable.
77
	 */
78
	protected static Shell getShell(IAdaptable info) {
79
		if (info != null) {
80
			Shell shell = (Shell) info.getAdapter(Shell.class);
81
			if (shell != null) {
82
				return shell;
83
			}
84
		}
85
		return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
86
	}
87
74
	/**
88
	/**
75
	 * Create an AbstractWorkspaceOperation with the specified name.
89
	 * Create an AbstractWorkspaceOperation with the specified name.
76
	 * 
90
	 * 
Lines 137-143 Link Here
137
	public boolean canExecute() {
151
	public boolean canExecute() {
138
		return isValid();
152
		return isValid();
139
	}
153
	}
140
	
154
141
	/*
155
	/*
142
	 * (non-Javadoc)
156
	 * (non-Javadoc)
143
	 * 
157
	 * 
Lines 173-197 Link Here
173
				public void run(IProgressMonitor monitor) throws CoreException {
187
				public void run(IProgressMonitor monitor) throws CoreException {
174
					doExecute(monitor, info);
188
					doExecute(monitor, info);
175
				}
189
				}
176
			}, null);
190
			}, null, IWorkspace.AVOID_UPDATE, null);
177
		} catch (final CoreException e) {
191
		} catch (final CoreException e) {
192
			final boolean[] propagateException = new boolean[1];
178
			getShell(info).getDisplay().syncExec(new Runnable() {
193
			getShell(info).getDisplay().syncExec(new Runnable() {
179
				public void run() {
194
				public void run() {
180
					ErrorDialog
195
					propagateException[0] = handleCoreException(
181
							.openError(
196
							e,
182
									getShell(info),
197
							getShell(info),
183
									NLS
198
							NLS
184
											.bind(
199
									.bind(
185
													UndoMessages.AbstractWorkspaceOperation_ExecuteErrorTitle,
200
											UndoMessages.AbstractWorkspaceOperation_ExecuteErrorTitle,
186
													getLabel()), null, e
201
											getLabel()));
187
											.getStatus());
188
202
189
				}
203
				}
190
204
191
			});
205
			});
192
			throw new ExecutionException(NLS.bind(
206
			if (propagateException[0]) {
193
					UndoMessages.AbstractWorkspaceOperation_ExecuteErrorTitle,
207
				throw new ExecutionException(
194
					getLabel()), e);
208
						NLS
209
								.bind(
210
										UndoMessages.AbstractWorkspaceOperation_ExecuteErrorTitle,
211
										getLabel()), e);
212
			}
195
		}
213
		}
196
		isValid = true;
214
		isValid = true;
197
		return Status.OK_STATUS;
215
		return Status.OK_STATUS;
Lines 215-237 Link Here
215
				}
233
				}
216
			}, null);
234
			}, null);
217
		} catch (final CoreException e) {
235
		} catch (final CoreException e) {
236
			final boolean[] propagateException = new boolean[1];
218
			getShell(info).getDisplay().syncExec(new Runnable() {
237
			getShell(info).getDisplay().syncExec(new Runnable() {
219
				public void run() {
238
				public void run() {
220
					ErrorDialog
239
					propagateException[0] = handleCoreException(
221
							.openError(
240
							e,
222
									getShell(info),
241
							getShell(info),
223
									NLS
242
							NLS
224
											.bind(
243
									.bind(
225
													UndoMessages.AbstractWorkspaceOperation_RedoErrorTitle,
244
											UndoMessages.AbstractWorkspaceOperation_RedoErrorTitle,
226
													getLabel()), null, e
245
											getLabel()));
227
											.getStatus());
228
229
				}
246
				}
230
247
231
			});
248
			});
232
			throw new ExecutionException(NLS.bind(
249
			if (propagateException[0]) {
233
					UndoMessages.AbstractWorkspaceOperation_RedoErrorTitle,
250
				throw new ExecutionException(NLS.bind(
234
					getLabel()), e);
251
						UndoMessages.AbstractWorkspaceOperation_RedoErrorTitle,
252
						getLabel()), e);
253
			}
235
		}
254
		}
236
		isValid = true;
255
		isValid = true;
237
		return Status.OK_STATUS;
256
		return Status.OK_STATUS;
Lines 255-277 Link Here
255
				}
274
				}
256
			}, null);
275
			}, null);
257
		} catch (final CoreException e) {
276
		} catch (final CoreException e) {
277
			final boolean[] propagateException = new boolean[1];
258
			getShell(info).getDisplay().syncExec(new Runnable() {
278
			getShell(info).getDisplay().syncExec(new Runnable() {
259
				public void run() {
279
				public void run() {
260
					ErrorDialog
280
					propagateException[0] = handleCoreException(
261
							.openError(
281
							e,
262
									getShell(info),
282
							getShell(info),
263
									NLS
283
							NLS
264
											.bind(
284
									.bind(
265
													UndoMessages.AbstractWorkspaceOperation_UndoErrorTitle,
285
											UndoMessages.AbstractWorkspaceOperation_UndoErrorTitle,
266
													getLabel()), null, e
286
											getLabel()));
267
											.getStatus());
268
287
269
				}
288
				}
270
289
271
			});
290
			});
272
			throw new ExecutionException(NLS.bind(
291
			if (propagateException[0]) {
273
					UndoMessages.AbstractWorkspaceOperation_UndoErrorTitle,
292
				throw new ExecutionException(NLS.bind(
274
					getLabel()), e);
293
						UndoMessages.AbstractWorkspaceOperation_UndoErrorTitle,
294
						getLabel()), e);
295
			}
275
		}
296
		}
276
		isValid = true;
297
		isValid = true;
277
		return Status.OK_STATUS;
298
		return Status.OK_STATUS;
Lines 289-313 Link Here
289
	protected abstract void doExecute(IProgressMonitor monitor, IAdaptable info)
310
	protected abstract void doExecute(IProgressMonitor monitor, IAdaptable info)
290
			throws CoreException;
311
			throws CoreException;
291
312
292
	/*
293
	 * Return the shell described by the specified adaptable, or the active
294
	 * shell if no shell has been specified in the adaptable.
295
	 */
296
	protected Shell getShell(IAdaptable info) {
297
		if (info != null) {
298
			Shell shell = (Shell) info.getAdapter(Shell.class);
299
			if (shell != null) {
300
				return shell;
301
			}
302
		}
303
		return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
304
	}
305
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
	 * Return whether the resources known by this operation contain any
560
	 * projects.
561
	 * 
562
	 * @return <code>true</code> if there is one or more projects known by
563
	 *         this operation and false if there are no projects.
564
	 */
565
	protected boolean resourcesIncludesProjects() {
566
		if (resources == null || resources.length == 0) {
567
			return false;
568
		}
569
		for (int i = 0; i < resources.length; i++) {
570
			if (resources[i].getType() == IResource.PROJECT) {
571
				return true;
572
			}
573
		}
574
		return false;
575
	}
576
577
	/**
578
	 * Handle the core exception that occurred while trying to execute, undo, or
579
	 * redo the operation, returning a boolean to indicate whether this
580
	 * exception should cuase a {@link ExecutionException} to be thrown.
581
	 * 
582
	 * It is safe to access UI in this method. The default implementation is to
583
	 * show an error dialog, but callers may choose to swallow certain
584
	 * exceptions or show them differently.
585
	 * 
586
	 * If the only difference in handling the exception is to show a different
587
	 * error message, callers should override
588
	 * {@link #getErrorMessage(CoreException)} instead.
589
	 */
590
	protected boolean handleCoreException(CoreException e, Shell shell,
591
			String errorTitle) {
592
		ErrorDialog.openError(shell, errorTitle, getErrorMessage(e), e
593
				.getStatus());
594
		return true;
595
	}
596
597
	/**
598
	 * Return the specific error message to use when the specified core
599
	 * exception occurs, or <code>null</code> to indicate that the the
600
	 * exception's message should be used.
601
	 */
602
	protected String getErrorMessage(CoreException e) {
603
		return null;
604
	}
515
}
605
}
(-)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
(-)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/CopyProjectOperation.java (-72 / +27 lines)
Lines 12-39 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;
18
import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
17
import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
19
import org.eclipse.core.resources.mapping.ResourceChangeValidator;
18
import org.eclipse.core.resources.mapping.ResourceChangeValidator;
20
import org.eclipse.core.runtime.CoreException;
19
import org.eclipse.core.runtime.IAdaptable;
21
import org.eclipse.core.runtime.IPath;
20
import org.eclipse.core.runtime.IPath;
22
import org.eclipse.core.runtime.IProgressMonitor;
21
import org.eclipse.core.runtime.IProgressMonitor;
23
import org.eclipse.core.runtime.IStatus;
24
import org.eclipse.core.runtime.MultiStatus;
22
import org.eclipse.core.runtime.MultiStatus;
25
import org.eclipse.core.runtime.OperationCanceledException;
26
import org.eclipse.core.runtime.Path;
23
import org.eclipse.core.runtime.Path;
27
import org.eclipse.core.runtime.Platform;
28
import org.eclipse.jface.dialogs.ErrorDialog;
24
import org.eclipse.jface.dialogs.ErrorDialog;
29
import org.eclipse.jface.dialogs.MessageDialog;
25
import org.eclipse.jface.dialogs.MessageDialog;
26
import org.eclipse.jface.operation.IRunnableWithProgress;
30
import org.eclipse.jface.window.Window;
27
import org.eclipse.jface.window.Window;
31
import org.eclipse.osgi.util.NLS;
28
import org.eclipse.osgi.util.NLS;
32
import org.eclipse.swt.widgets.Shell;
29
import org.eclipse.swt.widgets.Shell;
33
import org.eclipse.ui.PlatformUI;
30
import org.eclipse.ui.PlatformUI;
34
import org.eclipse.ui.dialogs.ProjectLocationSelectionDialog;
31
import org.eclipse.ui.dialogs.ProjectLocationSelectionDialog;
35
import org.eclipse.ui.ide.IDE;
32
import org.eclipse.ui.ide.IDE;
33
import org.eclipse.ui.ide.undo.CopyResourcesOperation;
36
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
34
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
35
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
37
import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;
36
import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;
38
37
39
/**
38
/**
Lines 68-73 Link Here
68
     * (and can hence be ignored)
67
     * (and can hence be ignored)
69
     * @return whether the operation should proceed
68
     * @return whether the operation should proceed
70
     * @since 3.2
69
     * @since 3.2
70
     * @deprecated As of 3.3, validation is performed in the undoable operation 
71
     * executed by this operation.
71
     */
72
     */
72
    protected static boolean validateCopy(Shell shell, IProject project, String newName, String[] modelProviderIds) {
73
    protected static boolean validateCopy(Shell shell, IProject project, String newName, String[] modelProviderIds) {
73
    	IResourceChangeDescriptionFactory factory = ResourceChangeValidator.getValidator().createDeltaFactory();
74
    	IResourceChangeDescriptionFactory factory = ResourceChangeValidator.getValidator().createDeltaFactory();
Lines 106-115 Link Here
106
107
107
        String newName = (String) destinationPaths[0];
108
        String newName = (String) destinationPaths[0];
108
        IPath newLocation = new Path((String) destinationPaths[1]);
109
        IPath newLocation = new Path((String) destinationPaths[1]);
109
110
        if (!validateCopy(parentShell, project, newName, getModelProviderIds())) {
111
			return;
112
		}
113
        
110
        
114
        boolean completed = performProjectCopy(project, newName, newLocation);
111
        boolean completed = performProjectCopy(project, newName, newLocation);
115
112
Lines 136-158 Link Here
136
     */
133
     */
137
    private boolean performProjectCopy(final IProject project,
134
    private boolean performProjectCopy(final IProject project,
138
            final String projectName, final IPath newLocation) {
135
            final String projectName, final IPath newLocation) {
139
        WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
136
        IRunnableWithProgress op = new IRunnableWithProgress() {
140
            public void execute(IProgressMonitor monitor) {
137
            public void run(IProgressMonitor monitor) {
141
                try {
138
            	CopyResourcesOperation op = new CopyResourcesOperation(project, 
142
                    if (monitor.isCanceled()) {
139
            			newLocation.append(projectName), 
143
						throw new OperationCanceledException();
140
            			IDEWorkbenchMessages.CopyProjectOperation_copyProject);
144
					}
141
    			op.setModelProviderIds(getModelProviderIds());
145
                    
142
    			try {
146
                    monitor.setTaskName(IDEWorkbenchMessages.CopyProjectOperation_progressTitle);
143
    				PlatformUI.getWorkbench().getOperationSupport()
147
                    
144
    						.getOperationHistory().execute(op, monitor, new IAdaptable() {
148
                    //Get a copy of the current description and modify it
145
    		   					public Object getAdapter(Class clazz) {
149
                    IProjectDescription newDescription = createProjectDescription(
146
    		   						if (clazz == Shell.class) {
150
                            project, projectName, newLocation);
147
    		   							return parentShell;
151
                    project.copy(newDescription, IResource.SHALLOW
148
    		   						}
152
                            | IResource.FORCE, monitor);
149
    		   						return null;
153
                } catch (CoreException e) {
150
    		   					}
154
                    recordError(e); // log error
151
    		   				});
155
                }
152
    			} catch (ExecutionException e) {
153
    				// Error message already shown to user by the operation
154
    				IDEWorkbenchPlugin.log(e.getMessage(), e);
155
    			}
156
            }
156
            }
157
        };
157
        };
158
158
Lines 175-225 Link Here
175
    }
175
    }
176
176
177
    /**
177
    /**
178
     * Create a new IProjectDescription for the copy using the auto-generated
179
     * name and path.
180
     * 
181
     * @return IProjectDescription
182
     * @param project the source project
183
     * @param projectName the name for the new project
184
     * @param rootLocation the path the new project will be stored under.
185
     * @throws CoreException
186
     */
187
    private IProjectDescription createProjectDescription(IProject project,
188
            String projectName, IPath rootLocation) throws CoreException {
189
        //Get a copy of the current description and modify it
190
        IProjectDescription newDescription = project.getDescription();
191
        newDescription.setName(projectName);
192
193
        //If the location is the default then set the location to null
194
        if (rootLocation.equals(Platform.getLocation())) {
195
			newDescription.setLocation(null);
196
		} else {
197
			newDescription.setLocation(rootLocation);
198
		}
199
200
        return newDescription;
201
    }
202
203
    /**
204
     * Records the core exception to be displayed to the user
205
     * once the action is finished.
206
     *
207
     * @param error a <code>CoreException</code>
208
     */
209
    private void recordError(CoreException error) {
210
211
        if (errorStatus == null) {
212
			errorStatus = new MultiStatus(
213
                    PlatformUI.PLUGIN_ID,
214
                    IStatus.ERROR,
215
                    IDEWorkbenchMessages.CopyProjectOperation_copyFailedMessage,
216
                    error);
217
		}
218
219
        errorStatus.merge(error.getStatus());
220
    }
221
222
    /**
223
     * Returns the model provider ids that are known to the client
178
     * Returns the model provider ids that are known to the client
224
     * that instantiated this operation.
179
     * that instantiated this operation.
225
     * 
180
     * 
(-)extensions/org/eclipse/ui/actions/MoveProjectAction.java (-72 / +32 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 78-122 Link Here
78
	 * Moves the project to the new values.
76
	 * Moves the project to the new values.
79
	 * 
77
	 * 
80
	 * @param project
78
	 * @param project
81
	 *            the project to copy
79
	 *            the project to move
82
	 * @param projectName
83
	 *            the name of the copy
84
	 * @param newLocation
80
	 * @param newLocation
85
	 *            IPath
81
	 *            IPath
86
	 * @return <code>true</code> if the copy operation completed, and
82
	 * @return <code>true</code> if the copy operation completed, and
87
	 *         <code>false</code> if it was abandoned part way
83
	 *         <code>false</code> if it was abandoned part way
88
	 */
84
	 */
89
	boolean performMove(final IProject project, final String projectName,
85
	boolean performMove(final IProject project, 
90
			final IPath newLocation) {
86
			final IPath newLocation) {
91
		WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
87
		
92
			public void execute(IProgressMonitor monitor) {
88
		IRunnableWithProgress op =  new IRunnableWithProgress() {
93
				try {
89
    		public void run(IProgressMonitor monitor) {
94
					if (monitor.isCanceled()) {
90
    			MoveResourcesOperation op = new MoveResourcesOperation(new IResource[] {project}, newLocation, getText());
95
						throw new OperationCanceledException();
91
    			op.setModelProviderIds(getModelProviderIds());
96
					}
92
    			try {
97
					
93
    				PlatformUI.getWorkbench().getOperationSupport()
98
					monitor.setTaskName(MOVE_PROGRESS_TITLE);
94
    						.getOperationHistory().execute(op, monitor, new IAdaptable() {
99
					//Get a copy of the current description and modify it
95
    		   					public Object getAdapter(Class clazz) {
100
					IProjectDescription newDescription = createDescription(
96
    		   						if (clazz == Shell.class) {
101
							project, projectName, newLocation);
97
    		   							return shell;
102
98
    		   						}
103
					project.move(newDescription, IResource.FORCE
99
    		   						return null;
104
							| IResource.SHALLOW, monitor);
100
    		   					}
105
101
    		   				});
106
				} catch (CoreException e) {
102
    			} catch (ExecutionException e) {
107
					recordError(e); // log error
103
    				IDEWorkbenchPlugin.log(e.getMessage(), e);
108
				} finally {
104
    			}
109
					monitor.done();
105
    		}
110
				}
106
    	};
111
			}
107
		
112
		};
113
114
		try {
108
		try {
115
			new ProgressMonitorJobsDialog(shell).run(true, true, op);
109
			new ProgressMonitorJobsDialog(shell).run(true, true, op);
116
		} catch (InterruptedException e) {
110
		} catch (InterruptedException e) {
117
			return false;
111
			return false;
118
		} catch (InvocationTargetException e) {
112
		} catch (InvocationTargetException e) {
119
			// CoreExceptions are collected above, but unexpected runtime
113
			// CoreExceptions are collected by the operation, but unexpected runtime
120
			// exceptions and errors may still occur.
114
			// exceptions and errors may still occur.
121
			IDEWorkbenchPlugin.log(getClass(),
115
			IDEWorkbenchPlugin.log(getClass(),
122
                    "performMove()", e.getTargetException()); //$NON-NLS-1$
116
                    "performMove()", e.getTargetException()); //$NON-NLS-1$
Lines 158-199 Link Here
158
			return;
152
			return;
159
		}
153
		}
160
154
161
		String projectName = (String) destinationPaths[0];
162
		IPath newLocation = new Path((String) destinationPaths[1]);
155
		IPath newLocation = new Path((String) destinationPaths[1]);
163
164
		if (!validateMove(project, projectName)) {
165
			return;
166
		}
167
		
156
		
168
		boolean completed = performMove(project, projectName, newLocation);
157
		performMove(project, 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
	}
158
	}
199
}
159
}
(-)extensions/org/eclipse/ui/actions/CopyProjectAction.java (-43 / +26 lines)
Lines 13-36 Link Here
13
import java.lang.reflect.InvocationTargetException;
13
import java.lang.reflect.InvocationTargetException;
14
import java.util.List;
14
import java.util.List;
15
15
16
import org.eclipse.core.commands.ExecutionException;
16
import org.eclipse.core.resources.IProject;
17
import org.eclipse.core.resources.IProject;
17
import org.eclipse.core.resources.IProjectDescription;
18
import org.eclipse.core.resources.IProjectDescription;
18
import org.eclipse.core.resources.IResource;
19
import org.eclipse.core.resources.IResource;
19
import org.eclipse.core.runtime.CoreException;
20
import org.eclipse.core.runtime.CoreException;
21
import org.eclipse.core.runtime.IAdaptable;
20
import org.eclipse.core.runtime.IPath;
22
import org.eclipse.core.runtime.IPath;
21
import org.eclipse.core.runtime.IProgressMonitor;
23
import org.eclipse.core.runtime.IProgressMonitor;
22
import org.eclipse.core.runtime.IStatus;
24
import org.eclipse.core.runtime.IStatus;
23
import org.eclipse.core.runtime.OperationCanceledException;
24
import org.eclipse.core.runtime.Path;
25
import org.eclipse.core.runtime.Path;
25
import org.eclipse.core.runtime.Platform;
26
import org.eclipse.core.runtime.Platform;
26
import org.eclipse.jface.dialogs.ErrorDialog;
27
import org.eclipse.jface.dialogs.MessageDialog;
27
import org.eclipse.jface.dialogs.MessageDialog;
28
import org.eclipse.jface.operation.IRunnableWithProgress;
28
import org.eclipse.jface.viewers.IStructuredSelection;
29
import org.eclipse.jface.viewers.IStructuredSelection;
29
import org.eclipse.osgi.util.NLS;
30
import org.eclipse.osgi.util.NLS;
30
import org.eclipse.swt.widgets.Shell;
31
import org.eclipse.swt.widgets.Shell;
31
import org.eclipse.ui.PlatformUI;
32
import org.eclipse.ui.PlatformUI;
32
import org.eclipse.ui.dialogs.ProjectLocationSelectionDialog;
33
import org.eclipse.ui.dialogs.ProjectLocationSelectionDialog;
34
import org.eclipse.ui.ide.undo.CopyResourcesOperation;
33
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
35
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
36
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
34
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
37
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
35
import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;
38
import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;
36
import org.eclipse.ui.plugin.AbstractUIPlugin;
39
import org.eclipse.ui.plugin.AbstractUIPlugin;
Lines 46-53 Link Here
46
49
47
    private static String COPY_TITLE = IDEWorkbenchMessages.CopyProjectAction_title;
50
    private static String COPY_TITLE = IDEWorkbenchMessages.CopyProjectAction_title;
48
51
49
    private static String COPY_PROGRESS_TITLE = IDEWorkbenchMessages.CopyProjectAction_progressTitle;
50
51
    private static String PROBLEMS_TITLE = IDEWorkbenchMessages.CopyProjectAction_copyFailedTitle;
52
    private static String PROBLEMS_TITLE = IDEWorkbenchMessages.CopyProjectAction_copyFailedTitle;
52
53
53
    /**
54
    /**
Lines 135-140 Link Here
135
    /**
136
    /**
136
     * Return the title of the errors dialog.
137
     * Return the title of the errors dialog.
137
     * @return java.lang.String
138
     * @return java.lang.String
139
     * 
140
     * @deprecated As of 3.3, the undoable operation created by this action
141
     * handles error dialogs.
138
     */
142
     */
139
    protected String getErrorsTitle() {
143
    protected String getErrorsTitle() {
140
        return PROBLEMS_TITLE;
144
        return PROBLEMS_TITLE;
Lines 159-188 Link Here
159
     */
163
     */
160
    boolean performCopy(final IProject project, final String projectName,
164
    boolean performCopy(final IProject project, final String projectName,
161
            final IPath newLocation) {
165
            final IPath newLocation) {
162
        WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
166
        IRunnableWithProgress op = new IRunnableWithProgress() {
163
            public void execute(IProgressMonitor monitor) {
167
            public void run(IProgressMonitor monitor) {
164
168
            	CopyResourcesOperation op = new CopyResourcesOperation(project, newLocation.append(projectName), getText());
165
                monitor.beginTask(COPY_PROGRESS_TITLE, 100);
169
    			op.setModelProviderIds(getModelProviderIds());
166
                try {
170
    			try {
167
                    if (monitor.isCanceled()) {
171
    				PlatformUI.getWorkbench().getOperationSupport()
168
						throw new OperationCanceledException();
172
    						.getOperationHistory().execute(op, monitor, new IAdaptable() {
169
					}
173
    		   					public Object getAdapter(Class clazz) {
170
174
    		   						if (clazz == Shell.class) {
171
                    //Get a copy of the current description and modify it
175
    		   							return shell;
172
                    IProjectDescription newDescription = createDescription(
176
    		   						}
173
                            project, projectName, newLocation);
177
    		   						return null;
174
                    monitor.worked(50);
178
    		   					}
175
179
    		   				});
176
                    project.copy(newDescription, IResource.SHALLOW
180
    			} catch (ExecutionException e) {
177
                            | IResource.FORCE, monitor);
181
    				IDEWorkbenchPlugin.log(e.getMessage(), e);
178
182
    			}
179
                    monitor.worked(50);
180
181
                } catch (CoreException e) {
182
                    recordError(e); // log error
183
                } finally {
184
                    monitor.done();
185
                }
186
            }
183
            }
187
        };
184
        };
188
185
Lines 239-260 Link Here
239
236
240
        String newName = (String) destinationPaths[0];
237
        String newName = (String) destinationPaths[0];
241
        IPath newLocation = new Path((String) destinationPaths[1]);
238
        IPath newLocation = new Path((String) destinationPaths[1]);
242
        if (!CopyProjectOperation.validateCopy(shell, project, newName, getModelProviderIds())) {
243
			return;
244
		}
245
239
246
        boolean completed = performCopy(project, newName, newLocation);
240
        performCopy(project, newName, newLocation);
247
248
        if (!completed) {
249
			return; // not appropriate to show errors
250
		}
251
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
    }
241
    }
259
242
260
	/**
243
	/**
(-)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 / +47 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
    			// Rename is only valid for a single resource.  This has already been validated.
556
    			if (resources.length == 1) {
557
	    			MoveResourcesOperation op = new MoveResourcesOperation(resources[0], newPath, getText());
558
	    			op.setModelProviderIds(getModelProviderIds());
559
	    			try {
560
	    				errorStatus[0] = PlatformUI.getWorkbench().getOperationSupport()
561
	    						.getOperationHistory().execute(op, monitor, new IAdaptable() {
562
	    		   					public Object getAdapter(Class clazz) {
563
	    		   						if (clazz == Shell.class) {
564
	    		   							return getShell();
565
	    		   						}
566
	    		   						return null;
567
	    		   					}
568
	    		   				});
569
	    			} catch (ExecutionException e) {
570
	    				IDEWorkbenchPlugin.log(e.getMessage(), e);
571
	    			}
572
    			}
573
    		}
574
    	};
575
    }
667
}
576
}
(-)extensions/org/eclipse/ui/actions/CopyFilesAndFoldersOperation.java (-99 / +71 lines)
Lines 18-23 Link Here
18
import java.util.Arrays;
18
import java.util.Arrays;
19
import java.util.List;
19
import java.util.List;
20
20
21
import org.eclipse.core.commands.ExecutionException;
21
import org.eclipse.core.filesystem.EFS;
22
import org.eclipse.core.filesystem.EFS;
22
import org.eclipse.core.filesystem.IFileInfo;
23
import org.eclipse.core.filesystem.IFileInfo;
23
import org.eclipse.core.filesystem.IFileStore;
24
import org.eclipse.core.filesystem.IFileStore;
Lines 30-37 Link Here
30
import org.eclipse.core.resources.IWorkspaceRoot;
31
import org.eclipse.core.resources.IWorkspaceRoot;
31
import org.eclipse.core.resources.ResourcesPlugin;
32
import org.eclipse.core.resources.ResourcesPlugin;
32
import org.eclipse.core.resources.WorkspaceJob;
33
import org.eclipse.core.resources.WorkspaceJob;
33
import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
34
import org.eclipse.core.resources.mapping.ResourceChangeValidator;
35
import org.eclipse.core.runtime.CoreException;
34
import org.eclipse.core.runtime.CoreException;
36
import org.eclipse.core.runtime.IAdaptable;
35
import org.eclipse.core.runtime.IAdaptable;
37
import org.eclipse.core.runtime.IPath;
36
import org.eclipse.core.runtime.IPath;
Lines 47-61 Link Here
47
import org.eclipse.jface.dialogs.IInputValidator;
46
import org.eclipse.jface.dialogs.IInputValidator;
48
import org.eclipse.jface.dialogs.InputDialog;
47
import org.eclipse.jface.dialogs.InputDialog;
49
import org.eclipse.jface.dialogs.MessageDialog;
48
import org.eclipse.jface.dialogs.MessageDialog;
49
import org.eclipse.jface.operation.IRunnableWithProgress;
50
import org.eclipse.jface.window.Window;
50
import org.eclipse.jface.window.Window;
51
import org.eclipse.osgi.util.NLS;
51
import org.eclipse.osgi.util.NLS;
52
import org.eclipse.swt.SWT;
52
import org.eclipse.swt.SWT;
53
import org.eclipse.swt.widgets.Display;
53
import org.eclipse.swt.widgets.Display;
54
import org.eclipse.swt.widgets.Shell;
54
import org.eclipse.swt.widgets.Shell;
55
import org.eclipse.ui.PlatformUI;
55
import org.eclipse.ui.PlatformUI;
56
import org.eclipse.ui.dialogs.ContainerGenerator;
57
import org.eclipse.ui.dialogs.IOverwriteQuery;
56
import org.eclipse.ui.dialogs.IOverwriteQuery;
58
import org.eclipse.ui.ide.IDE;
57
import org.eclipse.ui.ide.undo.AbstractCopyOrMoveResourcesOperation;
58
import org.eclipse.ui.ide.undo.CopyResourcesOperation;
59
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
59
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
60
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
60
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
61
import org.eclipse.ui.internal.ide.StatusUtil;
61
import org.eclipse.ui.internal.ide.StatusUtil;
Lines 388-393 Link Here
388
	 *            destination to which resources will be copied
388
	 *            destination to which resources will be copied
389
	 * @param subMonitor
389
	 * @param subMonitor
390
	 *            a progress monitor for showing progress and for cancelation
390
	 *            a progress monitor for showing progress and for cancelation
391
	 *          
392
	 * @deprecated As of 3.3, the work is performed in the undoable operation
393
	 * created in {@link #performCopy(IResource[], IPath, IProgressMonitor)}
391
	 */
394
	 */
392
	protected void copy(IResource[] resources, IPath destination,
395
	protected void copy(IResource[] resources, IPath destination,
393
			IProgressMonitor subMonitor) throws CoreException {
396
			IProgressMonitor subMonitor) throws CoreException {
Lines 541-568 Link Here
541
			return copiedResources[0];
544
			return copiedResources[0];
542
		}
545
		}
543
546
544
		if (!validateOperation(resources, destinationPath)) {
547
		IRunnableWithProgress op = new IRunnableWithProgress() {
545
			return copiedResources[0];
548
			public void run(IProgressMonitor monitor) {
546
		}
549
				copyResources(resources, destinationPath, copiedResources,
547
550
						monitor);
548
		if (fork) {
549
			WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
550
				public void execute(IProgressMonitor monitor) {
551
					copyResources(resources, destinationPath, copiedResources,
552
							monitor);
553
				}
554
			};
555
556
			try {
557
				PlatformUI.getWorkbench().getProgressService().run(true, true,
558
						op);
559
			} catch (InterruptedException e) {
560
				return copiedResources[0];
561
			} catch (InvocationTargetException e) {
562
				display(e);
563
			}
551
			}
564
		} else {
552
		};
565
			copyResources(resources, destinationPath, copiedResources, monitor);
553
554
		try {
555
			PlatformUI.getWorkbench().getProgressService().run(fork, true,
556
					op);
557
		} catch (InterruptedException e) {
558
			return copiedResources[0];
559
		} catch (InvocationTargetException e) {
560
			display(e);
566
		}
561
		}
567
562
568
		// If errors occurred, open an Error dialog
563
		// If errors occurred, open an Error dialog
Lines 570-616 Link Here
570
			displayError(errorStatus);
565
			displayError(errorStatus);
571
			errorStatus = null;
566
			errorStatus = null;
572
		}
567
		}
568
		
573
		return copiedResources[0];
569
		return copiedResources[0];
574
	}
570
	}
575
571
576
	/**
572
	/**
577
	 * Validates the copy or move operation.
578
	 * 
579
	 * @param resources
580
	 *            the resources being copied or moved
581
	 * @param destinationPath
582
	 *            the destination of the copy or move
583
	 * @return whether the operation should proceed
584
	 * @since 3.2
585
	 */
586
	private boolean validateOperation(IResource[] resources,
587
			IPath destinationPath) {
588
		IResourceChangeDescriptionFactory factory = ResourceChangeValidator
589
				.getValidator().createDeltaFactory();
590
		for (int i = 0; i < resources.length; i++) {
591
			IResource resource = resources[i];
592
			if (isMove()) {
593
				factory.move(resource, destinationPath.append(resource
594
						.getName()));
595
			} else {
596
				factory.copy(resource, destinationPath.append(resource
597
						.getName()));
598
			}
599
		}
600
		String title;
601
		String message;
602
		if (isMove()) {
603
			title = IDEWorkbenchMessages.CopyFilesAndFoldersOperation_confirmMove;
604
			message = IDEWorkbenchMessages.CopyFilesAndFoldersOperation_warningMove;
605
		} else {
606
			title = IDEWorkbenchMessages.CopyFilesAndFoldersOperation_confirmCopy;
607
			message = IDEWorkbenchMessages.CopyFilesAndFoldersOperation_warningCopy;
608
		}
609
		return IDE.promptToConfirm(messageShell, title, message, factory
610
				.getDelta(), modelProviderIds, true /* syncExec */);
611
	}
612
613
	/**
614
	 * Return whether the operation is a move or a copy
573
	 * Return whether the operation is a move or a copy
615
	 * 
574
	 * 
616
	 * @return whether the operation is a move or a copy
575
	 * @return whether the operation is a move or a copy
Lines 1190-1205 Link Here
1190
	private boolean performCopy(IResource[] resources, IPath destination,
1149
	private boolean performCopy(IResource[] resources, IPath destination,
1191
			IProgressMonitor monitor) {
1150
			IProgressMonitor monitor) {
1192
		try {
1151
		try {
1193
			ContainerGenerator generator = new ContainerGenerator(destination);
1152
			AbstractCopyOrMoveResourcesOperation op = getUndoableCopyOrMoveOperation(
1194
			generator.generateContainer(new SubProgressMonitor(monitor, 10));
1153
					resources, destination);
1195
			IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 75);
1154
			op.setModelProviderIds(getModelProviderIds());
1196
			copy(resources, destination, subMonitor);
1155
			PlatformUI.getWorkbench().getOperationSupport()
1197
		} catch (CoreException e) {
1156
					.getOperationHistory().execute(op, monitor, new IAdaptable() {
1198
			recordError(e); // log error
1157
	   					public Object getAdapter(Class clazz) {
1158
	   						if (clazz == Shell.class) {
1159
	   							return messageShell;
1160
	   						}
1161
	   						return null;
1162
	   					}
1163
	   				});
1164
		} catch (ExecutionException e) {
1165
			IDEWorkbenchPlugin.log(e.getMessage(), e);
1199
			return false;
1166
			return false;
1200
		} finally {
1167
		} 
1201
			monitor.done();
1202
		}
1203
		return true;
1168
		return true;
1204
	}
1169
	}
1205
1170
Lines 1222-1263 Link Here
1222
	private boolean performCopyWithAutoRename(IResource[] resources,
1187
	private boolean performCopyWithAutoRename(IResource[] resources,
1223
			IPath destination, IProgressMonitor monitor) {
1188
			IPath destination, IProgressMonitor monitor) {
1224
		IWorkspace workspace = resources[0].getWorkspace();
1189
		IWorkspace workspace = resources[0].getWorkspace();
1225
1190
		IPath [] destinationPaths = new IPath[resources.length];
1226
		try {
1191
		try {
1227
			ContainerGenerator generator = new ContainerGenerator(destination);
1228
			generator.generateContainer(new SubProgressMonitor(monitor, 10));
1229
1230
			IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 75);
1231
			subMonitor.beginTask(getOperationTitle(), resources.length);
1232
1233
			for (int i = 0; i < resources.length; i++) {
1192
			for (int i = 0; i < resources.length; i++) {
1234
				IResource source = resources[i];
1193
				IResource source = resources[i];
1235
				IPath destinationPath = destination.append(source.getName());
1194
				destinationPaths[i] = destination.append(source.getName());
1236
1195
1237
				if (workspace.getRoot().exists(destinationPath)) {
1196
				if (workspace.getRoot().exists(destinationPaths[i])) {
1238
					destinationPath = getNewNameFor(destinationPath, workspace);
1197
					destinationPaths[i] = getNewNameFor(destinationPaths[i], workspace);
1239
				}
1240
				if (destinationPath != null) {
1241
					try {
1242
						source.copy(destinationPath, IResource.SHALLOW,
1243
								new SubProgressMonitor(subMonitor, 0));
1244
					} catch (CoreException e) {
1245
						recordError(e); // log error
1246
						return false;
1247
					}
1248
				}
1249
				subMonitor.worked(1);
1250
				if (subMonitor.isCanceled()) {
1251
					throw new OperationCanceledException();
1252
				}
1198
				}
1253
			}
1199
			}
1254
		} catch (CoreException e) {
1200
			CopyResourcesOperation op = new CopyResourcesOperation(resources, destinationPaths, 
1255
			recordError(e); // log error
1201
					IDEWorkbenchMessages.CopyFilesAndFoldersOperation_copyTitle);
1202
			op.setModelProviderIds(getModelProviderIds());
1203
			PlatformUI.getWorkbench().getOperationSupport()
1204
					.getOperationHistory().execute(op, monitor, new IAdaptable() {
1205
	   					public Object getAdapter(Class clazz) {
1206
	   						if (clazz == Shell.class) {
1207
	   							return messageShell;
1208
	   						}
1209
	   						return null;
1210
	   					}
1211
	   				});
1212
		} catch (ExecutionException e) {
1213
			IDEWorkbenchPlugin.log(e.getMessage(), e);
1256
			return false;
1214
			return false;
1257
		} finally {
1258
			monitor.done();
1259
		}
1215
		}
1260
1261
		return true;
1216
		return true;
1262
	}
1217
	}
1263
1218
Lines 1744-1747 Link Here
1744
	public void setModelProviderIds(String[] modelProviderIds) {
1699
	public void setModelProviderIds(String[] modelProviderIds) {
1745
		this.modelProviderIds = modelProviderIds;
1700
		this.modelProviderIds = modelProviderIds;
1746
	}
1701
	}
1702
	
1703
	/**
1704
	 * Returns an IUndoableOperation suitable for performing the move or copy
1705
	 * operation that will move or copy the given resources to the given 
1706
	 * destination path.
1707
	 * 
1708
	 * @param resources
1709
	 * 			the resources to be moved or copied
1710
	 * @param destinationPath
1711
	 * 			the destination path to which the resources should be moved
1712
	 * @return the operation that should be used to perform the move or cop
1713
	 */
1714
	protected AbstractCopyOrMoveResourcesOperation getUndoableCopyOrMoveOperation(IResource[] resources, IPath destinationPath) {
1715
		return new CopyResourcesOperation(resources, destinationPath, 
1716
				IDEWorkbenchMessages.CopyFilesAndFoldersOperation_copyTitle);
1717
		
1718
	}
1747
}
1719
}
(-)extensions/org/eclipse/ui/actions/MoveFilesAndFoldersOperation.java (+25 lines)
Lines 22-27 Link Here
22
import org.eclipse.core.runtime.SubProgressMonitor;
22
import org.eclipse.core.runtime.SubProgressMonitor;
23
import org.eclipse.osgi.util.NLS;
23
import org.eclipse.osgi.util.NLS;
24
import org.eclipse.swt.widgets.Shell;
24
import org.eclipse.swt.widgets.Shell;
25
import org.eclipse.ui.ide.undo.AbstractCopyOrMoveResourcesOperation;
26
import org.eclipse.ui.ide.undo.MoveResourcesOperation;
25
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
27
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
26
28
27
/**
29
/**
Lines 61-66 Link Here
61
     * @param resources the resources to move
63
     * @param resources the resources to move
62
     * @param destination destination to which resources will be moved
64
     * @param destination destination to which resources will be moved
63
     * @param subMonitor a progress monitor for showing progress and for cancelation
65
     * @param subMonitor a progress monitor for showing progress and for cancelation
66
     * 
67
     * @deprecated As of 3.3, the work is performed in the undoable operation
68
	 * created in {@link #performCopy(IResource[], IPath, IProgressMonitor)}
69
64
     */
70
     */
65
    protected void copy(IResource[] resources, IPath destination,
71
    protected void copy(IResource[] resources, IPath destination,
66
            IProgressMonitor subMonitor) throws CoreException {
72
            IProgressMonitor subMonitor) throws CoreException {
Lines 169-174 Link Here
169
     * @param existing existing file to set the source content in
175
     * @param existing existing file to set the source content in
170
     * @param subMonitor a progress monitor for showing progress and for cancelation
176
     * @param subMonitor a progress monitor for showing progress and for cancelation
171
     * @throws CoreException setContents failed
177
     * @throws CoreException setContents failed
178
     * @deprecated As of 3.3, this method is not called.
172
     */
179
     */
173
    private void moveExisting(IResource source, IResource existing,
180
    private void moveExisting(IResource source, IResource existing,
174
            IProgressMonitor subMonitor) throws CoreException {
181
            IProgressMonitor subMonitor) throws CoreException {
Lines 223-226 Link Here
223
    protected boolean isMove() {
230
    protected boolean isMove() {
224
    	return true;
231
    	return true;
225
    }
232
    }
233
    
234
	/**
235
	 * Returns an IUndoableOperation suitable for performing the move or copy
236
	 * operation that will move or copy the given resources to the given 
237
	 * destination path.
238
	 * 
239
	 * @param resources
240
	 * 			the resources to be moved or copied
241
	 * @param destinationPath
242
	 * 			the destination path to which the resources should be moved
243
	 * @return the operation that should be used to perform the move or copy
244
	 * @since 3.3
245
	 */
246
	protected AbstractCopyOrMoveResourcesOperation getUndoableCopyOrMoveOperation(IResource[] resources, IPath destinationPath) {
247
		return new MoveResourcesOperation(resources, destinationPath, 
248
				IDEWorkbenchMessages.CopyFilesAndFoldersOperation_moveTitle);
249
		
250
	}
226
}
251
}
(-)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 / +5 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 297-302 Link Here
297
	public static String CopyFilesAndFoldersOperation_CopyResourcesTask;
289
	public static String CopyFilesAndFoldersOperation_CopyResourcesTask;
298
	public static String CopyFilesAndFoldersOperation_parentNotEqual;
290
	public static String CopyFilesAndFoldersOperation_parentNotEqual;
299
	public static String CopyFilesAndFoldersOperation_infoNotFound;
291
	public static String CopyFilesAndFoldersOperation_infoNotFound;
292
	public static String CopyFilesAndFoldersOperation_copyTitle;
293
	public static String CopyFilesAndFoldersOperation_moveTitle;
300
294
301
	public static String MoveFilesAndFoldersOperation_sameSourceAndDest;
295
	public static String MoveFilesAndFoldersOperation_sameSourceAndDest;
302
	public static String MoveFilesAndFoldersOperation_moveFailedTitle;
296
	public static String MoveFilesAndFoldersOperation_moveFailedTitle;
Lines 366-371 Link Here
366
	public static String WizardNewFolderCreationPage_progress;
360
	public static String WizardNewFolderCreationPage_progress;
367
	public static String WizardNewFolderCreationPage_errorTitle;
361
	public static String WizardNewFolderCreationPage_errorTitle;
368
	public static String WizardNewFolderCreationPage_internalErrorTitle;
362
	public static String WizardNewFolderCreationPage_internalErrorTitle;
363
	public static String WizardNewFolderCreationPage_title;
369
	public static String WizardNewFolder_internalError;
364
	public static String WizardNewFolder_internalError;
370
365
371
	// --- New File ---
366
	// --- New File ---
Lines 375-380 Link Here
375
	public static String WizardNewFileCreationPage_file;
370
	public static String WizardNewFileCreationPage_file;
376
	public static String WizardNewFileCreationPage_internalErrorTitle;
371
	public static String WizardNewFileCreationPage_internalErrorTitle;
377
	public static String WizardNewFileCreationPage_internalErrorMessage;
372
	public static String WizardNewFileCreationPage_internalErrorMessage;
373
	public static String WizardNewFileCreationPage_title;
374
378
375
379
	// --- Linked Resource ---
376
	// --- Linked Resource ---
380
	public static String WizardNewLinkPage_linkFileButton;
377
	public static String WizardNewLinkPage_linkFileButton;
(-)src/org/eclipse/ui/internal/ide/messages.properties (-8 / +4 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 305-310 Link Here
305
CopyFilesAndFoldersOperation_CopyResourcesTask=Copying Resources
297
CopyFilesAndFoldersOperation_CopyResourcesTask=Copying Resources
306
CopyFilesAndFoldersOperation_parentNotEqual = The resources must have the same parent.
298
CopyFilesAndFoldersOperation_parentNotEqual = The resources must have the same parent.
307
CopyFilesAndFoldersOperation_infoNotFound = Information for {0} could not be read. Please check the .log file for details.
299
CopyFilesAndFoldersOperation_infoNotFound = Information for {0} could not be read. Please check the .log file for details.
300
CopyFilesAndFoldersOperation_copyTitle= Copy Resources
301
CopyFilesAndFoldersOperation_moveTitle= Move Resources
308
302
309
MoveFilesAndFoldersOperation_sameSourceAndDest = Cannot move ''{0}''. The source and destination are the same.
303
MoveFilesAndFoldersOperation_sameSourceAndDest = Cannot move ''{0}''. The source and destination are the same.
310
MoveFilesAndFoldersOperation_moveFailedTitle = Move Problems
304
MoveFilesAndFoldersOperation_moveFailedTitle = Move Problems
Lines 386-391 Link Here
386
WizardNewFolderCreationPage_progress = Creating
380
WizardNewFolderCreationPage_progress = Creating
387
WizardNewFolderCreationPage_errorTitle = Creation Problems
381
WizardNewFolderCreationPage_errorTitle = Creation Problems
388
WizardNewFolderCreationPage_internalErrorTitle = Creation problems
382
WizardNewFolderCreationPage_internalErrorTitle = Creation problems
383
WizardNewFolderCreationPage_title = New Folder
389
WizardNewFolder_internalError = Internal error: {0}
384
WizardNewFolder_internalError = Internal error: {0}
390
385
391
# --- New File ---
386
# --- New File ---
Lines 395-400 Link Here
395
WizardNewFileCreationPage_file = file
390
WizardNewFileCreationPage_file = file
396
WizardNewFileCreationPage_internalErrorTitle = Creation problems
391
WizardNewFileCreationPage_internalErrorTitle = Creation problems
397
WizardNewFileCreationPage_internalErrorMessage = Internal error: {0}
392
WizardNewFileCreationPage_internalErrorMessage = Internal error: {0}
393
WizardNewFileCreationPage_title = New File
398
394
399
# --- Linked Resource ---
395
# --- Linked Resource ---
400
WizardNewLinkPage_linkFileButton = &Link to file on the file system
396
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 (+140 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 file 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
	public void createExistentResourceFromHandle(IResource resource,
93
			IProgressMonitor monitor) throws CoreException {
94
95
		Assert.isLegal(resource instanceof IFile);
96
		if (resource.exists()) {
97
			return;
98
		}
99
		IFile fileHandle = (IFile) resource;
100
		monitor.beginTask(UndoMessages.FileDescription_NewFileProgress, 200);
101
		try {
102
			if (monitor.isCanceled()) {
103
				throw new OperationCanceledException();
104
			}
105
			if (location != null) {
106
				fileHandle.createLink(location, IResource.ALLOW_MISSING_LOCAL,
107
						new SubProgressMonitor(monitor, 200));
108
			} else {
109
				InputStream contents = new StringBufferInputStream(
110
						UndoMessages.FileDescription_ContentsCouldNotBeRestored);
111
				String charset = null;
112
				// Retrieve the contents and charset from the file state.
113
				// Other file state attributes, such as timestamps, have
114
				// already been retrieved from the original IResource object
115
				// and are restored in the superclass.
116
				if (fileState != null && fileState.exists()) {
117
					contents = fileState.getContents();
118
					charset = fileState.getCharset();
119
				}
120
				fileHandle.create(contents, false, new SubProgressMonitor(
121
						monitor, 100));
122
				fileHandle.setCharset(charset, new SubProgressMonitor(monitor,
123
						100));
124
			}
125
			if (monitor.isCanceled()) {
126
				throw new OperationCanceledException();
127
			}
128
		} finally {
129
			monitor.done();
130
		}
131
	}
132
133
	public boolean isValid() {
134
		return super.isValid() && fileState != null && fileState.exists();
135
	}
136
137
	public String getName() {
138
		return name;
139
	}
140
}
(-)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 && resourcesIncludesProjects()) {
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
		setResourceDescriptions(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 (+92 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
	public void createExistentResourceFromHandle(IResource resource,
62
			IProgressMonitor monitor) throws CoreException {
63
64
		Assert.isLegal(resource instanceof IFolder);
65
		if (resource.exists()) {
66
			return;
67
		}
68
		IFolder folderHandle = (IFolder) resource;
69
		try {
70
			monitor.beginTask(UndoMessages.FolderDescription_NewFolderProgress,
71
					200);
72
			if (monitor.isCanceled()) {
73
				throw new OperationCanceledException();
74
			}
75
			if (location != null) {
76
				folderHandle.createLink(location,
77
						IResource.ALLOW_MISSING_LOCAL, new SubProgressMonitor(
78
								monitor, 100));
79
			} else {
80
				folderHandle.create(false, true, new SubProgressMonitor(
81
						monitor, 100));
82
			}
83
			if (monitor.isCanceled()) {
84
				throw new OperationCanceledException();
85
			}
86
			createChildResources(folderHandle, monitor, 100);
87
88
		} finally {
89
			monitor.done();
90
		}
91
	}
92
}
(-)src/org/eclipse/ui/ide/undo/MoveResourcesOperation.java (+115 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
22
/**
23
 * A MoveResourcesOperation represents an undoable operation for moving one or
24
 * 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 MoveResourcesOperation extends
37
		AbstractCopyOrMoveResourcesOperation {
38
39
	/**
40
	 * Create a MoveResourcesOperation that moves all of the specified resources
41
	 * to the same target location, using their existing names.
42
	 * 
43
	 * @param resources
44
	 *            the resources to be moved
45
	 * @param destinationPath
46
	 *            the destination path for the resources, not including the name
47
	 *            of the new resource.
48
	 * @param label
49
	 *            the label of the operation
50
	 */
51
	public MoveResourcesOperation(IResource[] resources, IPath destinationPath,
52
			String label) {
53
		super(resources, destinationPath, label);
54
	}
55
56
	/**
57
	 * Create a MoveResourcesOperation that moves a single resource to a new
58
	 * location. The new location includes the name of the resource, so this may
59
	 * be used for a move/rename operation or a simple move.
60
	 * 
61
	 * @param resource
62
	 *            the resource to be moved
63
	 * @param newPath
64
	 *            the new path for the resource, including its desired name.
65
	 * @param label
66
	 *            the label of the operation
67
	 */
68
	public MoveResourcesOperation(IResource resource, IPath newPath,
69
			String label) {
70
		super(new IResource[] { resource }, new IPath[] { newPath }, label);
71
	}
72
73
	protected void doExecute(IProgressMonitor monitor, IAdaptable uiInfo)
74
			throws CoreException {
75
		moveOrCopy(monitor, uiInfo, true); // true = move
76
	}
77
78
	protected void doUndo(IProgressMonitor monitor, IAdaptable uiInfo)
79
			throws CoreException {
80
		moveOrCopy(monitor, uiInfo, true); // true = move
81
	}
82
83
	protected boolean updateResourceChangeDescriptionFactory(
84
			IResourceChangeDescriptionFactory factory, int operation) {
85
		for (int i = 0; i < resources.length; i++) {
86
			IResource resource = resources[i];
87
			factory.move(resource, getDestinationPath(resource, i, true));
88
		}
89
		return true;
90
	}
91
92
	public IStatus computeExecutionStatus(IProgressMonitor monitor) {
93
		IStatus status = super.computeExecutionStatus(monitor);
94
		if (status.isOK()) {
95
			status = computeMoveOrCopyStatus();
96
		}
97
		return status;
98
	}
99
100
	public IStatus computeUndoableStatus(IProgressMonitor monitor) {
101
		IStatus status = super.computeUndoableStatus(monitor);
102
		if (status.isOK()) {
103
			status = computeMoveOrCopyStatus();
104
		}
105
		return status;
106
	}
107
108
	public IStatus computeRedoableStatus(IProgressMonitor monitor) {
109
		IStatus status = super.computeRedoableStatus(monitor);
110
		if (status.isOK()) {
111
			status = computeMoveOrCopyStatus();
112
		}
113
		return status;
114
	}
115
}
(-)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
	public 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/AbstractCopyOrMoveResourcesOperation.java (+288 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.net.URI;
15
import java.util.ArrayList;
16
import java.util.List;
17
18
import org.eclipse.core.resources.IProject;
19
import org.eclipse.core.resources.IResource;
20
import org.eclipse.core.runtime.CoreException;
21
import org.eclipse.core.runtime.IAdaptable;
22
import org.eclipse.core.runtime.IPath;
23
import org.eclipse.core.runtime.IProgressMonitor;
24
import org.eclipse.core.runtime.IStatus;
25
import org.eclipse.core.runtime.Path;
26
import org.eclipse.core.runtime.Platform;
27
import org.eclipse.core.runtime.Status;
28
import org.eclipse.core.runtime.SubProgressMonitor;
29
import org.eclipse.jface.dialogs.IDialogConstants;
30
import org.eclipse.ui.internal.ide.undo.ResourceDescription;
31
import org.eclipse.ui.internal.ide.undo.UndoMessages;
32
33
/**
34
 * An AbstractCopyOrMoveResourcesOperation represents an undoable operation for
35
 * moving or copying one or more resources in the workspace.
36
 * 
37
 * This class is not intended to be subclassed by clients.
38
 * 
39
 * <strong>EXPERIMENTAL</strong> This class or interface has been added as part
40
 * of a work in progress. This API may change at any given time. Please do not
41
 * use this API without consulting with the Platform/UI team.
42
 * 
43
 * @since 3.3
44
 * 
45
 */
46
public abstract class AbstractCopyOrMoveResourcesOperation extends
47
		AbstractResourcesOperation {
48
49
	// Used when there are different destination names for each resource
50
	protected IPath[] destinationPaths = null;
51
52
	// Used when all resources are going to the same container (no name changes)
53
	protected IPath destination = null;
54
55
	/**
56
	 * Create an AbstractCopyOrMoveResourcesOperation that moves or copies all
57
	 * of the specified resources to the specified paths. The destination paths
58
	 * must include the names of the resources at their new location.
59
	 * 
60
	 * @param resources
61
	 *            the resources to be moved or copied
62
	 * @param destinationPaths
63
	 *            the destination paths for the resources, including the name to
64
	 *            be assigned to the resource at its new location.
65
	 * @param label
66
	 *            the label of the operation
67
	 */
68
	AbstractCopyOrMoveResourcesOperation(IResource[] resources,
69
			IPath[] destinationPaths, String label) {
70
		super(resources, label);
71
		this.destinationPaths = destinationPaths;
72
	}
73
74
	/**
75
	 * Create an AbstractCopyOrMoveResourcesOperation that moves or copies all
76
	 * of the specified resources to the same target location, using their
77
	 * existing names.
78
	 * 
79
	 * @param resources
80
	 *            the resources to be moved or copied
81
	 * @param destinationPath
82
	 *            the destination path for the resources, not including the name
83
	 *            of the new resource.
84
	 * @param label
85
	 *            the label of the operation
86
	 */
87
	AbstractCopyOrMoveResourcesOperation(IResource[] resources,
88
			IPath destinationPath, String label) {
89
		super(resources, label);
90
		destination = destinationPath;
91
	}
92
93
	protected void moveOrCopy(IProgressMonitor monitor, IAdaptable uiInfo,
94
			boolean move) throws CoreException {
95
96
		String progressMessage;
97
		if (move) {
98
			progressMessage = UndoMessages.AbstractResourcesOperation_MovingResources;
99
		} else {
100
			progressMessage = UndoMessages.AbstractResourcesOperation_CopyingResourcesProgress;
101
		}
102
		monitor.beginTask(progressMessage, 2000);
103
		IResource[] resourcesInNewLocations = new IResource[resources.length];
104
		List overwrittenResources = new ArrayList();
105
		IPath[] newDestinationPaths = new IPath[resources.length];
106
107
		for (int i = 0; i < resources.length; i++) {
108
			// Record the original path so this can be undone
109
			if (resources[i].getType() == IResource.PROJECT) {
110
				URI locationURI = ((IProject) resources[i]).getDescription()
111
						.getLocationURI();
112
				if (locationURI == null) {
113
					newDestinationPaths[i] = Platform.getLocation().append(
114
							resources[i].getName());
115
				} else {
116
					newDestinationPaths[i] = new Path(locationURI.getPath())
117
							.append(resources[i].getName());
118
				}
119
			} else {
120
				newDestinationPaths[i] = resources[i].getFullPath();
121
			}
122
			// Move or copy the resources and record the overwrites that would
123
			// be restored if this operation were reversed
124
			ResourceDescription[] overwrites;
125
			if (move) {
126
				overwrites = move(resources[i], getDestinationPath(
127
						resources[i], i, true), new SubProgressMonitor(monitor,
128
						1000 / resources.length), uiInfo);
129
			} else {
130
				overwrites = copy(
131
						new IResource[] { resources[i] },
132
						getDestinationPath(resources[i], i, true),
133
						new SubProgressMonitor(monitor, 1000 / resources.length),
134
						uiInfo, true);
135
			}
136
			// Accumulate the overwrites into the full list
137
			for (int j = 0; j < overwrites.length; j++) {
138
				overwrittenResources.add(overwrites[i]);
139
			}
140
			// Record the resource in its new location
141
			resourcesInNewLocations[i] = getWorkspace().getRoot().findMember(
142
					getDestinationPath(resources[i], i, false));
143
		}
144
145
		// Are there any previously overwritten resources to restore now?
146
		if (resourceDescriptions != null) {
147
			for (int i = 0; i < resourceDescriptions.length; i++) {
148
				if (resourceDescriptions[i] != null) {
149
					resourceDescriptions[i]
150
							.createResource(new SubProgressMonitor(monitor,
151
									1000 / resourceDescriptions.length));
152
				}
153
			}
154
		}
155
156
		// Reset resource descriptions to the just overwritten resources
157
		setResourceDescriptions((ResourceDescription[]) overwrittenResources
158
				.toArray(new ResourceDescription[overwrittenResources.size()]));
159
160
		// Reset the target resources to refer to the resources in their new
161
		// location. Note that the destination paths were reset to the original
162
		// location as we did the move.
163
		setTargetResources(resourcesInNewLocations);
164
165
		// Reset the destination path to the new paths
166
		destinationPaths = newDestinationPaths;
167
		destination = null;
168
169
		monitor.done();
170
	}
171
172
	/*
173
	 * Compute the status for moving or copying the resources.
174
	 * 
175
	 * Note this method may be called on initial moving or copying of a
176
	 * resource, or when a move or copy is undone or redone. Therefore, this
177
	 * method should check conditions that can change over the life of the
178
	 * operation, such as whether the file to moved or copied exists, and
179
	 * whether the target location is still valid. One-time static checks should
180
	 * typically be done by the caller so that the user is not continually
181
	 * prompted or warned about conditions that were acceptable at the time of
182
	 * original execution and do not change over time.
183
	 */
184
	protected IStatus computeMoveOrCopyStatus() {
185
		// Check for error conditions first so that we do not prompt the user
186
		// on warnings that eventually will not matter anyway.
187
		if (resources == null || !hasDestinationPath()) {
188
			markInvalid();
189
			return getErrorStatus(UndoMessages.AbstractResourcesOperation_NotEnoughInfo);
190
		}
191
		for (int i = 0; i < resources.length; i++) {
192
			IResource resource = resources[i];
193
			// Does the resource still exist?
194
			if (!resource.exists()) {
195
				markInvalid();
196
				return getErrorStatus(UndoMessages.MoveOrCopyResourceOperation_ResourceDoesNotExist);
197
			}
198
			// Are we really trying to move it to a different name?
199
			IPath proposedPath = getDestinationPath(resource, i, false);
200
			if (resource.getFullPath().equals(proposedPath)) {
201
				markInvalid();
202
				return getErrorStatus(UndoMessages.MoveOrCopyResourceOperation_SameNameOrLocation);
203
			}
204
			// Is the proposed name valid?
205
			IStatus status = getWorkspace().validateName(
206
					proposedPath.lastSegment(), resource.getType());
207
			if (status.getSeverity() == IStatus.ERROR) {
208
				markInvalid();
209
			}
210
			if (!status.isOK()) {
211
				return status;
212
			}
213
		}
214
215
		for (int i = 0; i < resources.length; i++) {
216
			// No error conditions. Check and warn for any overwrites that may
217
			// occur.
218
			IResource newResource = null;
219
			if (resources[i].getType() == IResource.PROJECT) {
220
				// Projects may be moved to a new location or copied to a new
221
				// name. To cover both cases, we consider matching location
222
				// paths, including name, to represent an overwrite.
223
				IPath proposedPath = getDestinationPath(resources[i], i, true);
224
				IPath existingPath = resources[i].getLocation().append(
225
						resources[i].getName());
226
				if (proposedPath.equals(existingPath)) {
227
					newResource = resources[i];
228
				}
229
			} else {
230
				IPath proposedPath = getDestinationPath(resources[i], i, false);
231
				newResource = getWorkspace().getRoot().findMember(proposedPath);
232
			}
233
			if (newResource != null) {
234
				int result = queryOverwrite(newResource, null);
235
				if (result == IDialogConstants.YES_TO_ALL_ID) {
236
					return Status.OK_STATUS;
237
				} else if (result == IDialogConstants.CANCEL_ID) {
238
					return Status.CANCEL_STATUS;
239
				} else if (result == IDialogConstants.NO_ID) {
240
					markInvalid();
241
					return getErrorStatus(UndoMessages.AbstractResourcesOperation_overwriteError);
242
				}
243
				// Otherwise (YES_ID) we continue checking each one
244
				// individually.
245
			}
246
		}
247
		return Status.OK_STATUS;
248
	}
249
250
	protected IPath getDestinationPath(IResource resource, int i,
251
			boolean includeProjectLocation) {
252
		if (resource.getType() == IResource.PROJECT) {
253
			return getProjectPath((IProject) resource, i,
254
					includeProjectLocation);
255
		}
256
		if (destinationPaths != null) {
257
			return destinationPaths[i];
258
		}
259
		return destination.append(resource.getName());
260
261
	}
262
263
	private IPath getProjectPath(IProject project, int i,
264
			boolean includeProjectLocation) {
265
		String projectName;
266
		IPath projectLocation = null;
267
		if (destinationPaths != null) {
268
			if (includeProjectLocation) {
269
				return destinationPaths[i];
270
			}
271
			// new name specified in destination path
272
			projectName = destinationPaths[i].lastSegment();
273
		} else {
274
			// if not use the old name and common destination path
275
			projectName = project.getName();
276
			projectLocation = destination;
277
		}
278
		if (includeProjectLocation) {
279
			return projectLocation.append(projectName);
280
		} 
281
		return new Path(projectName);
282
	}
283
284
	protected boolean hasDestinationPath() {
285
		return (destinationPaths != null && resources.length == destinationPaths.length)
286
				|| (destination != null);
287
	}
288
}
(-)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/ide/undo/AbstractResourcesOperation.java (+765 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.IContainer;
18
import org.eclipse.core.resources.IFile;
19
import org.eclipse.core.resources.IProject;
20
import org.eclipse.core.resources.IProjectDescription;
21
import org.eclipse.core.resources.IResource;
22
import org.eclipse.core.resources.IResourceStatus;
23
import org.eclipse.core.resources.IWorkspace;
24
import org.eclipse.core.resources.IWorkspaceRoot;
25
import org.eclipse.core.resources.ResourcesPlugin;
26
import org.eclipse.core.runtime.CoreException;
27
import org.eclipse.core.runtime.IAdaptable;
28
import org.eclipse.core.runtime.IPath;
29
import org.eclipse.core.runtime.IProgressMonitor;
30
import org.eclipse.core.runtime.IStatus;
31
import org.eclipse.core.runtime.MultiStatus;
32
import org.eclipse.core.runtime.NullProgressMonitor;
33
import org.eclipse.core.runtime.OperationCanceledException;
34
import org.eclipse.core.runtime.Platform;
35
import org.eclipse.core.runtime.Status;
36
import org.eclipse.core.runtime.SubProgressMonitor;
37
import org.eclipse.jface.dialogs.IDialogConstants;
38
import org.eclipse.jface.dialogs.MessageDialog;
39
import org.eclipse.osgi.util.NLS;
40
import org.eclipse.swt.widgets.Shell;
41
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
42
import org.eclipse.ui.internal.ide.undo.ContainerDescription;
43
import org.eclipse.ui.internal.ide.undo.FileDescription;
44
import org.eclipse.ui.internal.ide.undo.ResourceDescription;
45
import org.eclipse.ui.internal.ide.undo.UndoMessages;
46
47
/**
48
 * An AbstractResourcesOperation represents an undoable operation that
49
 * manipulates resources. It provides implementations for resource rename,
50
 * delete, creation, and modification. It also assigns the workspace undo
51
 * context as the undo context for operations of this type.
52
 * 
53
 * This class is not intended to be subclassed by clients.
54
 * 
55
 * <strong>EXPERIMENTAL</strong> This class or interface has been added as part
56
 * of a work in progress. This API may change at any given time. Please do not
57
 * use this API without consulting with the Platform/UI team.
58
 * 
59
 * @since 3.3
60
 * 
61
 */
62
public abstract class AbstractResourcesOperation extends
63
		AbstractWorkspaceOperation {
64
65
	/*
66
	 * Delete all of the specified resources, returning resource descriptions
67
	 * that can be used to restore them.
68
	 * 
69
	 * This method is static to ensure "statelessness." Calling instance methods
70
	 * are responsible for maintaining the current state of resources and
71
	 * resource descriptions for the operation.
72
	 */
73
	protected static ResourceDescription[] delete(
74
			IResource[] resourcesToDelete, IProgressMonitor monitor,
75
			IAdaptable uiInfo, boolean deleteContent) throws CoreException {
76
		final List exceptions = new ArrayList();
77
		boolean forceOutOfSyncDelete = false;
78
		ResourceDescription[] returnedResourceDescriptions = new ResourceDescription[resourcesToDelete.length];
79
		monitor
80
				.beginTask(
81
						UndoMessages.AbstractResourcesOperation_DeleteResourcesProgress,
82
						resourcesToDelete.length);
83
		try {
84
			for (int i = 0; i < resourcesToDelete.length; ++i) {
85
				if (monitor.isCanceled()) {
86
					throw new OperationCanceledException();
87
				}
88
				IResource resource = resourcesToDelete[i];
89
				try {
90
					returnedResourceDescriptions[i] = delete(resource,
91
							new SubProgressMonitor(monitor, 1), uiInfo,
92
							forceOutOfSyncDelete, deleteContent);
93
				} catch (CoreException e) {
94
					if (resource.getType() == IResource.FILE) {
95
						IStatus[] children = e.getStatus().getChildren();
96
						if (children.length == 1
97
								&& children[0].getCode() == IResourceStatus.OUT_OF_SYNC_LOCAL) {
98
							int result = queryDeleteOutOfSync(resource, uiInfo);
99
100
							if (result == IDialogConstants.YES_ID) {
101
								// retry the delete with a force out of sync
102
								delete(resource, new SubProgressMonitor(
103
										monitor, 1), uiInfo, true,
104
										deleteContent);
105
							} else if (result == IDialogConstants.YES_TO_ALL_ID) {
106
								// all future attempts should force out of
107
								// sync
108
								forceOutOfSyncDelete = true;
109
								delete(resource, new SubProgressMonitor(
110
										monitor, 1), uiInfo,
111
										forceOutOfSyncDelete, deleteContent);
112
							} else if (result == IDialogConstants.CANCEL_ID) {
113
								throw new OperationCanceledException();
114
							} else {
115
								exceptions.add(e);
116
							}
117
						} else {
118
							exceptions.add(e);
119
						}
120
					} else {
121
						exceptions.add(e);
122
					}
123
				}
124
			}
125
			IStatus result = createResult(exceptions);
126
			if (!result.isOK()) {
127
				throw new CoreException(result);
128
			}
129
		} finally {
130
			monitor.done();
131
		}
132
		return returnedResourceDescriptions;
133
	}
134
135
	/*
136
	 * Recreate the resources from the specified resource descriptions.
137
	 * 
138
	 * This method is static to ensure "statelessness." Calling instance methods
139
	 * are responsible for maintaining the current state of resources and
140
	 * resource descriptions for the operation.
141
	 */
142
	protected static IResource[] recreate(
143
			ResourceDescription[] resourcesToRecreate,
144
			IProgressMonitor monitor, IAdaptable uiInfo) throws CoreException {
145
		final List exceptions = new ArrayList();
146
		IResource[] resourcesToReturn = new IResource[resourcesToRecreate.length];
147
		monitor
148
				.beginTask(
149
						UndoMessages.AbstractResourcesOperation_CreateResourcesProgress,
150
						resourcesToRecreate.length);
151
		try {
152
			for (int i = 0; i < resourcesToRecreate.length; ++i) {
153
				if (monitor.isCanceled()) {
154
					throw new OperationCanceledException();
155
				}
156
				try {
157
					resourcesToReturn[i] = resourcesToRecreate[i]
158
							.createResource(new SubProgressMonitor(monitor, 1));
159
				} catch (CoreException e) {
160
					exceptions.add(e);
161
				}
162
			}
163
			IStatus result = createResult(exceptions);
164
			if (!result.isOK()) {
165
				throw new CoreException(result);
166
			}
167
		} finally {
168
			monitor.done();
169
		}
170
		return resourcesToReturn;
171
	}
172
173
	/*
174
	 * Move the specified resource to the new path provided. The new path
175
	 * includes any new name desired for the moved resource. Return the resource
176
	 * descriptions for any resources that were overwritten as part of the move.
177
	 * 
178
	 * This method is static to ensure "statelessness." Calling instance methods
179
	 * are responsible for maintaining the current state of resources and
180
	 * resource descriptions for the operation.
181
	 */
182
183
	protected static ResourceDescription[] move(IResource resourceToMove,
184
			IPath newPath, IProgressMonitor monitor, IAdaptable uiInfo)
185
			throws CoreException {
186
		monitor.beginTask(
187
				UndoMessages.AbstractResourcesOperation_MovingResources, 3);
188
		IWorkspaceRoot workspaceRoot = resourceToMove.getWorkspace().getRoot();
189
		List overwrittenResources = new ArrayList();
190
191
		// Some moves are optimized and recorded as complete in this flag
192
		boolean moved = false;
193
		IResource newResource = workspaceRoot.findMember(newPath);
194
		// If a resource already exists at the new location, we must
195
		// overwrite it.
196
		if (newResource != null) {
197
			// File on file overwrite is optimized as a reset of the
198
			// target file's contents
199
			if (resourceToMove.getType() == IResource.FILE
200
					&& newResource.getType() == IResource.FILE) {
201
				IFile file = (IFile) resourceToMove;
202
				IFile existingFile = (IFile) newResource;
203
				ResourceDescription resourceDescription = copyOverExistingResource(
204
						file, existingFile, monitor, uiInfo, true);
205
				if (resourceDescription != null) {
206
					overwrittenResources.add(resourceDescription);
207
					moved = true;
208
				}
209
			} else {
210
				// Any other overwrite is simply a delete of the resource
211
				// that is being overwritten, followed by the move
212
				ResourceDescription[] deleted = delete(
213
						new IResource[] { newResource },
214
						new SubProgressMonitor(monitor, 1), uiInfo, false);
215
				for (int j = 0; j < deleted.length; j++) {
216
					overwrittenResources.add(deleted[j]);
217
				}
218
			}
219
		} else {
220
			monitor.worked(100);
221
		}
222
		// Overwrites have been handled. If there is still a move to do, do
223
		// so now.
224
		if (!moved) {
225
			if (resourceToMove.getType() == IResource.PROJECT) {
226
				IProject project = (IProject) resourceToMove;
227
				IProjectDescription description = project.getDescription();
228
				description.setName(newPath.lastSegment());
229
				// If the location is the default then set the location
230
				// to null
231
				IPath projectLocation = newPath.removeLastSegments(1);
232
				if (projectLocation.equals(Platform.getLocation())) {
233
					description.setLocation(null);
234
				} else {
235
					description.setLocation(projectLocation);
236
				}
237
				project.move(description, IResource.FORCE | IResource.SHALLOW,
238
						new SubProgressMonitor(monitor, 2));
239
			} else {
240
				generateContainers(newPath.removeLastSegments(1));
241
				resourceToMove
242
						.move(newPath, IResource.KEEP_HISTORY
243
								| IResource.SHALLOW, new SubProgressMonitor(
244
								monitor, 2));
245
246
			}
247
		}
248
		monitor.done();
249
		return (ResourceDescription[]) overwrittenResources
250
				.toArray(new ResourceDescription[overwrittenResources.size()]);
251
	}
252
253
	/*
254
	 * Copies the resources to the given destination. This method is called
255
	 * recursively to merge folders during folder copy. Return an array of
256
	 * ResourceDescriptions for any resources that were overwritten as part of
257
	 * the copy.
258
	 */
259
	protected static ResourceDescription[] copy(IResource[] resources,
260
			IPath destination, IProgressMonitor monitor, IAdaptable uiInfo,
261
			boolean pathIncludesName) throws CoreException {
262
263
		monitor
264
				.beginTask(
265
						UndoMessages.AbstractResourcesOperation_CopyingResourcesProgress,
266
						resources.length);
267
		List overwrittenResources = new ArrayList();
268
		for (int i = 0; i < resources.length; i++) {
269
			IResource source = resources[i];
270
			IPath destinationPath;
271
			if (pathIncludesName) {
272
				destinationPath = destination;
273
			} else {
274
				destinationPath = destination.append(source.getName());
275
			}
276
			IWorkspace workspace = source.getWorkspace();
277
			IWorkspaceRoot workspaceRoot = workspace.getRoot();
278
			IResource existing = workspaceRoot.findMember(destinationPath);
279
			if (source.getType() == IResource.FOLDER && existing != null) {
280
				// The resource is a folder and it exists in the destination.
281
				// Copy its children to the existing destination.
282
				if (homogenousResources(source, existing)) {
283
					IResource[] children = ((IContainer) source).members();
284
					ResourceDescription[] overwritten = copy(children,
285
							destinationPath,
286
							new SubProgressMonitor(monitor, 1), uiInfo, false);
287
					for (int j = 0; j < overwritten.length; j++) {
288
						overwrittenResources.add(overwritten[j]);
289
					}
290
291
				} else {
292
					// delete the destination folder, copying a linked folder
293
					// over an unlinked one or vice versa. Fixes bug 28772.
294
					ResourceDescription[] deleted = delete(
295
							new IResource[] { existing },
296
							new SubProgressMonitor(monitor, 0), uiInfo, false);
297
					source.copy(destinationPath, IResource.SHALLOW,
298
							new SubProgressMonitor(monitor, 1));
299
					for (int j = 0; j < deleted.length; j++) {
300
						overwrittenResources.add(deleted[j]);
301
					}
302
				}
303
			} else {
304
				if (existing != null) {
305
					if (homogenousResources(source, existing)) {
306
						overwrittenResources.add(copyOverExistingResource(
307
								source, existing, new SubProgressMonitor(
308
										monitor, 1), uiInfo, false));
309
					} else {
310
						// Copying a linked resource over unlinked or vice
311
						// versa. Can't use setContents here. Fixes bug 28772.
312
						ResourceDescription[] deleted = delete(
313
								new IResource[] { existing },
314
								new SubProgressMonitor(monitor, 0), uiInfo,
315
								false);
316
						source.copy(destinationPath, IResource.SHALLOW,
317
								new SubProgressMonitor(monitor, 1));
318
						for (int j = 0; j < deleted.length; j++) {
319
							overwrittenResources.add(deleted[j]);
320
						}
321
					}
322
				} else {
323
					// no resources are being overwritten
324
					if (source.getType() == IResource.PROJECT) {
325
						// Get a copy of the current description and modify it
326
						IProjectDescription newDescription = ((IProject) source)
327
								.getDescription();
328
						newDescription.setName(destinationPath.lastSegment());
329
						// If the location is the default then set the location
330
						// to null
331
						IPath projectLocation = destinationPath
332
								.removeLastSegments(1);
333
						if (projectLocation.equals(Platform.getLocation())) {
334
							newDescription.setLocation(null);
335
						} else {
336
							newDescription.setLocation(projectLocation);
337
						}
338
						source.copy(newDescription, IResource.SHALLOW
339
								| IResource.FORCE, monitor);
340
					} else {
341
						// ensure the destination path exists
342
						IPath parentPath = destination;
343
						if (pathIncludesName) {
344
							parentPath = destination.removeLastSegments(1);
345
						}
346
						generateContainers(parentPath);
347
						source.copy(destinationPath, IResource.SHALLOW,
348
								new SubProgressMonitor(monitor, 1));
349
					}
350
				}
351
352
				if (monitor.isCanceled()) {
353
					throw new OperationCanceledException();
354
				}
355
			}
356
		}
357
		return (ResourceDescription[]) overwrittenResources
358
				.toArray(new ResourceDescription[overwrittenResources.size()]);
359
360
	}
361
362
	/*
363
	 * Delete the specified resource, recording enough information about it that
364
	 * it can be restored later. Return a ResourceDescription capable of
365
	 * restoring the resource.
366
	 * 
367
	 * This method is static to ensure "statelessness." Calling instance methods
368
	 * are responsible for maintaining the current state of resources and
369
	 * resource descriptions for the operation.
370
	 */
371
	protected static ResourceDescription delete(IResource resourceToDelete,
372
			IProgressMonitor monitor, IAdaptable uiInfo,
373
			boolean forceOutOfSyncDelete, boolean deleteContent)
374
			throws CoreException {
375
		ResourceDescription resourceDescription = ResourceDescription
376
				.fromResource(resourceToDelete);
377
		if (resourceToDelete.getType() == IResource.PROJECT) {
378
			IProject project = (IProject) resourceToDelete;
379
			project.delete(deleteContent, forceOutOfSyncDelete, monitor);
380
		} else {
381
			// if it's not a project, just delete it
382
			monitor
383
					.beginTask(
384
							UndoMessages.AbstractResourcesOperation_DeleteResourcesProgress,
385
							2);
386
			int updateFlags;
387
			if (forceOutOfSyncDelete) {
388
				updateFlags = IResource.KEEP_HISTORY | IResource.FORCE;
389
			} else {
390
				updateFlags = IResource.KEEP_HISTORY;
391
			}
392
			resourceToDelete.delete(updateFlags, new SubProgressMonitor(
393
					monitor, 1));
394
			resourceDescription.recordLastHistory(resourceToDelete,
395
					new SubProgressMonitor(monitor, 1));
396
			monitor.done();
397
		}
398
399
		return resourceDescription;
400
	}
401
402
	private static ResourceDescription copyOverExistingResource(
403
			IResource source, IResource existing, IProgressMonitor monitor,
404
			IAdaptable uiInfo, boolean deleteSourceFile) throws CoreException {
405
		IFile file = getFile(source);
406
		IFile existingFile = getFile(existing);
407
		monitor
408
				.beginTask(
409
						UndoMessages.AbstractResourcesOperation_CopyingResourcesProgress,
410
						3);
411
		if (file != null && existingFile != null) {
412
			if (validateEdit(file, existingFile, getShell(uiInfo))) {
413
				// Remember the state of the existing file so it can be
414
				// restored.
415
				FileDescription fileDescription = new FileDescription(
416
						existingFile);
417
				// Reset the contents to that of the file being moved
418
				existingFile.setContents(file.getContents(),
419
						IResource.KEEP_HISTORY, new SubProgressMonitor(monitor,
420
								1));
421
				fileDescription.recordLastHistory(existingFile,
422
						new SubProgressMonitor(monitor, 1));
423
				// Now delete the source file if requested
424
				// We don't need to remember anything about it, because
425
				// any undo involving this operation will move the original
426
				// content back to it.
427
				if (deleteSourceFile) {
428
					file.delete(IResource.KEEP_HISTORY, new SubProgressMonitor(
429
							monitor, 1));
430
				}
431
				monitor.done();
432
				return fileDescription;
433
			}
434
		}
435
		monitor.done();
436
		return null;
437
	}
438
439
	/**
440
	 * Returns the resource either casted to or adapted to an IFile.
441
	 * 
442
	 * @param resource
443
	 *            resource to cast/adapt
444
	 * @return the resource either casted to or adapted to an IFile.
445
	 *         <code>null</code> if the resource does not adapt to IFile
446
	 */
447
	private static IFile getFile(IResource resource) {
448
		if (resource instanceof IFile) {
449
			return (IFile) resource;
450
		}
451
		return (IFile) ((IAdaptable) resource).getAdapter(IFile.class);
452
	}
453
454
	/**
455
	 * Check for existence of the specified path and generate any containers
456
	 * that do not yet exist.
457
	 * 
458
	 * @param path
459
	 *            the path describing the container hierarchy to be checked.
460
	 */
461
	private static void generateContainers(IPath path) throws CoreException {
462
		IContainer container;
463
		if (path.segmentCount() == 1) {
464
			container = ResourcesPlugin.getWorkspace().getRoot().getProject(
465
					path.segment(0));
466
		} else {
467
			container = ResourcesPlugin.getWorkspace().getRoot()
468
					.getFolder(path);
469
		}
470
		if (container != null) {
471
			ContainerDescription containerDescription = ContainerDescription
472
					.fromContainer(container);
473
			containerDescription.createExistentResourceFromHandle(container,
474
					new NullProgressMonitor());
475
		}
476
477
	}
478
479
	/**
480
	 * Ask the user whether the given resource should be deleted despite being
481
	 * out of sync with the file system.
482
	 * 
483
	 * @param resource
484
	 *            the out of sync resource
485
	 * @param uiInfo
486
	 *            an adaptable describing the ui info for this operation
487
	 * @return One of the IDialogConstants constants indicating which of the
488
	 *         Yes, Yes to All, No, Cancel options has been selected by the
489
	 *         user.
490
	 */
491
	private static int queryDeleteOutOfSync(IResource resource,
492
			IAdaptable uiInfo) {
493
		Shell shell = getShell(uiInfo);
494
		final MessageDialog dialog = new MessageDialog(
495
				shell,
496
				UndoMessages.AbstractResourcesOperation_deletionMessageTitle,
497
				null,
498
				NLS
499
						.bind(
500
								UndoMessages.AbstractResourcesOperation_outOfSyncQuestion,
501
								resource.getName()), MessageDialog.QUESTION,
502
				new String[] { IDialogConstants.YES_LABEL,
503
						IDialogConstants.YES_TO_ALL_LABEL,
504
						IDialogConstants.NO_LABEL,
505
						IDialogConstants.CANCEL_LABEL }, 0);
506
		shell.getDisplay().syncExec(new Runnable() {
507
			public void run() {
508
				dialog.open();
509
			}
510
		});
511
		int result = dialog.getReturnCode();
512
		if (result == 0) {
513
			return IDialogConstants.YES_ID;
514
		}
515
		if (result == 1) {
516
			return IDialogConstants.YES_TO_ALL_ID;
517
		}
518
		if (result == 2) {
519
			return IDialogConstants.NO_ID;
520
		}
521
		return IDialogConstants.CANCEL_ID;
522
	}
523
524
	/**
525
	 * Creates and returns a result status appropriate for the given list of
526
	 * exceptions.
527
	 * 
528
	 * @param exceptions
529
	 *            The list of exceptions that occurred (may be empty)
530
	 * @return The result status for the deletion
531
	 */
532
	private static IStatus createResult(List exceptions) {
533
		if (exceptions.isEmpty()) {
534
			return Status.OK_STATUS;
535
		}
536
		final int exceptionCount = exceptions.size();
537
		if (exceptionCount == 1) {
538
			return ((CoreException) exceptions.get(0)).getStatus();
539
		}
540
		CoreException[] children = (CoreException[]) exceptions
541
				.toArray(new CoreException[exceptionCount]);
542
		boolean outOfSync = false;
543
		for (int i = 0; i < children.length; i++) {
544
			if (children[i].getStatus().getCode() == IResourceStatus.OUT_OF_SYNC_LOCAL) {
545
				outOfSync = true;
546
				break;
547
			}
548
		}
549
		String title = outOfSync ? UndoMessages.AbstractResourcesOperation_outOfSyncError
550
				: UndoMessages.AbstractResourcesOperation_deletionExceptionMessage;
551
		final MultiStatus multi = new MultiStatus(
552
				IDEWorkbenchPlugin.IDE_WORKBENCH, 0, title, null);
553
		for (int i = 0; i < exceptionCount; i++) {
554
			CoreException exception = children[i];
555
			IStatus status = exception.getStatus();
556
			multi.add(new Status(status.getSeverity(), status.getPlugin(),
557
					status.getCode(), status.getMessage(), exception));
558
		}
559
		return multi;
560
	}
561
562
	/**
563
	 * Validates the destination file if it is read-only and additionally the
564
	 * source file if both are read-only. Returns true if both files could be
565
	 * made writeable.
566
	 * 
567
	 * @param source
568
	 *            source file
569
	 * @param destination
570
	 *            destination file
571
	 * @param shell
572
	 *            ui context for the validation
573
	 * @return boolean <code>true</code> both files could be made writeable.
574
	 *         <code>false</code> either one or both files were not made
575
	 *         writeable
576
	 */
577
	private static boolean validateEdit(IFile source, IFile destination,
578
			Shell shell) {
579
		if (destination.isReadOnly()) {
580
			IWorkspace workspace = source.getWorkspace();
581
			IStatus status;
582
			if (source.isReadOnly()) {
583
				status = workspace.validateEdit(new IFile[] { source,
584
						destination }, shell);
585
			} else {
586
				status = workspace.validateEdit(new IFile[] { destination },
587
						shell);
588
			}
589
			return status.isOK();
590
		}
591
		return true;
592
	}
593
594
	/**
595
	 * Returns whether the given resources are either both linked or both
596
	 * unlinked.
597
	 * 
598
	 * @param source
599
	 *            source resource
600
	 * @param destination
601
	 *            destination resource
602
	 * @return boolean <code>true</code> if both resources are either linked
603
	 *         or unlinked. <code>false</code> otherwise.
604
	 */
605
	private static boolean homogenousResources(IResource source,
606
			IResource destination) {
607
		boolean isSourceLinked = source.isLinked();
608
		boolean isDestinationLinked = destination.isLinked();
609
610
		return (isSourceLinked && isDestinationLinked || isSourceLinked == false
611
				&& isDestinationLinked == false);
612
	}
613
614
	protected ResourceDescription[] resourceDescriptions;
615
616
	/**
617
	 * Create an Abstract Resources Operation
618
	 * 
619
	 * @param resources
620
	 *            the resources to be modified
621
	 * @param label
622
	 *            the label of the operation
623
	 */
624
	AbstractResourcesOperation(IResource[] resources, String label) {
625
		super(label);
626
		this.addContext(WorkspaceUndoSupport.getWorkspaceUndoContext());
627
628
		setTargetResources(resources);
629
	}
630
631
	/**
632
	 * Create an Abstract Resources Operation
633
	 * 
634
	 * @param resourceDescriptions
635
	 *            the resourceDescriptions describing resources to be created
636
	 * @param label
637
	 *            the label of the operation
638
	 */
639
	AbstractResourcesOperation(ResourceDescription[] resourceDescriptions,
640
			String label) {
641
		super(label);
642
		addContext(WorkspaceUndoSupport.getWorkspaceUndoContext());
643
		setResourceDescriptions(resourceDescriptions);
644
	}
645
646
	protected void delete(IProgressMonitor monitor, IAdaptable uiInfo,
647
			boolean deleteContent) throws CoreException {
648
		setResourceDescriptions(AbstractResourcesOperation.delete(resources,
649
				monitor, uiInfo, deleteContent));
650
		setTargetResources(new IResource[0]);
651
	}
652
653
	protected void recreate(IProgressMonitor monitor, IAdaptable uiInfo)
654
			throws CoreException {
655
		setTargetResources(AbstractResourcesOperation.recreate(
656
				resourceDescriptions, monitor, uiInfo));
657
		setResourceDescriptions(new ResourceDescription[0]);
658
	}
659
660
	/*
661
	 * Compute the status for creating resources from the descriptions.
662
	 * 
663
	 * Note this method may be called on initial creation of a resource, or when
664
	 * a create or delete operation is being undone or redone. Therefore, this
665
	 * method should check conditions that can change over the life of the
666
	 * operation, such as the existence of the information needed to carry out
667
	 * the operation. One-time static checks should typically be done by the
668
	 * caller (such as the action that creates the operation) so that the user
669
	 * is not continually prompted or warned about conditions that were
670
	 * acceptable at the time of original execution.
671
	 */
672
	protected IStatus computeCreateStatus() {
673
		if (resourceDescriptions == null || resourceDescriptions.length == 0) {
674
			markInvalid();
675
			return getErrorStatus(UndoMessages.AbstractResourcesOperation_NotEnoughInfo);
676
		}
677
		for (int i = 0; i < resourceDescriptions.length; i++) {
678
			if (!resourceDescriptions[i].isValid()) {
679
				markInvalid();
680
				return getErrorStatus(UndoMessages.AbstractResourcesOperation_InvalidRestoreInfo);
681
			}
682
		}
683
		return Status.OK_STATUS;
684
	}
685
686
	/*
687
	 * Compute the status for deleting resources.
688
	 * 
689
	 * Note this method may be called on initial deletion of a resource, or when
690
	 * a create or delete operation is being undone or redone. Therefore, this
691
	 * method should check conditions that can change over the life of the
692
	 * operation, such as the existence of the resources to be deleted. One-time
693
	 * static checks should typically be done by the caller (such as the action
694
	 * that creates the operation) so that the user is not continually prompted
695
	 * or warned about conditions that were acceptable at the time of original
696
	 * execution.
697
	 */
698
699
	protected IStatus computeDeleteStatus() {
700
		if (resources == null || resources.length == 0) {
701
			markInvalid();
702
			return getErrorStatus(UndoMessages.AbstractResourcesOperation_NotEnoughInfo);
703
		}
704
		if (!resourcesExist()) {
705
			markInvalid();
706
			return getErrorStatus(UndoMessages.AbstractResourcesOperation_ResourcesDoNotExist);
707
		}
708
		return Status.OK_STATUS;
709
	}
710
711
	/**
712
	 * Ask the user whether the given resource should be overwritten.
713
	 * 
714
	 * @param resource
715
	 *            the resource to be overwritten
716
	 * @param uiInfo
717
	 *            an adaptable describing the ui info for this operation
718
	 * @return One of the IDialogConstants constants indicating which of the
719
	 *         Yes, Yes to All, No, Cancel options has been selected by the
720
	 *         user.
721
	 */
722
	protected int queryOverwrite(IResource resource, IAdaptable uiInfo) {
723
		Shell shell = getShell(uiInfo);
724
		final MessageDialog dialog = new MessageDialog(
725
				shell,
726
				UndoMessages.AbstractResourcesOperation_overwriteTitle,
727
				null,
728
				NLS
729
						.bind(
730
								UndoMessages.AbstractResourcesOperation_overwriteQuestion,
731
								resource.getName()), MessageDialog.QUESTION,
732
				new String[] { IDialogConstants.YES_LABEL,
733
						IDialogConstants.YES_TO_ALL_LABEL,
734
						IDialogConstants.NO_LABEL,
735
						IDialogConstants.CANCEL_LABEL }, 0);
736
		shell.getDisplay().syncExec(new Runnable() {
737
			public void run() {
738
				dialog.open();
739
			}
740
		});
741
		int result = dialog.getReturnCode();
742
		if (result == 0) {
743
			return IDialogConstants.YES_ID;
744
		}
745
		if (result == 1) {
746
			return IDialogConstants.YES_TO_ALL_ID;
747
		}
748
		if (result == 2) {
749
			return IDialogConstants.NO_ID;
750
		}
751
		return IDialogConstants.CANCEL_ID;
752
	}
753
754
	/*
755
	 * Set the array of resource descriptions describing resources to be
756
	 * restored when undoing or redoing this operation.
757
	 */
758
	protected void setResourceDescriptions(ResourceDescription[] descriptions) {
759
		if (descriptions == null) {
760
			resourceDescriptions = new ResourceDescription[0];
761
		} else {
762
			resourceDescriptions = descriptions;
763
		}
764
	}
765
}
(-)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
		setResourceDescriptions(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/internal/ide/undo/ProjectDescription.java (+94 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
	public void createExistentResourceFromHandle(IResource resource,
68
			IProgressMonitor monitor) throws CoreException {
69
		Assert.isLegal(resource instanceof IProject);
70
		if (resource.exists()) {
71
			return;
72
		}
73
		IProject projectHandle = (IProject) resource;
74
		monitor.beginTask(UndoMessages.ProjectDescription_NewProjectProgress,
75
				200);
76
		if (projectDescription == null) {
77
			projectHandle.create(new SubProgressMonitor(monitor, 100));
78
		} else {
79
			projectHandle.create(projectDescription, new SubProgressMonitor(
80
					monitor, 100));
81
		}
82
83
		if (monitor.isCanceled()) {
84
			throw new OperationCanceledException();
85
		}
86
		projectHandle.open(IResource.BACKGROUND_REFRESH,
87
				new SubProgressMonitor(monitor, 100));
88
		monitor.done();
89
	}
90
91
	public String getName() {
92
		return projectDescription.getName();
93
	}
94
}
(-)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/ide/undo/CopyResourcesOperation.java (+195 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.SubProgressMonitor;
22
import org.eclipse.ui.internal.ide.undo.ResourceDescription;
23
import org.eclipse.ui.internal.ide.undo.UndoMessages;
24
25
/**
26
 * A CopyResourcesOperation represents an undoable operation for copying 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 CopyResourcesOperation extends
40
		AbstractCopyOrMoveResourcesOperation {
41
42
	IResource[] originalResources;
43
44
	IPath[] originalDestinationPaths = null;
45
46
	IPath originalDestination = null;
47
48
	/**
49
	 * Create a CopyResourcesOperation that copies a single resource to a new
50
	 * location. The new location includes the name of the copy.
51
	 * 
52
	 * @param resource
53
	 *            the resource to be moved
54
	 * @param newPath
55
	 *            the new path for the resource, including its desired name.
56
	 * @param label
57
	 *            the label of the operation
58
	 */
59
	public CopyResourcesOperation(IResource resource, IPath newPath,
60
			String label) {
61
		super(new IResource[] { resource }, new IPath[] { newPath }, label);
62
		originalResources = new IResource[] { resource };
63
		originalDestinationPaths = new IPath[] { newPath };
64
	}
65
66
	/**
67
	 * Create a CopyResourcesOperation that copies all of the specified
68
	 * resources to a single target location. The original resource name will be
69
	 * used when copied to the new location.
70
	 * 
71
	 * @param resources
72
	 *            the resources to be copied
73
	 * @param destinationPath
74
	 *            the destination path for the copied resource.
75
	 * @param label
76
	 *            the label of the operation
77
	 */
78
	public CopyResourcesOperation(IResource[] resources, IPath destinationPath,
79
			String label) {
80
		super(resources, destinationPath, label);
81
		originalResources = resources;
82
		originalDestination = destinationPath;
83
	}
84
85
	/**
86
	 * Create a CopyResourcesOperation that copies each of the specified
87
	 * resources to its corresponding destination path in the destination path
88
	 * array. The resource name for the target is included in the corresponding
89
	 * destination path.
90
	 * 
91
	 * @param resources
92
	 *            the resources to be copied
93
	 * @param destinationPaths
94
	 *            a destination path for each copied resource, which includes
95
	 *            the name of the resource at the new destination
96
	 * @param label
97
	 *            the label of the operation
98
	 */
99
	public CopyResourcesOperation(IResource[] resources,
100
			IPath[] destinationPaths, String label) {
101
		super(resources, destinationPaths, label);
102
		originalResources = resources;
103
		// the destination array must be copied so it will be remembered.
104
		// move and copy operations update the original array.
105
		originalDestinationPaths = new IPath[destinationPaths.length];
106
		System.arraycopy(destinationPaths, 0, originalDestinationPaths, 0,
107
				destinationPaths.length);
108
	}
109
110
	protected void doExecute(IProgressMonitor monitor, IAdaptable uiInfo)
111
			throws CoreException {
112
		moveOrCopy(monitor, uiInfo, false); // false = copy
113
	}
114
115
	protected void doUndo(IProgressMonitor monitor, IAdaptable uiInfo)
116
			throws CoreException {
117
		monitor
118
				.beginTask(
119
						UndoMessages.AbstractResourcesOperation_CopyingResourcesProgress,
120
						2);
121
		// undoing a copy is first deleting the copied resources...
122
		AbstractResourcesOperation.delete(resources, new SubProgressMonitor(
123
				monitor, 1), uiInfo, true);
124
		// then restoring any overwritten by the previous copy...
125
		AbstractResourcesOperation.recreate(resourceDescriptions,
126
				new SubProgressMonitor(monitor, 1), uiInfo);
127
		setResourceDescriptions(new ResourceDescription[0]);
128
		// then setting the target resources and destination paths
129
		// back to the original ones
130
		setTargetResources(originalResources);
131
		if (originalDestination != null) {
132
			destination = originalDestination;
133
			destinationPaths = null;
134
		} else {
135
			destination = null;
136
			destinationPaths = originalDestinationPaths;
137
		}
138
		monitor.done();
139
	}
140
141
	protected boolean updateResourceChangeDescriptionFactory(
142
			IResourceChangeDescriptionFactory factory, int operation) {
143
		boolean update = false;
144
		if (operation == UNDO) {
145
			for (int i = 0; i < resources.length; i++) {
146
				update = true;
147
				IResource resource = resources[i];
148
				factory.delete(resource);
149
			}
150
			for (int i = 0; i < resourceDescriptions.length; i++) {
151
				update = true;
152
				IResource resource = resourceDescriptions[i].createResourceHandle();
153
				factory.create(resource);
154
			}
155
		} else {
156
			for (int i = 0; i < resources.length; i++) {
157
				update = true;
158
				IResource resource = resources[i];
159
				factory.copy(resource, getDestinationPath(resource, i, false));
160
			}
161
		}
162
		return update;
163
	}
164
165
	public IStatus computeExecutionStatus(IProgressMonitor monitor) {
166
		IStatus status = super.computeExecutionStatus(monitor);
167
		if (status.isOK()) {
168
			status = computeMoveOrCopyStatus();
169
		}
170
		return status;
171
	}
172
173
	public IStatus computeUndoableStatus(IProgressMonitor monitor) {
174
		IStatus status = super.computeUndoableStatus(monitor);
175
		// undoing a copy means deleting the copy that was made
176
		if (status.isOK()) {
177
			status = computeDeleteStatus();
178
		}
179
		// and if there were resources overwritten by the copy, can we still
180
		// recreate them?
181
		if (status.isOK() && resourceDescriptions != null
182
				&& resourceDescriptions.length > 0) {
183
			status = computeCreateStatus();
184
		}
185
		return status;
186
	}
187
188
	public IStatus computeRedoableStatus(IProgressMonitor monitor) {
189
		IStatus status = super.computeRedoableStatus(monitor);
190
		if (status.isOK()) {
191
			status = computeMoveOrCopyStatus();
192
		}
193
		return status;
194
	}
195
}

Return to bug 123674