blob: e4b4a6cf1a258fb32f0899b88a660469079dba88 [file] [log] [blame]
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);
}
}
}