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 org.eclipse.core.resources.IContainer;
013: import org.eclipse.core.resources.IFile;
014: import org.eclipse.core.resources.IResource;
015: import org.eclipse.core.resources.IWorkspace;
016: import org.eclipse.core.resources.IWorkspaceRoot;
017: import org.eclipse.core.runtime.CoreException;
018: import org.eclipse.core.runtime.IPath;
019: import org.eclipse.core.runtime.IProgressMonitor;
020: import org.eclipse.core.runtime.OperationCanceledException;
021: import org.eclipse.core.runtime.SubProgressMonitor;
022: import org.eclipse.osgi.util.NLS;
023: import org.eclipse.swt.widgets.Shell;
024: import org.eclipse.ui.ide.undo.AbstractWorkspaceOperation;
025: import org.eclipse.ui.ide.undo.MoveResourcesOperation;
026: import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
027:
028: /**
029: * Moves files and folders.
030: * <p>
031: * This class may be instantiated; it is not intended to be subclassed.
032: * </p>
033: *
034: * @since 2.1
035: */
036: public class MoveFilesAndFoldersOperation extends
037: CopyFilesAndFoldersOperation {
038:
039: /**
040: * Creates a new operation initialized with a shell.
041: *
042: * @param shell
043: * parent shell for error dialogs
044: */
045: public MoveFilesAndFoldersOperation(Shell shell) {
046: super (shell);
047: }
048:
049: /**
050: * Returns whether this operation is able to perform on-the-fly
051: * auto-renaming of resources with name collisions.
052: *
053: * @return <code>true</code> if auto-rename is supported, and
054: * <code>false</code> otherwise
055: */
056: protected boolean canPerformAutoRename() {
057: return false;
058: }
059:
060: /**
061: * Moves the resources to the given destination. This method is called
062: * recursively to merge folders during folder move.
063: *
064: * @param resources
065: * the resources to move
066: * @param destination
067: * destination to which resources will be moved
068: * @param subMonitor
069: * a progress monitor for showing progress and for cancelation
070: *
071: * @deprecated As of 3.3, the work is performed in the undoable operation
072: * created in
073: * {@link #getUndoableCopyOrMoveOperation(IResource[], IPath)}
074: */
075: protected void copy(IResource[] resources, IPath destination,
076: IProgressMonitor subMonitor) throws CoreException {
077: for (int i = 0; i < resources.length; i++) {
078: IResource source = resources[i];
079: IPath destinationPath = destination
080: .append(source.getName());
081: IWorkspace workspace = source.getWorkspace();
082: IWorkspaceRoot workspaceRoot = workspace.getRoot();
083: IResource existing = workspaceRoot
084: .findMember(destinationPath);
085: if (source.getType() == IResource.FOLDER
086: && existing != null) {
087: // the resource is a folder and it exists in the destination,
088: // move the children of the folder.
089: if (homogenousResources(source, existing)) {
090: IResource[] children = ((IContainer) source)
091: .members();
092: copy(children, destinationPath, subMonitor);
093: delete(source, subMonitor);
094: } else {
095: // delete the destination folder, moving a linked folder
096: // over an unlinked one or vice versa. Fixes bug 28772.
097: delete(existing, new SubProgressMonitor(subMonitor,
098: 0));
099: source.move(destinationPath, IResource.SHALLOW
100: | IResource.KEEP_HISTORY,
101: new SubProgressMonitor(subMonitor, 0));
102: }
103: } else {
104: // if we're merging folders, we could be overwriting an existing
105: // file
106: if (existing != null) {
107: if (homogenousResources(source, existing)) {
108: moveExisting(source, existing, subMonitor);
109: } else {
110: // Moving a linked resource over unlinked or vice versa.
111: // Can't use setContents here. Fixes bug 28772.
112: delete(existing, new SubProgressMonitor(
113: subMonitor, 0));
114: source.move(destinationPath, IResource.SHALLOW
115: | IResource.KEEP_HISTORY,
116: new SubProgressMonitor(subMonitor, 0));
117: }
118: } else {
119: source.move(destinationPath, IResource.SHALLOW
120: | IResource.KEEP_HISTORY,
121: new SubProgressMonitor(subMonitor, 0));
122: }
123: subMonitor.worked(1);
124: if (subMonitor.isCanceled()) {
125: throw new OperationCanceledException();
126: }
127: }
128: }
129: }
130:
131: /**
132: * Returns the message for querying deep copy/move of a linked resource.
133: *
134: * @param source
135: * resource the query is made for
136: * @return the deep query message
137: */
138: protected String getDeepCheckQuestion(IResource source) {
139: return NLS
140: .bind(
141: IDEWorkbenchMessages.CopyFilesAndFoldersOperation_deepMoveQuestion,
142: source.getFullPath().makeRelative());
143: }
144:
145: /**
146: * Returns the task title for this operation's progress dialog.
147: *
148: * @return the task title
149: */
150: protected String getOperationTitle() {
151: return IDEWorkbenchMessages.MoveFilesAndFoldersOperation_operationTitle;
152: }
153:
154: /**
155: * Returns the message for this operation's problems dialog.
156: *
157: * @return the problems message
158: */
159: protected String getProblemsMessage() {
160: return IDEWorkbenchMessages.MoveFilesAndFoldersOperation_problemMessage;
161: }
162:
163: /**
164: * Returns the title for this operation's problems dialog.
165: *
166: * @return the problems dialog title
167: */
168: protected String getProblemsTitle() {
169: return IDEWorkbenchMessages.MoveFilesAndFoldersOperation_moveFailedTitle;
170: }
171:
172: /**
173: * Returns whether the source file in a destination collision will be
174: * validateEdited together with the collision itself. Returns true.
175: *
176: * @return boolean <code>true</code>, the source file in a destination
177: * collision should be validateEdited.
178: */
179: protected boolean getValidateConflictSource() {
180: return true;
181: }
182:
183: /**
184: * Sets the content of the existing file to the source file content. Deletes
185: * the source file.
186: *
187: * @param source
188: * source file to move
189: * @param existing
190: * existing file to set the source content in
191: * @param subMonitor
192: * a progress monitor for showing progress and for cancelation
193: * @throws CoreException
194: * setContents failed
195: * @deprecated As of 3.3, this method is not called.
196: */
197: private void moveExisting(IResource source, IResource existing,
198: IProgressMonitor subMonitor) throws CoreException {
199: IFile existingFile = getFile(existing);
200:
201: if (existingFile != null) {
202: IFile sourceFile = getFile(source);
203:
204: if (sourceFile != null) {
205: existingFile.setContents(sourceFile.getContents(),
206: IResource.KEEP_HISTORY, new SubProgressMonitor(
207: subMonitor, 0));
208: delete(sourceFile, subMonitor);
209: }
210: }
211: }
212:
213: /*
214: * (non-Javadoc) Overrides method in CopyFilesAndFoldersOperation
215: *
216: * Note this method is for internal use only. It is not API.
217: *
218: */
219: public String validateDestination(IContainer destination,
220: IResource[] sourceResources) {
221: IPath destinationLocation = destination.getLocation();
222:
223: for (int i = 0; i < sourceResources.length; i++) {
224: IResource sourceResource = sourceResources[i];
225:
226: // is the source being copied onto itself?
227: if (sourceResource.getParent().equals(destination)) {
228: return NLS
229: .bind(
230: IDEWorkbenchMessages.MoveFilesAndFoldersOperation_sameSourceAndDest,
231: sourceResource.getName());
232: }
233: // test if linked source is copied onto itself. Fixes bug 29913.
234: if (destinationLocation != null) {
235: IPath sourceLocation = sourceResource.getLocation();
236: IPath destinationResource = destinationLocation
237: .append(sourceResource.getName());
238: if (sourceLocation != null
239: && sourceLocation
240: .isPrefixOf(destinationResource)) {
241: return NLS
242: .bind(
243: IDEWorkbenchMessages.MoveFilesAndFoldersOperation_sameSourceAndDest,
244: sourceResource.getName());
245: }
246: }
247: }
248: return super .validateDestination(destination, sourceResources);
249: }
250:
251: /*
252: * (non-Javadoc)
253: *
254: * @see org.eclipse.ui.actions.CopyFilesAndFoldersOperation#isMove()
255: */
256: protected boolean isMove() {
257: return true;
258: }
259:
260: /**
261: * Returns an AbstractWorkspaceOperation suitable for performing the move or
262: * copy operation that will move or copy the given resources to the given
263: * destination path.
264: *
265: * @param resources
266: * the resources to be moved or copied
267: * @param destinationPath
268: * the destination path to which the resources should be moved
269: * @return the operation that should be used to perform the move or copy
270: * @since 3.3
271: */
272: protected AbstractWorkspaceOperation getUndoableCopyOrMoveOperation(
273: IResource[] resources, IPath destinationPath) {
274: return new MoveResourcesOperation(
275: resources,
276: destinationPath,
277: IDEWorkbenchMessages.CopyFilesAndFoldersOperation_moveTitle);
278:
279: }
280: }
|