| package org.eclipse.cdt.internal.core.model; |
| |
| /* |
| * (c) Copyright QNX Software Systems Ltd. 2002. |
| * All Rights Reserved. |
| */ |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.eclipse.cdt.core.model.CModelException; |
| import org.eclipse.cdt.core.model.ICElement; |
| import org.eclipse.cdt.core.model.ICElementDelta; |
| import org.eclipse.cdt.core.model.ICModelStatus; |
| import org.eclipse.cdt.core.model.ICModelStatusConstants; |
| import org.eclipse.cdt.core.model.ICProject; |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.Path; |
| |
| /** |
| * This operation copies/moves/renames a collection of resources from their current |
| * container to a new container, optionally renaming the |
| * elements. |
| * <p>Notes:<ul> |
| * <li>If there is already an resource with the same name in |
| * the new container, the operation either overwrites or aborts, |
| * depending on the collision policy setting. The default setting is |
| * abort. |
| * |
| * <li>The collection of elements being copied must all share the |
| * same type of container. |
| * |
| * <li>This operation can be used to copy and rename elements within |
| * the same container. |
| * |
| * <li>This operation only copies translation units. |
| * </ul> |
| * |
| */ |
| public class CopyResourceElementsOperation extends MultiOperation { |
| |
| /** |
| * The list of new resources created during this operation. |
| */ |
| protected ArrayList fCreatedElements; |
| |
| /** |
| * Table specifying deltas for elements being |
| * copied/moved/renamed. Keyed by elements' project(s), and |
| * values are the corresponding deltas. |
| */ |
| protected Map fDeltasPerProject= new HashMap(1); |
| |
| public CopyResourceElementsOperation(ICElement[] src, ICElement[] dst, boolean force) { |
| super(src, dst, force); |
| } |
| |
| /** |
| * Returns the <code>CElementDelta</code> for <code>cProject</code>, |
| * creating it and putting it in <code>fDeltasPerProject</code> if |
| * it does not exist yet. |
| */ |
| private CElementDelta getDeltaFor(ICProject cProject) { |
| CElementDelta delta = (CElementDelta) fDeltasPerProject.get(cProject); |
| if (delta == null) { |
| delta = new CElementDelta(cProject); |
| fDeltasPerProject.put(cProject, delta); |
| } |
| return delta; |
| } |
| |
| /** |
| * @see MultiOperation |
| */ |
| protected String getMainTaskName() { |
| return "operation.copyResourceProgress"; //$NON-NLS-1$ |
| } |
| |
| /** |
| * Sets the deltas to register the changes resulting from this operation |
| * for this source element and its destination. |
| * If the operation is a cross project operation<ul> |
| * <li>On a copy, the delta should be rooted in the dest project |
| * <li>On a move, two deltas are generated<ul> |
| * <li>one rooted in the source project |
| * <li>one rooted in the destination project</ul></ul> |
| * If the operation is rooted in a single project, the delta is rooted in that project |
| * |
| */ |
| protected void prepareDeltas(ICElement sourceElement, ICElement destinationElement) { |
| ICProject destProject = destinationElement.getCProject(); |
| if (isMove()) { |
| ICProject sourceProject = sourceElement.getCProject(); |
| getDeltaFor(sourceProject).movedFrom(sourceElement, destinationElement); |
| getDeltaFor(destProject).movedTo(destinationElement, sourceElement); |
| } else { |
| getDeltaFor(destProject).added(destinationElement); |
| } |
| } |
| |
| /** |
| * Process all of the changed deltas generated by this operation. |
| */ |
| protected void processDeltas() { |
| for (Iterator deltas = this.fDeltasPerProject.values().iterator(); deltas.hasNext();){ |
| addDelta((ICElementDelta) deltas.next()); |
| } |
| } |
| |
| /** |
| * Copies/moves a compilation unit with the name <code>newName</code> |
| * to the destination package.<br> |
| * The package statement in the compilation unit is updated if necessary. |
| * The main type of the compilation unit is renamed if necessary. |
| * |
| * @exception JavaModelException if the operation is unable to |
| * complete |
| */ |
| private void processResource(ICElement source, ICElement dest) throws CModelException { |
| String newName = getNewNameFor(source); |
| String destName = (newName != null) ? newName : source.getElementName(); |
| |
| // copy resource |
| IFile sourceResource = (IFile)source.getResource(); |
| // can be an IFolder or an IProject |
| IContainer destFolder = (IContainer)dest.getResource(); |
| IFile destFile = destFolder.getFile(new Path(destName)); |
| if (!destFile.equals(sourceResource)) { |
| try { |
| if (destFile.exists()) { |
| if (fForce) { |
| // we can remove it |
| deleteResource(destFile, false); |
| } else { |
| // abort |
| throw new CModelException(new CModelStatus(ICModelStatusConstants.NAME_COLLISION)); |
| } |
| } |
| if (this.isMove()) { |
| sourceResource.move(destFile.getFullPath(), fForce, true, getSubProgressMonitor(1)); |
| } else { |
| sourceResource.copy(destFile.getFullPath(), fForce, getSubProgressMonitor(1)); |
| } |
| this.hasModifiedResource = true; |
| } catch (CModelException e) { |
| throw e; |
| } catch (CoreException e) { |
| throw new CModelException(e); |
| } |
| |
| // update new resource content |
| |
| // register the correct change deltas |
| ICElement cdest = CModelManager.getDefault().create(destFile); |
| prepareDeltas(source, cdest); |
| fCreatedElements.add(cdest); |
| //if (newName != null) { |
| //the main type has been renamed |
| //String oldName = source.getElementName(); |
| //oldName = oldName.substring(0, oldName.length() - 5); |
| //String nName = newName; |
| //nName = nName.substring(0, nName.length() - 5); |
| //prepareDeltas(source.getType(oldName), cdest.getType(nName)); |
| //} |
| } else { |
| if (!fForce) { |
| throw new CModelException(new CModelStatus(ICModelStatusConstants.NAME_COLLISION)); |
| } |
| // update new resource content |
| // in case we do a saveas on the same resource we have to simply update the contents |
| // see http://dev.eclipse.org/bugs/show_bug.cgi?id=9351 |
| } |
| } |
| |
| /** |
| * @see MultiOperation |
| * This method delegates to <code>processResource</code> or |
| * <code>processPackageFragmentResource</code>, depending on the type of |
| * <code>element</code>. |
| */ |
| protected void processElement(ICElement element) throws CModelException { |
| ICElement dest = getDestinationParent(element); |
| if (element.getElementType() <= ICElement.C_UNIT) { |
| processResource(element, dest); |
| //fCreatedElements.add(dest.getCompilationUnit(element.getElementName())); |
| } else { |
| throw new CModelException(new CModelStatus(ICModelStatusConstants.INVALID_ELEMENT_TYPES, element)); |
| } |
| } |
| |
| /** |
| * @see MultiOperation |
| * Overridden to allow special processing of <code>CElementDelta</code>s |
| * and <code>fResultElements</code>. |
| */ |
| protected void processElements() throws CModelException { |
| fCreatedElements = new ArrayList(fElementsToProcess.length); |
| try { |
| super.processElements(); |
| } catch (CModelException cme) { |
| throw cme; |
| } finally { |
| fResultElements = new ICElement[fCreatedElements.size()]; |
| fCreatedElements.toArray(fResultElements); |
| processDeltas(); |
| } |
| } |
| |
| /** |
| * Possible failures: |
| * <ul> |
| * <li>NO_ELEMENTS_TO_PROCESS - no elements supplied to the operation |
| * <li>INDEX_OUT_OF_BOUNDS - the number of renamings supplied to the operation |
| * does not match the number of elements that were supplied. |
| * </ul> |
| */ |
| protected ICModelStatus verify() { |
| ICModelStatus status = super.verify(); |
| if (!status.isOK()) { |
| return status; |
| } |
| |
| if (fRenamingsList != null && fRenamingsList.length != fElementsToProcess.length) { |
| return new CModelStatus(ICModelStatusConstants.INDEX_OUT_OF_BOUNDS); |
| } |
| return CModelStatus.VERIFIED_OK; |
| } |
| |
| /** |
| * @see MultiOperation |
| */ |
| protected void verify(ICElement element) throws CModelException { |
| if (element == null || !element.exists()) |
| error(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST, element); |
| |
| if (element.isReadOnly() && (isRename() || isMove())) |
| error(ICModelStatusConstants.READ_ONLY, element); |
| |
| CElement dest = (CElement) getDestinationParent(element); |
| verifyDestination(element, dest); |
| if (fRenamings != null) { |
| verifyRenaming(element); |
| } |
| } |
| } |