blob: cf863e63e075b979fdcc185b10a6e2934532c72b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2007 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.ide.undo;
import java.net.URI;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.ui.internal.ide.undo.ProjectDescription;
import org.eclipse.ui.internal.ide.undo.UndoMessages;
/**
* A CopyProjectOperation represents an undoable operation for copying a
* project, also specifying the location of its contents. Clients may call the
* public API from a background thread.
*
* This class is intended to be instantiated and used by clients. It is not
* intended to be subclassed by clients.
*
* @since 3.3
*
*/
public class CopyProjectOperation extends AbstractCopyOrMoveResourcesOperation {
private URI projectLocation;
private IProject originalProject;
private ProjectDescription originalProjectDescription;
/**
* Create a CopyProjectOperation that copies the specified project and sets
* its location to the specified location.
*
* @param project
* the project to be copied
* @param name
* the name of the copy
* @param location
* the location for the project's content, or <code>null</code>
* if the default project location should be used.
* @param label
* the label of the operation
*/
public CopyProjectOperation(IProject project, String name, URI location,
String label) {
super(new IResource[] { project }, new Path(name), label);
Assert.isLegal(project != null);
originalProject = project;
if (location != null
&& URIUtil.toPath(location).equals(Platform.getLocation())) {
projectLocation = null;
} else {
projectLocation = location;
}
}
/*
* Make a project handle for the proposed target project, or null if one
* cannot be made.
*/
private IProject getProposedProjectHandle() {
if (destination.segmentCount() == 1) {
return getWorkspace().getRoot().getProject(
destination.lastSegment());
}
return null;
}
/*
* (non-Javadoc)
*
* Checks that the specified project location is valid in addition to
* superclass checks.
*
* @see org.eclipse.ui.ide.undo.AbstractCopyOrMoveResourcesOperation#computeMoveOrCopyStatus()
*/
protected IStatus computeMoveOrCopyStatus() {
IStatus status = Status.OK_STATUS;
IProject project = getProposedProjectHandle();
if (project == null) {
return getErrorStatus(UndoMessages.AbstractResourcesOperation_NotEnoughInfo);
}
if (projectLocation != null) {
status = getWorkspace().validateProjectLocationURI(project,
projectLocation);
}
if (status.isOK()) {
return super.computeMoveOrCopyStatus();
}
return status;
}
/*
* (non-Javadoc)
*
* Map execute to copying the project
*
* @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#doExecute(org.eclipse.core.runtime.IProgressMonitor,
* org.eclipse.core.runtime.IAdaptable)
*/
protected void doExecute(IProgressMonitor monitor, IAdaptable uiInfo)
throws CoreException {
IProject newProject = copyProject(originalProject, destination,
projectLocation, monitor);
setTargetResources(new IResource[] { newProject });
setResourceDescriptions(new ResourceDescription[0]);
}
/*
* (non-Javadoc)
*
* Map undo to deleting the project we just copied.
*
* @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#doExecute(org.eclipse.core.runtime.IProgressMonitor,
* org.eclipse.core.runtime.IAdaptable)
*/
protected void doUndo(IProgressMonitor monitor, IAdaptable uiInfo)
throws CoreException {
// Delete the project that was copied
WorkspaceUndoUtil.delete(resources, new SubProgressMonitor(monitor, 1),
uiInfo, true);
// Set the target resource to the original
setTargetResources(new IResource[] { originalProject });
setResourceDescriptions(new ResourceDescription[0]);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.ide.undo.AbstractCopyOrMoveResourcesOperation#isDestinationPathValid(org.eclipse.core.resources.IResource,
* int)
*/
protected boolean isDestinationPathValid(IResource resource, int index) {
// path has already been validated in #computeMoveOrCopyStatus()
return true;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.ide.undo.AbstractCopyOrMoveResourcesOperation#getProposedName(org.eclipse.core.resources.IResource,
* int)
*/
protected String getProposedName(IResource resource, int index) {
return destination.lastSegment();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#updateResourceChangeDescriptionFactory(org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory,
* int)
*/
protected boolean updateResourceChangeDescriptionFactory(
IResourceChangeDescriptionFactory factory, int operation) {
boolean update = false;
if (operation == UNDO) {
for (int i = 0; i < resources.length; i++) {
update = true;
IResource resource = resources[i];
factory.delete(resource);
}
} else {
factory.copy(originalProject,
getDestinationPath(originalProject, 0));
}
return update;
}
/*
* (non-Javadoc)
*
* This implementation computes the ability to delete the original copy and
* restore any overwritten resources.
*
* @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#computeUndoableStatus(org.eclipse.core.runtime.IProgressMonitor)
*/
public IStatus computeUndoableStatus(IProgressMonitor monitor) {
IStatus status = super.computeUndoableStatus(monitor);
if (!status.isOK()) {
return status;
}
// If the original project content no longer exist, we do not want to
// attempt to undo the copy which involves deleting the copies. They may
// be all we have left.
if (originalProject == null
|| !originalProjectDescription.verifyExistence(true)) {
markInvalid();
return getErrorStatus(UndoMessages.CopyResourcesOperation_NotAllowedDueToDataLoss);
}
// undoing a copy means deleting the copy that was made
if (status.isOK()) {
status = computeDeleteStatus();
}
return status;
}
/*
* Copy the specified project, returning the handle of the copy.
*/
IProject copyProject(IProject project, IPath destinationPath,
URI locationURI, IProgressMonitor monitor) throws CoreException {
monitor
.setTaskName(UndoMessages.AbstractCopyOrMoveResourcesOperation_copyProjectProgress);
boolean open = project.isOpen();
if (!open) {
// Must open project in order to get the original project
// description for performing the undo.
project.open(null);
}
originalProjectDescription = new ProjectDescription(project);
IProjectDescription description = project.getDescription();
// Set the new name and location into the project's description
description.setName(destinationPath.lastSegment());
description.setLocationURI(locationURI);
project.copy(description, IResource.FORCE | IResource.SHALLOW, monitor);
// Close the original project if it was closed when we started.
if (!open) {
project.close(null);
}
// Now return the handle of the new project
return (IProject) getWorkspace().getRoot().findMember(destinationPath);
}
}