/******************************************************************************* * 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); } }