001: /*******************************************************************************
002: * Copyright (c) 2006, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.ide.undo;
011:
012: import java.net.URI;
013:
014: import org.eclipse.core.filesystem.URIUtil;
015: import org.eclipse.core.resources.IProject;
016: import org.eclipse.core.resources.IProjectDescription;
017: import org.eclipse.core.resources.IResource;
018: import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
019: import org.eclipse.core.runtime.Assert;
020: import org.eclipse.core.runtime.CoreException;
021: import org.eclipse.core.runtime.IAdaptable;
022: import org.eclipse.core.runtime.IPath;
023: import org.eclipse.core.runtime.IProgressMonitor;
024: import org.eclipse.core.runtime.IStatus;
025: import org.eclipse.core.runtime.Path;
026: import org.eclipse.core.runtime.Platform;
027: import org.eclipse.core.runtime.Status;
028: import org.eclipse.core.runtime.SubProgressMonitor;
029: import org.eclipse.ui.internal.ide.undo.ProjectDescription;
030: import org.eclipse.ui.internal.ide.undo.UndoMessages;
031:
032: /**
033: * A CopyProjectOperation represents an undoable operation for copying a
034: * project, also specifying the location of its contents. Clients may call the
035: * public API from a background thread.
036: *
037: * This class is intended to be instantiated and used by clients. It is not
038: * intended to be subclassed by clients.
039: *
040: * @since 3.3
041: *
042: */
043: public class CopyProjectOperation extends
044: AbstractCopyOrMoveResourcesOperation {
045:
046: private URI projectLocation;
047:
048: private IProject originalProject;
049:
050: private ProjectDescription originalProjectDescription;
051:
052: /**
053: * Create a CopyProjectOperation that copies the specified project and sets
054: * its location to the specified location.
055: *
056: * @param project
057: * the project to be copied
058: * @param name
059: * the name of the copy
060: * @param location
061: * the location for the project's content, or <code>null</code>
062: * if the default project location should be used.
063: * @param label
064: * the label of the operation
065: */
066: public CopyProjectOperation(IProject project, String name,
067: URI location, String label) {
068: super (new IResource[] { project }, new Path(name), label);
069: Assert.isLegal(project != null);
070: originalProject = project;
071: if (location != null
072: && URIUtil.toPath(location).equals(
073: Platform.getLocation())) {
074: projectLocation = null;
075: } else {
076: projectLocation = location;
077: }
078: }
079:
080: /*
081: * Make a project handle for the proposed target project, or null if one
082: * cannot be made.
083: */
084: private IProject getProposedProjectHandle() {
085: if (destination.segmentCount() == 1) {
086: return getWorkspace().getRoot().getProject(
087: destination.lastSegment());
088: }
089: return null;
090: }
091:
092: /*
093: * (non-Javadoc)
094: *
095: * Checks that the specified project location is valid in addition to
096: * superclass checks.
097: *
098: * @see org.eclipse.ui.ide.undo.AbstractCopyOrMoveResourcesOperation#computeMoveOrCopyStatus()
099: */
100: protected IStatus computeMoveOrCopyStatus() {
101: IStatus status = Status.OK_STATUS;
102: IProject project = getProposedProjectHandle();
103: if (project == null) {
104: return getErrorStatus(UndoMessages.AbstractResourcesOperation_NotEnoughInfo);
105: }
106: if (projectLocation != null) {
107: status = getWorkspace().validateProjectLocationURI(project,
108: projectLocation);
109: }
110: if (status.isOK()) {
111: return super .computeMoveOrCopyStatus();
112: }
113: return status;
114: }
115:
116: /*
117: * (non-Javadoc)
118: *
119: * Map execute to copying the project
120: *
121: * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#doExecute(org.eclipse.core.runtime.IProgressMonitor,
122: * org.eclipse.core.runtime.IAdaptable)
123: */
124: protected void doExecute(IProgressMonitor monitor, IAdaptable uiInfo)
125: throws CoreException {
126: IProject newProject = copyProject(originalProject, destination,
127: projectLocation, monitor);
128: setTargetResources(new IResource[] { newProject });
129: setResourceDescriptions(new ResourceDescription[0]);
130: }
131:
132: /*
133: * (non-Javadoc)
134: *
135: * Map undo to deleting the project we just copied.
136: *
137: * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#doExecute(org.eclipse.core.runtime.IProgressMonitor,
138: * org.eclipse.core.runtime.IAdaptable)
139: */
140: protected void doUndo(IProgressMonitor monitor, IAdaptable uiInfo)
141: throws CoreException {
142: // Delete the project that was copied
143: WorkspaceUndoUtil.delete(resources, new SubProgressMonitor(
144: monitor, 1), uiInfo, true);
145: // Set the target resource to the original
146: setTargetResources(new IResource[] { originalProject });
147: setResourceDescriptions(new ResourceDescription[0]);
148: }
149:
150: /*
151: * (non-Javadoc)
152: *
153: * @see org.eclipse.ui.ide.undo.AbstractCopyOrMoveResourcesOperation#isDestinationPathValid(org.eclipse.core.resources.IResource,
154: * int)
155: */
156: protected boolean isDestinationPathValid(IResource resource,
157: int index) {
158: // path has already been validated in #computeMoveOrCopyStatus()
159: return true;
160: }
161:
162: /*
163: * (non-Javadoc)
164: *
165: * @see org.eclipse.ui.ide.undo.AbstractCopyOrMoveResourcesOperation#getProposedName(org.eclipse.core.resources.IResource,
166: * int)
167: */
168: protected String getProposedName(IResource resource, int index) {
169: return destination.lastSegment();
170: }
171:
172: /*
173: * (non-Javadoc)
174: *
175: * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#updateResourceChangeDescriptionFactory(org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory,
176: * int)
177: */
178: protected boolean updateResourceChangeDescriptionFactory(
179: IResourceChangeDescriptionFactory factory, int operation) {
180: boolean update = false;
181: if (operation == UNDO) {
182: for (int i = 0; i < resources.length; i++) {
183: update = true;
184: IResource resource = resources[i];
185: factory.delete(resource);
186: }
187: } else {
188: factory.copy(originalProject, getDestinationPath(
189: originalProject, 0));
190: }
191: return update;
192: }
193:
194: /*
195: * (non-Javadoc)
196: *
197: * This implementation computes the ability to delete the original copy and
198: * restore any overwritten resources.
199: *
200: * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#computeUndoableStatus(org.eclipse.core.runtime.IProgressMonitor)
201: */
202: public IStatus computeUndoableStatus(IProgressMonitor monitor) {
203: IStatus status = super .computeUndoableStatus(monitor);
204: if (!status.isOK()) {
205: return status;
206: }
207: // If the original project content no longer exist, we do not want to
208: // attempt to undo the copy which involves deleting the copies. They may
209: // be all we have left.
210: if (originalProject == null
211: || !originalProjectDescription.verifyExistence(true)) {
212: markInvalid();
213: return getErrorStatus(UndoMessages.CopyResourcesOperation_NotAllowedDueToDataLoss);
214: }
215: // undoing a copy means deleting the copy that was made
216: if (status.isOK()) {
217: status = computeDeleteStatus();
218: }
219: return status;
220: }
221:
222: /*
223: * Copy the specified project, returning the handle of the copy.
224: */
225: IProject copyProject(IProject project, IPath destinationPath,
226: URI locationURI, IProgressMonitor monitor)
227: throws CoreException {
228: monitor
229: .setTaskName(UndoMessages.AbstractCopyOrMoveResourcesOperation_copyProjectProgress);
230:
231: boolean open = project.isOpen();
232: if (!open) {
233: // Must open project in order to get the original project
234: // description for performing the undo.
235: project.open(null);
236: }
237: originalProjectDescription = new ProjectDescription(project);
238: IProjectDescription description = project.getDescription();
239:
240: // Set the new name and location into the project's description
241: description.setName(destinationPath.lastSegment());
242: description.setLocationURI(locationURI);
243:
244: project.copy(description, IResource.FORCE | IResource.SHALLOW,
245: monitor);
246:
247: // Close the original project if it was closed when we started.
248: if (!open) {
249: project.close(null);
250: }
251: // Now return the handle of the new project
252: return (IProject) getWorkspace().getRoot().findMember(
253: destinationPath);
254: }
255: }
|