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.util.Iterator;
013: import java.util.List;
014:
015: import org.eclipse.core.resources.IContainer;
016: import org.eclipse.core.resources.IResource;
017: import org.eclipse.core.resources.IWorkspace;
018: import org.eclipse.core.resources.IWorkspaceRoot;
019: import org.eclipse.core.runtime.IPath;
020: import org.eclipse.jface.viewers.IStructuredSelection;
021: import org.eclipse.swt.widgets.Shell;
022: import org.eclipse.ui.PlatformUI;
023: import org.eclipse.ui.dialogs.ContainerSelectionDialog;
024: import org.eclipse.ui.dialogs.ISelectionValidator;
025: import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
026: import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
027: import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
028:
029: /**
030: * Standard action for copying the currently selected resources elsewhere
031: * in the workspace. All resources being copied as a group must be siblings.
032: * <p>
033: * This class may be instantiated; it is not intended to be subclassed.
034: * </p>
035: */
036: public class CopyResourceAction extends SelectionListenerAction
037: implements ISelectionValidator {
038:
039: /**
040: * The id of this action.
041: */
042: public static final String ID = PlatformUI.PLUGIN_ID
043: + ".CopyResourceAction"; //$NON-NLS-1$
044:
045: /**
046: * The shell in which to show any dialogs.
047: */
048: private Shell shell;
049:
050: /**
051: * The operation to run. This is created only during the life-cycle of the
052: * run method.
053: */
054: protected CopyFilesAndFoldersOperation operation;
055:
056: private String[] modelProviderIds;
057:
058: /**
059: * Returns a new name for a copy of the resource at the given path in the given
060: * workspace. This name could be determined either automatically or by querying
061: * the user. This name will <b>not</b> be verified by the caller, so it must be
062: * valid and unique.
063: * <p>
064: * Note this method is for internal use only.
065: * </p>
066: *
067: * @param originalName the full path of the resource
068: * @param workspace the workspace
069: * @return the new full path for the copy, or <code>null</code> if the resource
070: * should not be copied
071: */
072: public static IPath getNewNameFor(IPath originalName,
073: IWorkspace workspace) {
074: return CopyFilesAndFoldersOperation.getAutoNewNameFor(
075: originalName, workspace);
076: }
077:
078: /**
079: * Creates a new action.
080: *
081: * @param shell the shell for any dialogs
082: */
083: public CopyResourceAction(Shell shell) {
084: this (shell, IDEWorkbenchMessages.CopyResourceAction_title);
085: PlatformUI.getWorkbench().getHelpSystem().setHelp(this ,
086: IIDEHelpContextIds.COPY_RESOURCE_ACTION);
087: }
088:
089: /**
090: * Creates a new action with the given text.
091: *
092: * @param shell the shell for any dialogs
093: * @param name the string used as the name for the action,
094: * or <code>null</code> if there is no name
095: */
096: CopyResourceAction(Shell shell, String name) {
097: super (name);
098: setToolTipText(IDEWorkbenchMessages.CopyResourceAction_toolTip);
099: setId(CopyResourceAction.ID);
100: if (shell == null) {
101: throw new IllegalArgumentException();
102: }
103: this .shell = shell;
104: }
105:
106: /**
107: * Returns the operation to perform when this action runs.
108: *
109: * @return the operation to perform when this action runs.
110: */
111: protected CopyFilesAndFoldersOperation createOperation() {
112: return new CopyFilesAndFoldersOperation(getShell());
113: }
114:
115: /**
116: * Returns the path of the container to initially select in the container
117: * selection dialog, or <code>null</code> if there is no initial selection
118: * @return The initial container; <code>null</code> if none.
119: */
120: IContainer getInitialContainer() {
121: List resources = getSelectedResources();
122: if (resources.size() > 0) {
123: IResource resource = (IResource) resources.get(0);
124: return resource.getParent();
125: }
126: return null;
127: }
128:
129: /**
130: * Returns an array of resources to use for the operation from
131: * the provided list.
132: *
133: * @param resourceList The list of resources to converted into an array.
134: * @return an array of resources to use for the operation
135: */
136: protected IResource[] getResources(List resourceList) {
137: return (IResource[]) resourceList
138: .toArray(new IResource[resourceList.size()]);
139: }
140:
141: /**
142: * Returns the shell in which to show any dialogs
143: * @return The shell for parenting dialogs; never <code>null</code>.
144: */
145: Shell getShell() {
146: return shell;
147: }
148:
149: /**
150: * The <code>CopyResourceAction</code> implementation of this
151: * <code>ISelectionValidator</code> method checks whether the given path
152: * is a good place to copy the selected resources.
153: */
154: public String isValid(Object destination) {
155: IWorkspaceRoot root = IDEWorkbenchPlugin.getPluginWorkspace()
156: .getRoot();
157: IContainer container = (IContainer) root
158: .findMember((IPath) destination);
159:
160: if (container != null) {
161: // create a new operation here.
162: // isValid is API and may be called in any context.
163: CopyFilesAndFoldersOperation newOperation = createOperation();
164: List sources = getSelectedResources();
165: IResource[] resources = (IResource[]) sources
166: .toArray(new IResource[sources.size()]);
167: return newOperation.validateDestination(container,
168: resources);
169: }
170: return null;
171: }
172:
173: /**
174: * Asks the user for the destination of this action.
175: *
176: * @return the path on an existing or new resource container, or
177: * <code>null</code> if the operation should be abandoned
178: */
179: IPath queryDestinationResource() {
180: // start traversal at root resource, should probably start at a
181: // better location in the tree
182: ContainerSelectionDialog dialog = new ContainerSelectionDialog(
183: shell,
184: getInitialContainer(),
185: true,
186: IDEWorkbenchMessages.CopyResourceAction_selectDestination);
187: dialog.setValidator(this );
188: dialog.showClosedProjects(false);
189: dialog.open();
190: Object[] result = dialog.getResult();
191: if (result != null && result.length == 1) {
192: return (IPath) result[0];
193: }
194: return null;
195: }
196:
197: /* (non-Javadoc)
198: * Method declared on IAction.
199: */
200: public void run() {
201: try {
202: operation = createOperation();
203: operation.setModelProviderIds(getModelProviderIds());
204:
205: // WARNING: do not query the selected resources more than once
206: // since the selection may change during the run,
207: // e.g. due to window activation when the prompt dialog is dismissed.
208: // For more details, see Bug 60606 [Navigator] (data loss) Navigator deletes/moves the wrong file
209: List sources = getSelectedResources();
210:
211: IPath destination = queryDestinationResource();
212: if (destination == null) {
213: return;
214: }
215:
216: IWorkspaceRoot root = IDEWorkbenchPlugin
217: .getPluginWorkspace().getRoot();
218: IContainer container = (IContainer) root
219: .findMember(destination);
220: if (container == null) {
221: return;
222: }
223:
224: runOperation(getResources(sources), container);
225: } finally {
226: operation = null;
227: }
228: }
229:
230: /**
231: * Runs the operation created in <code>createOperaiton</code>
232: *
233: * @param resources source resources to pass to the operation
234: * @param destination destination container to pass to the operation
235: */
236: protected void runOperation(IResource[] resources,
237: IContainer destination) {
238: operation.copyResources(resources, destination);
239: }
240:
241: /**
242: * The <code>CopyResourceAction</code> implementation of this
243: * <code>SelectionListenerAction</code> method enables this action only if
244: * all of the one or more selections are sibling resources which are
245: * local (depth infinity).
246: */
247: protected boolean updateSelection(IStructuredSelection selection) {
248: if (!super .updateSelection(selection)) {
249: return false;
250: }
251: if (getSelectedNonResources().size() > 0) {
252: return false;
253: }
254:
255: // to enable this command all selected resources must be siblings
256: List selectedResources = getSelectedResources();
257: if (selectedResources.size() == 0) {
258: return false;
259: }
260: IContainer firstParent = ((IResource) selectedResources.get(0))
261: .getParent();
262: if (firstParent == null) {
263: return false;
264: }
265: Iterator resourcesEnum = selectedResources.iterator();
266: while (resourcesEnum.hasNext()) {
267: IResource currentResource = (IResource) resourcesEnum
268: .next();
269: if (!currentResource.exists()) {
270: return false;
271: }
272: if (currentResource.getType() == IResource.PROJECT) {
273: return false;
274: }
275: IContainer parent = currentResource.getParent();
276: if ((parent != null) && (!parent.equals(firstParent))) {
277: return false;
278: }
279: }
280: return true;
281: }
282:
283: /**
284: * Returns the model provider ids that are known to the client
285: * that instantiated this operation.
286: *
287: * @return the model provider ids that are known to the client
288: * that instantiated this operation.
289: * @since 3.2
290: */
291: public String[] getModelProviderIds() {
292: return modelProviderIds;
293: }
294:
295: /**
296: * Sets the model provider ids that are known to the client
297: * that instantiated this operation. Any potential side effects
298: * reported by these models during validation will be ignored.
299: *
300: * @param modelProviderIds the model providers known to the client
301: * who is using this operation.
302: * @since 3.2
303: */
304: public void setModelProviderIds(String[] modelProviderIds) {
305: this.modelProviderIds = modelProviderIds;
306: }
307: }
|