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.util.ArrayList;
013: import java.util.List;
014:
015: import org.eclipse.core.resources.IResource;
016: import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
017: import org.eclipse.core.runtime.CoreException;
018: import org.eclipse.core.runtime.IAdaptable;
019: import org.eclipse.core.runtime.IPath;
020: import org.eclipse.core.runtime.IProgressMonitor;
021: import org.eclipse.core.runtime.IStatus;
022: import org.eclipse.core.runtime.SubProgressMonitor;
023: import org.eclipse.ui.internal.ide.undo.UndoMessages;
024:
025: /**
026: * A MoveResourcesOperation represents an undoable operation for moving one or
027: * more resources in the workspace. Clients may call the public API from a
028: * background thread.
029: *
030: * This operation can track any overwritten resources and restore them when the
031: * move is undone. It is up to clients to determine whether overwrites are
032: * allowed. If a resource should not be overwritten, it should not be included
033: * in this operation. In addition to checking for overwrites, the target
034: * location for the move is assumed to have already been validated by the
035: * client. It will not be revalidated on undo and redo.
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 MoveResourcesOperation extends
044: AbstractCopyOrMoveResourcesOperation {
045:
046: IResource[] originalResources;
047:
048: IPath originalDestination;
049:
050: IPath[] originalDestinationPaths;
051:
052: /**
053: * Create a MoveResourcesOperation that moves all of the specified resources
054: * to the same target location, using their existing names.
055: *
056: * @param resources
057: * the resources to be moved
058: * @param destinationPath
059: * the destination path for the resources, not including the name
060: * of the moved resource.
061: * @param label
062: * the label of the operation
063: */
064: public MoveResourcesOperation(IResource[] resources,
065: IPath destinationPath, String label) {
066: super (resources, destinationPath, label);
067: originalResources = this .resources;
068: originalDestination = this .destination;
069: originalDestinationPaths = this .destinationPaths;
070: }
071:
072: /**
073: * Create a MoveResourcesOperation that moves a single resource to a new
074: * location. The new location includes the name of the resource, so this may
075: * be used for a move/rename operation or a simple move.
076: *
077: * @param resource
078: * the resource to be moved
079: * @param newPath
080: * the new path for the resource, including its desired name.
081: * @param label
082: * the label of the operation
083: */
084: public MoveResourcesOperation(IResource resource, IPath newPath,
085: String label) {
086: super (new IResource[] { resource }, new IPath[] { newPath },
087: label);
088: originalResources = this .resources;
089: originalDestination = this .destination;
090: originalDestinationPaths = this .destinationPaths;
091: }
092:
093: /*
094: * (non-Javadoc)
095: *
096: * Map execute to moving the resources
097: *
098: * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#doExecute(org.eclipse.core.runtime.IProgressMonitor,
099: * org.eclipse.core.runtime.IAdaptable)
100: */
101: protected void doExecute(IProgressMonitor monitor, IAdaptable uiInfo)
102: throws CoreException {
103: move(monitor, uiInfo);
104: }
105:
106: /**
107: * Move any known resources according to the destination parameters known by
108: * this operation. Store enough information to undo and redo the operation.
109: *
110: * @param monitor
111: * the progress monitor to use for the operation
112: * @param uiInfo
113: * the IAdaptable (or <code>null</code>) provided by the
114: * caller in order to supply UI information for prompting the
115: * user if necessary. When this parameter is not
116: * <code>null</code>, it contains an adapter for the
117: * org.eclipse.swt.widgets.Shell.class
118: * @throws CoreException
119: * propagates any CoreExceptions thrown from the resources API
120: */
121: protected void move(IProgressMonitor monitor, IAdaptable uiInfo)
122: throws CoreException {
123:
124: monitor.beginTask("", 2000); //$NON-NLS-1$
125: monitor
126: .setTaskName(UndoMessages.AbstractResourcesOperation_MovingResources);
127: List resourcesAtDestination = new ArrayList();
128: List undoDestinationPaths = new ArrayList();
129: List overwrittenResources = new ArrayList();
130:
131: for (int i = 0; i < resources.length; i++) {
132: // Move the resources and record the overwrites that would
133: // be restored if this operation were reversed
134: ResourceDescription[] overwrites;
135: overwrites = WorkspaceUndoUtil.move(
136: new IResource[] { resources[i] },
137: getDestinationPath(resources[i], i),
138: resourcesAtDestination, undoDestinationPaths,
139: new SubProgressMonitor(monitor,
140: 1000 / resources.length), uiInfo, true);
141:
142: // Accumulate the overwrites into the full list
143: for (int j = 0; j < overwrites.length; j++) {
144: overwrittenResources.add(overwrites[j]);
145: }
146: }
147:
148: // Are there any previously overwritten resources to restore now?
149: if (resourceDescriptions != null) {
150: for (int i = 0; i < resourceDescriptions.length; i++) {
151: if (resourceDescriptions[i] != null) {
152: resourceDescriptions[i]
153: .createResource(new SubProgressMonitor(
154: monitor,
155: 1000 / resourceDescriptions.length));
156: }
157: }
158: }
159:
160: // Reset resource descriptions to the just overwritten resources
161: setResourceDescriptions((ResourceDescription[]) overwrittenResources
162: .toArray(new ResourceDescription[overwrittenResources
163: .size()]));
164:
165: // Reset the target resources to refer to the resources in their new
166: // location.
167: setTargetResources((IResource[]) resourcesAtDestination
168: .toArray(new IResource[resourcesAtDestination.size()]));
169: // Reset the destination paths that correspond to these resources
170: destinationPaths = (IPath[]) undoDestinationPaths
171: .toArray(new IPath[undoDestinationPaths.size()]);
172: destination = null;
173:
174: monitor.done();
175: }
176:
177: /*
178: * (non-Javadoc)
179: *
180: * Map undo to moving the resources.
181: *
182: * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#doUndo(org.eclipse.core.runtime.IProgressMonitor,
183: * org.eclipse.core.runtime.IAdaptable)
184: */
185: protected void doUndo(IProgressMonitor monitor, IAdaptable uiInfo)
186: throws CoreException {
187: // We've recorded the original moves atomically, so perform the move
188: move(monitor, uiInfo);
189: // Now reset everything back to the way it was originally.
190: // If we don't do this, the move will be "precisely reversed."
191: // For example, if we merged a folder by moving certain files,
192: // we want redo to redo the folder merge, rather than remembering
193: // only the files that were originally merged. This makes us more
194: // adaptable to changes in the target.
195: setTargetResources(originalResources);
196: this .resourceDescriptions = new ResourceDescription[0];
197: this .destination = originalDestination;
198: this .destinationPaths = originalDestinationPaths;
199: }
200:
201: /*
202: * (non-Javadoc)
203: *
204: * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#updateResourceChangeDescriptionFactory(org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory,
205: * int)
206: */
207: protected boolean updateResourceChangeDescriptionFactory(
208: IResourceChangeDescriptionFactory factory, int operation) {
209: for (int i = 0; i < resources.length; i++) {
210: IResource resource = resources[i];
211: factory.move(resource, getDestinationPath(resource, i));
212: }
213: return true;
214: }
215:
216: /*
217: * (non-Javadoc)
218: *
219: * Map undo to move status.
220: *
221: * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#computeUndoableStatus(org.eclipse.core.runtime.IProgressMonitor)
222: */
223: public IStatus computeUndoableStatus(IProgressMonitor monitor) {
224: IStatus status = super.computeUndoableStatus(monitor);
225: if (status.isOK()) {
226: status = computeMoveOrCopyStatus();
227: }
228: return status;
229: }
230: }
|