blob: b6d27ac0ddceb6e8d4b899c4a50a7c612ddeaf21 [file] [log] [blame]
package org.eclipse.ui.actions;
/*
* Copyright (c) 2000, 2002 IBM Corp. All rights reserved.
* This file is made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*/
import java.util.ArrayList;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.internal.WorkbenchMessages;
/**
* Moves files and folders.
* <p>
* This class may be instantiated; it is not intended to be subclassed.
* </p>
*
* @since 2.1
*/
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
*/
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 rejectedFiles files rejected for copy during validateEdit
* @param destination destination to which resources will be moved
* @param subMonitor a progress monitor for showing progress and for cancelation
*/
protected void copy(IResource[] resources, ArrayList rejectedFiles, IPath destination, IProgressMonitor subMonitor) throws CoreException {
for (int i = 0; i < resources.length; i++) {
IResource source = resources[i];
IPath destinationPath = destination.append(source.getName());
IWorkspace workspace = source.getWorkspace();
IWorkspaceRoot workspaceRoot = workspace.getRoot();
boolean isFolder = source.getType() == IResource.FOLDER;
boolean exists = workspaceRoot.exists(destinationPath);
if (isFolder && exists) {
// the resource is a folder and it exists in the destination, copy the
// children of the folder
IResource[] children = ((IContainer) source).members();
copy(children, rejectedFiles, destinationPath, subMonitor);
// need to explicitly delete the folder since we're not moving it
delete(source, subMonitor);
} else if (!rejectedFiles.contains(destinationPath)) {
// if we're merging folders, we could be overwriting an existing file
IResource existing = workspaceRoot.findMember(destinationPath);
boolean canMove = true;
if (existing != null) {
canMove = !moveExisting(source, existing, subMonitor);
if (canMove) {
canMove = delete(existing, subMonitor);
}
}
// was the resource deleted successfully or was there no existing resource to delete?
if (canMove) {
int flags = IResource.SHALLOW;
if (source.isLinked() && checkDeep(source)) {
// do a deep move of the resource
flags = IResource.NONE;
}
flags |= IResource.KEEP_HISTORY;
source.move(destinationPath, flags, new SubProgressMonitor(subMonitor, 0));
}
subMonitor.worked(1);
if (subMonitor.isCanceled()) {
throw new OperationCanceledException();
}
}
}
}
/**
* 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
*/
protected String getDeepCheckQuestion(IResource source) {
return WorkbenchMessages.format(
"CopyFilesAndFoldersOperation.deepMoveQuestion", //$NON-NLS-1$
new Object[] {source.getFullPath().makeRelative()});
}
/**
* Returns the message for this operation's problems dialog.
*
* @return the problems message
*/
protected String getProblemsMessage() {
return WorkbenchMessages.getString("MoveFilesAndFoldersOperation.problemMessage"); //$NON-NLS-1$
}
/**
* Returns the title for this operation's problems dialog.
*
* @return the problems dialog title
*/
protected String getProblemsTitle() {
return WorkbenchMessages.getString("MoveFilesAndFoldersOperation.moveFailedTitle"); //$NON-NLS-1$
}
/**
* 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 subMonitor a progress monitor for showing progress and for cancelation
* @return boolean <code>true</code> if the source file was moved.
* <code>false</code> otherwise
* @throws CoreException setContents failed
*/
private boolean moveExisting(IResource source, IResource existing, IProgressMonitor subMonitor) throws CoreException {
boolean moved = false;
IFile existingFile = getFile(existing);
if (existingFile != null) {
IFile sourceFile = getFile(source);
if (sourceFile != null) {
existingFile.setContents(sourceFile.getContents(), IResource.KEEP_HISTORY, new SubProgressMonitor(subMonitor, 0));
delete(sourceFile, subMonitor);
moved = true;
}
}
return moved;
}
/* (non-Javadoc)
* Overrides method in CopyFilesAndFoldersOperation
*
* Note this method is for internal use only. It is not API.
*
*/
public String validateDestination(IContainer destination, IResource[] sourceResources) {
IPath destinationLocation = destination.getLocation();
for (int i = 0; i < sourceResources.length; i++) {
IResource sourceResource = sourceResources[i];
// is the source being copied onto itself?
if (sourceResource.getParent().equals(destination)) {
return WorkbenchMessages.format(
"MoveFilesAndFoldersOperation.sameSourceAndDest", //$NON-NLS-1$
new Object[] {sourceResource.getName()});
}
// test if linked source is copied onto itself. Fixes bug 29913.
if (destinationLocation != null) {
IPath sourceLocation = sourceResource.getLocation();
IPath destinationResource = destinationLocation.append(sourceResource.getName());
if (sourceLocation != null && sourceLocation.isPrefixOf(destinationResource)) {
return WorkbenchMessages.format(
"MoveFilesAndFoldersOperation.sameSourceAndDest", //$NON-NLS-1$
new Object[] {sourceResource.getName()});
}
}
}
return super.validateDestination(destination, sourceResources);
}
}