blob: 9142176ceccc435a48a993ea4054f05504242146 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.actions;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.ide.undo.AbstractWorkspaceOperation;
import org.eclipse.ui.ide.undo.MoveResourcesOperation;
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
/**
* Moves files and folders.
* <p>
* This class may be instantiated; it is not intended to be subclassed.
* </p>
*
* @since 2.1
* @noextend This class is not intended to be subclassed by clients.
*/
public class MoveFilesAndFoldersOperation extends CopyFilesAndFoldersOperation {
/**
* Creates a new operation initialized with a shell.
*
* @param shell
* parent shell for error dialogs
*/
public MoveFilesAndFoldersOperation(Shell shell) {
super(shell);
}
/**
* Returns whether this operation is able to perform on-the-fly
* auto-renaming of resources with name collisions.
*
* @return <code>true</code> if auto-rename is supported, and
* <code>false</code> otherwise
*/
@Override
protected boolean canPerformAutoRename() {
return false;
}
/**
* Moves the resources to the given destination. This method is called
* recursively to merge folders during folder move.
*
* @param resources
* the resources to move
* @param destination
* destination to which resources will be moved
* @param monitor
* a progress monitor for showing progress and for cancelation
*
* @deprecated As of 3.3, the work is performed in the undoable operation
* created in
* {@link #getUndoableCopyOrMoveOperation(IResource[], IPath)}
*/
@Deprecated
@Override
protected void copy(IResource[] resources, IPath destination, IProgressMonitor monitor) throws CoreException {
SubMonitor subMonitor = SubMonitor.convert(monitor, resources.length);
for (IResource resource : resources) {
SubMonitor iterationMonitor = subMonitor.split(1).setWorkRemaining(100);
IPath destinationPath = destination.append(resource.getName());
IWorkspace workspace = resource.getWorkspace();
IWorkspaceRoot workspaceRoot = workspace.getRoot();
IResource existing = workspaceRoot.findMember(destinationPath);
if (resource.getType() == IResource.FOLDER && existing != null) {
// the resource is a folder and it exists in the destination,
// move the children of the folder.
if (homogenousResources(resource, existing)) {
IResource[] children = ((IContainer) resource).members();
copy(children, destinationPath, iterationMonitor.split(50));
delete(resource, iterationMonitor.split(50));
} else {
// delete the destination folder, moving a linked folder
// over an unlinked one or vice versa. Fixes bug 28772.
delete(existing, iterationMonitor.split(50));
resource.move(destinationPath, IResource.SHALLOW | IResource.KEEP_HISTORY,
iterationMonitor.split(50));
}
} else {
// if we're merging folders, we could be overwriting an existing
// file
if (existing != null) {
if (homogenousResources(resource, existing)) {
moveExisting(resource, existing, iterationMonitor.split(100));
} else {
// Moving a linked resource over unlinked or vice versa.
// Can't use setContents here. Fixes bug 28772.
delete(existing, iterationMonitor.split(50));
resource.move(destinationPath, IResource.SHALLOW | IResource.KEEP_HISTORY,
iterationMonitor.split(50));
}
} else {
resource.move(destinationPath, IResource.SHALLOW | IResource.KEEP_HISTORY,
iterationMonitor.split(100));
}
}
}
}
/**
* Returns the message for querying deep copy/move of a linked resource.
*
* @param source
* resource the query is made for
* @return the deep query message
*/
@Override
protected String getDeepCheckQuestion(IResource source) {
return NLS
.bind(
IDEWorkbenchMessages.CopyFilesAndFoldersOperation_deepMoveQuestion,
source.getFullPath().makeRelative());
}
/**
* Returns the task title for this operation's progress dialog.
*
* @return the task title
*/
@Override
protected String getOperationTitle() {
return IDEWorkbenchMessages.MoveFilesAndFoldersOperation_operationTitle;
}
/**
* Returns the message for this operation's problems dialog.
*
* @return the problems message
*/
@Override
protected String getProblemsMessage() {
return IDEWorkbenchMessages.MoveFilesAndFoldersOperation_problemMessage;
}
/**
* Returns the title for this operation's problems dialog.
*
* @return the problems dialog title
*/
@Override
protected String getProblemsTitle() {
return IDEWorkbenchMessages.MoveFilesAndFoldersOperation_moveFailedTitle;
}
/**
* Returns whether the source file in a destination collision will be
* validateEdited together with the collision itself. Returns true.
*
* @return boolean <code>true</code>, the source file in a destination
* collision should be validateEdited.
*/
@Override
protected boolean getValidateConflictSource() {
return true;
}
/**
* Sets the content of the existing file to the source file content. Deletes
* the source file.
*
* @param source
* source file to move
* @param existing
* existing file to set the source content in
* @param monitor
* a progress monitor for showing progress and for cancelation
* @throws CoreException
* setContents failed
* @deprecated As of 3.3, this method is not called.
*/
@Deprecated
private void moveExisting(IResource source, IResource existing, IProgressMonitor monitor) throws CoreException {
SubMonitor subMonitor = SubMonitor.convert(monitor, 2);
IFile existingFile = getFile(existing);
if (existingFile != null) {
IFile sourceFile = getFile(source);
if (sourceFile != null) {
existingFile.setContents(sourceFile.getContents(), IResource.KEEP_HISTORY, subMonitor.split(1));
delete(sourceFile, subMonitor.split(1));
}
}
}
@Override
public String validateDestination(IContainer destination,
IResource[] sourceResources) {
IPath destinationLocation = destination.getLocation();
for (IResource sourceRessource : sourceResources) {
// is the source being copied onto itself?
if (sourceRessource.getParent().equals(destination)) {
return NLS
.bind(
IDEWorkbenchMessages.MoveFilesAndFoldersOperation_sameSourceAndDest,
sourceRessource.getName());
}
// test if linked source is copied onto itself. Fixes bug 29913.
if (destinationLocation != null) {
IPath sourceLocation = sourceRessource.getLocation();
IPath destinationResource = destinationLocation
.append(sourceRessource.getName());
if (sourceLocation != null
&& sourceLocation.isPrefixOf(destinationResource)) {
return NLS
.bind(
IDEWorkbenchMessages.MoveFilesAndFoldersOperation_sameSourceAndDest,
sourceRessource.getName());
}
}
}
return super.validateDestination(destination, sourceResources);
}
@Override
protected boolean isMove() {
return true;
}
/**
* Returns an AbstractWorkspaceOperation suitable for performing the move or
* copy operation that will move or copy the given resources to the given
* destination path.
*
* @param resources
* the resources to be moved or copied
* @param destinationPath
* the destination path to which the resources should be moved
* @return the operation that should be used to perform the move or copy
* @since 3.3
*/
@Override
protected AbstractWorkspaceOperation getUndoableCopyOrMoveOperation(
IResource[] resources, IPath destinationPath) {
return new MoveResourcesOperation(resources, destinationPath,
IDEWorkbenchMessages.CopyFilesAndFoldersOperation_moveTitle);
}
}