001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.actions;
011:
012: import java.lang.reflect.InvocationTargetException;
013: import java.net.URI;
014: import java.util.List;
015:
016: import org.eclipse.core.commands.ExecutionException;
017: import org.eclipse.core.filesystem.URIUtil;
018: import org.eclipse.core.resources.IProject;
019: import org.eclipse.core.resources.IProjectDescription;
020: import org.eclipse.core.resources.IResource;
021: import org.eclipse.core.runtime.CoreException;
022: import org.eclipse.core.runtime.IPath;
023: import org.eclipse.core.runtime.IProgressMonitor;
024: import org.eclipse.core.runtime.IStatus;
025: import org.eclipse.core.runtime.Platform;
026: import org.eclipse.jface.dialogs.ErrorDialog;
027: import org.eclipse.jface.dialogs.MessageDialog;
028: import org.eclipse.jface.operation.IRunnableWithProgress;
029: import org.eclipse.jface.viewers.IStructuredSelection;
030: import org.eclipse.osgi.util.NLS;
031: import org.eclipse.swt.widgets.Shell;
032: import org.eclipse.ui.PlatformUI;
033: import org.eclipse.ui.dialogs.ProjectLocationSelectionDialog;
034: import org.eclipse.ui.ide.undo.WorkspaceUndoUtil;
035: import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
036: import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
037: import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
038: import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;
039: import org.eclipse.ui.plugin.AbstractUIPlugin;
040:
041: /**
042: * The CopyProjectAction is the action designed to copy projects specifically as
043: * they have different semantics from other resources. Note that this action
044: * assumes that a single project is selected and being manipulated. This should
045: * be disabled for multi select or no selection.
046: */
047: public class CopyProjectAction extends SelectionListenerAction {
048: private static String COPY_TOOL_TIP = IDEWorkbenchMessages.CopyProjectAction_toolTip;
049:
050: private static String COPY_TITLE = IDEWorkbenchMessages.CopyProjectAction_title;
051:
052: private static String PROBLEMS_TITLE = IDEWorkbenchMessages.CopyProjectAction_copyFailedTitle;
053:
054: /**
055: * The id of this action.
056: */
057: public static final String ID = PlatformUI.PLUGIN_ID
058: + ".CopyProjectAction";//$NON-NLS-1$
059:
060: /**
061: * The shell in which to show any dialogs.
062: */
063: protected Shell shell;
064:
065: /**
066: * Status containing the errors detected when running the operation or
067: * <code>null</code> if no errors detected.
068: */
069: protected IStatus errorStatus;
070:
071: private String[] modelProviderIds;
072:
073: /**
074: * Creates a new project copy action with the default text.
075: *
076: * @param shell
077: * the shell for any dialogs
078: */
079: public CopyProjectAction(Shell shell) {
080: this (shell, COPY_TITLE);
081: PlatformUI.getWorkbench().getHelpSystem().setHelp(this ,
082: IIDEHelpContextIds.COPY_PROJECT_ACTION);
083: }
084:
085: /**
086: * Creates a new project copy action with the given text.
087: *
088: * @param shell
089: * the shell for any dialogs
090: * @param name
091: * the string used as the text for the action, or
092: * <code>null</code> if there is no text
093: */
094: CopyProjectAction(Shell shell, String name) {
095: super (name);
096: setToolTipText(COPY_TOOL_TIP);
097: setId(CopyProjectAction.ID);
098: if (shell == null) {
099: throw new IllegalArgumentException();
100: }
101: this .shell = shell;
102: }
103:
104: /**
105: * Create a new IProjectDescription for the copy using the name and path
106: * selected from the dialog.
107: *
108: * @return IProjectDescription
109: * @param project
110: * the source project
111: * @param projectName
112: * the name for the new project
113: * @param rootLocation
114: * the path the new project will be stored under.
115: */
116: protected IProjectDescription createDescription(IProject project,
117: String projectName, IPath rootLocation)
118: throws CoreException {
119: // Get a copy of the current description and modify it
120: IProjectDescription newDescription = project.getDescription();
121: newDescription.setName(projectName);
122:
123: // If the location is the default then set the location to null
124: if (rootLocation.equals(Platform.getLocation())) {
125: newDescription.setLocation(null);
126: } else {
127: newDescription.setLocation(rootLocation);
128: }
129:
130: return newDescription;
131: }
132:
133: /**
134: * Opens an error dialog to display the given message.
135: * <p>
136: * Note that this method must be called from UI thread.
137: * </p>
138: *
139: * @param message
140: * the message
141: */
142: void displayError(String message) {
143: MessageDialog.openError(this .shell, getErrorsTitle(), message);
144: }
145:
146: /**
147: * Return the title of the errors dialog.
148: *
149: * @return java.lang.String
150: *
151: * @deprecated As of 3.3, the undoable operation created by this action
152: * handles error dialogs.
153: */
154: protected String getErrorsTitle() {
155: return PROBLEMS_TITLE;
156: }
157:
158: /**
159: * Get the plugin used by a copy action
160: *
161: * @return AbstractUIPlugin
162: */
163: protected org.eclipse.ui.plugin.AbstractUIPlugin getPlugin() {
164: return (AbstractUIPlugin) Platform
165: .getPlugin(PlatformUI.PLUGIN_ID);
166: }
167:
168: /**
169: * Copies the project to the new values.
170: *
171: * @param project
172: * the project to copy
173: * @param projectName
174: * the name of the copy
175: * @param newLocation
176: * URI
177: * @return <code>true</code> if the copy operation completed, and
178: * <code>false</code> if it was abandoned part way
179: */
180: boolean performCopy(final IProject project,
181: final String projectName, final URI newLocation) {
182: IRunnableWithProgress op = new IRunnableWithProgress() {
183: public void run(IProgressMonitor monitor) {
184: org.eclipse.ui.ide.undo.CopyProjectOperation op = new org.eclipse.ui.ide.undo.CopyProjectOperation(
185: project, projectName, newLocation, getText());
186: op.setModelProviderIds(getModelProviderIds());
187: try {
188: PlatformUI.getWorkbench().getOperationSupport()
189: .getOperationHistory().execute(
190: op,
191: monitor,
192: WorkspaceUndoUtil
193: .getUIInfoAdapter(shell));
194: } catch (ExecutionException e) {
195: if (e.getCause() instanceof CoreException) {
196: recordError((CoreException) e.getCause());
197: } else {
198: IDEWorkbenchPlugin.log(e.getMessage(), e);
199: displayError(e.getMessage());
200: }
201: }
202: }
203: };
204:
205: try {
206: new ProgressMonitorJobsDialog(shell).run(true, true, op);
207: } catch (InterruptedException e) {
208: return false;
209: } catch (InvocationTargetException e) {
210: displayError(NLS
211: .bind(
212: IDEWorkbenchMessages.CopyProjectAction_internalError,
213: e.getTargetException().getMessage()));
214: return false;
215: }
216:
217: return true;
218: }
219:
220: /**
221: * Query for a new project name and destination using the parameters in the
222: * existing project.
223: *
224: * @return Object [] or null if the selection is cancelled
225: * @param project
226: * the project we are going to copy.
227: */
228: protected Object[] queryDestinationParameters(IProject project) {
229: ProjectLocationSelectionDialog dialog = new ProjectLocationSelectionDialog(
230: shell, project);
231: dialog
232: .setTitle(IDEWorkbenchMessages.CopyProjectAction_copyTitle);
233: dialog.open();
234: return dialog.getResult();
235: }
236:
237: /**
238: * Records the core exception to be displayed to the user once the action is
239: * finished.
240: *
241: * @param error
242: * a <code>CoreException</code>
243: */
244: final void recordError(CoreException error) {
245: this .errorStatus = error.getStatus();
246: }
247:
248: /**
249: * Implementation of method defined on <code>IAction</code>.
250: */
251: public void run() {
252:
253: errorStatus = null;
254:
255: IProject project = (IProject) getSelectedResources().get(0);
256:
257: // Get the project name and location in a two element list
258: Object[] destinationPaths = queryDestinationParameters(project);
259: if (destinationPaths == null) {
260: return;
261: }
262:
263: String newName = (String) destinationPaths[0];
264: URI newLocation = URIUtil.toURI((String) destinationPaths[1]);
265:
266: boolean completed = performCopy(project, newName, newLocation);
267:
268: if (!completed) {
269: return; // not appropriate to show errors
270: }
271:
272: // If errors occurred, open an Error dialog
273: if (errorStatus != null) {
274: ErrorDialog.openError(this .shell, getErrorsTitle(), null,
275: errorStatus);
276: errorStatus = null;
277: }
278: }
279:
280: /**
281: * The <code>CopyResourceAction</code> implementation of this
282: * <code>SelectionListenerAction</code> method enables this action only if
283: * there is a single selection which is a project.
284: */
285: protected boolean updateSelection(IStructuredSelection selection) {
286: if (!super .updateSelection(selection)) {
287: return false;
288: }
289: if (getSelectedNonResources().size() > 0) {
290: return false;
291: }
292:
293: // to enable this command there must be one project selected and nothing
294: // else
295: List selectedResources = getSelectedResources();
296: if (selectedResources.size() != 1) {
297: return false;
298: }
299: IResource source = (IResource) selectedResources.get(0);
300: if (source instanceof IProject && ((IProject) source).isOpen()) {
301: return true;
302: }
303: return false;
304: }
305:
306: /**
307: * Returns the model provider ids that are known to the client that
308: * instantiated this operation.
309: *
310: * @return the model provider ids that are known to the client that
311: * instantiated this operation.
312: * @since 3.2
313: */
314: public String[] getModelProviderIds() {
315: return modelProviderIds;
316: }
317:
318: /**
319: * Sets the model provider ids that are known to the client that
320: * instantiated this operation. Any potential side effects reported by these
321: * models during validation will be ignored.
322: *
323: * @param modelProviderIds
324: * the model providers known to the client who is using this
325: * operation.
326: * @since 3.2
327: */
328: public void setModelProviderIds(String[] modelProviderIds) {
329: this.modelProviderIds = modelProviderIds;
330: }
331: }
|