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