new version with WorkingCopy Management
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / CopyResourceElementsOperation.java
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/CopyResourceElementsOperation.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/CopyResourceElementsOperation.java
new file mode 100644 (file)
index 0000000..2e30065
--- /dev/null
@@ -0,0 +1,648 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.core;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import net.sourceforge.phpdt.core.IBuffer;
+import net.sourceforge.phpdt.core.ICompilationUnit;
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IJavaElementDelta;
+import net.sourceforge.phpdt.core.IJavaModelStatus;
+import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
+import net.sourceforge.phpdt.core.IJavaProject;
+import net.sourceforge.phpdt.core.IPackageFragment;
+import net.sourceforge.phpdt.core.IPackageFragmentRoot;
+import net.sourceforge.phpdt.core.IType;
+import net.sourceforge.phpdt.core.JavaModelException;
+import net.sourceforge.phpdt.core.jdom.DOMException;
+import net.sourceforge.phpdt.core.jdom.DOMFactory;
+import net.sourceforge.phpdt.core.jdom.IDOMCompilationUnit;
+import net.sourceforge.phpdt.core.jdom.IDOMNode;
+import net.sourceforge.phpdt.core.jdom.IDOMPackage;
+import net.sourceforge.phpeclipse.PHPCore;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+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>When a compilation unit is copied to a new package, the
+ *    package declaration in the compilation unit is automatically updated.
+ *
+ *    <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 compilation units and package fragments.
+ *    It does not copy package fragment roots - a platform operation must be used for that.
+ * </ul>
+ *
+ */
+public class CopyResourceElementsOperation extends MultiOperation {
+       /**
+        * A collection of renamed compilation units.  These cus do
+        * not need to be saved as they no longer exist.
+        */
+       protected ArrayList fRenamedCompilationUnits = null;
+       /**
+        * 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);
+       /**
+        * The <code>DOMFactory</code> used to manipulate the source code of
+        * <code>ICompilationUnit</code>.
+        */
+       protected DOMFactory fFactory;
+       /**
+        * The list of new resources created during this operation.
+        */
+       protected ArrayList fCreatedElements;
+       /**
+        * When executed, this operation will copy the given resources to the
+        * given containers.  The resources and destination containers must be in
+        * the correct order. If there is > 1 destination, the number of destinations
+        * must be the same as the number of resources being copied/moved.
+        */
+       public CopyResourceElementsOperation(IJavaElement[] resourcesToCopy, IJavaElement[] destContainers, boolean force) {
+               super(resourcesToCopy, destContainers, force);
+               fFactory = new DOMFactory();
+       }
+       /**
+        * When executed, this operation will copy the given resources to the
+        * given container.
+        */
+       public CopyResourceElementsOperation(IJavaElement[] resourcesToCopy, IJavaElement destContainer, boolean force) {
+               this(resourcesToCopy, new IJavaElement[]{destContainer}, force);
+       }
+       /**
+        * Returns the children of <code>source</code> which are affected by this operation.
+        * If <code>source</code> is a <code>K_SOURCE</code>, these are the <code>.java</code>
+        * files, if it is a <code>K_BINARY</code>, they are the <code>.class</code> files.
+        */
+       private IResource[] collectResourcesOfInterest(IPackageFragment source) throws JavaModelException {
+               IJavaElement[] children = source.getChildren();
+               int childOfInterest = IJavaElement.COMPILATION_UNIT;
+//             if (source.getKind() == IPackageFragmentRoot.K_BINARY) {
+//                     childOfInterest = IJavaElement.CLASS_FILE;
+//             }
+               ArrayList correctKindChildren = new ArrayList(children.length);
+               for (int i = 0; i < children.length; i++) {
+                       IJavaElement child = children[i];
+                       if (child.getElementType() == childOfInterest) {
+                               correctKindChildren.add(child.getResource());
+                       }
+               }
+               // Gather non-java resources
+//             Object[] nonJavaResources = source.getNonJavaResources();
+//             int actualNonJavaResourceCount = 0;
+//             for (int i = 0, max = nonJavaResources.length; i < max; i++){
+//                     if (nonJavaResources[i] instanceof IResource) actualNonJavaResourceCount++;
+//             }
+//             IResource[] actualNonJavaResources = new IResource[actualNonJavaResourceCount];
+//             for (int i = 0, max = nonJavaResources.length, index = 0; i < max; i++){
+//                     if (nonJavaResources[i] instanceof IResource) actualNonJavaResources[index++] = (IResource)nonJavaResources[i];
+//             }
+               
+//             if (actualNonJavaResourceCount != 0) {
+//                     int correctKindChildrenSize = correctKindChildren.size();
+//                     IResource[] result = new IResource[correctKindChildrenSize + actualNonJavaResourceCount];
+//                     correctKindChildren.toArray(result);
+//                     System.arraycopy(actualNonJavaResources, 0, result, correctKindChildrenSize, actualNonJavaResourceCount);
+//                     return result;
+//             } else {
+                       IResource[] result = new IResource[correctKindChildren.size()];
+                       correctKindChildren.toArray(result);
+                       return result;
+//             }
+       }
+       /**
+        * Creates any destination package fragment(s) which do not exists yet.
+        */
+       private void createNeededPackageFragments(IContainer sourceFolder, IPackageFragmentRoot root, String newFragName, boolean moveFolder) throws JavaModelException {
+               IContainer parentFolder = (IContainer) root.getResource();
+               JavaElementDelta projectDelta = null;
+               String[] names = net.sourceforge.phpdt.internal.core.Util.getTrimmedSimpleNames(newFragName);
+               StringBuffer sideEffectPackageName = new StringBuffer();
+               char[][] exclusionsPatterns = ((PackageFragmentRoot)root).fullExclusionPatternChars();
+               for (int i = 0; i < names.length; i++) {
+                       String subFolderName = names[i];
+                       sideEffectPackageName.append(subFolderName);
+                       IResource subFolder = parentFolder.findMember(subFolderName);
+                       if (subFolder == null) {
+                               // create deepest folder only if not a move (folder will be moved in processPackageFragmentResource)
+                               if (!(moveFolder && i == names.length-1)) {
+                                       createFolder(parentFolder, subFolderName, fForce);
+                               }
+                               parentFolder = parentFolder.getFolder(new Path(subFolderName));
+                               sourceFolder = sourceFolder.getFolder(new Path(subFolderName));
+                               if (sourceFolder.isReadOnly()) {
+                                       parentFolder.setReadOnly(true);
+                               }
+                               IPackageFragment sideEffectPackage = root.getPackageFragment(sideEffectPackageName.toString());
+                               if (i < names.length - 1 // all but the last one are side effect packages
+                                               && !net.sourceforge.phpdt.internal.core.Util.isExcluded(parentFolder, exclusionsPatterns)) { 
+                                       if (projectDelta == null) {
+                                               projectDelta = getDeltaFor(root.getJavaProject());
+                                       }
+                                       projectDelta.added(sideEffectPackage);
+                               }
+                               fCreatedElements.add(sideEffectPackage);
+                       } else {
+                               parentFolder = (IContainer) subFolder;
+                       }
+                       sideEffectPackageName.append('.');
+               }
+       }
+       /**
+        * Returns the <code>JavaElementDelta</code> for <code>javaProject</code>,
+        * creating it and putting it in <code>fDeltasPerProject</code> if
+        * it does not exist yet.
+        */
+       private JavaElementDelta getDeltaFor(IJavaProject javaProject) {
+               JavaElementDelta delta = (JavaElementDelta) fDeltasPerProject.get(javaProject);
+               if (delta == null) {
+                       delta = new JavaElementDelta(javaProject);
+                       fDeltasPerProject.put(javaProject, delta);
+               }
+               return delta;
+       }
+       /**
+        * @see MultiOperation
+        */
+       protected String getMainTaskName() {
+               return net.sourceforge.phpdt.internal.core.Util.bind("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(IJavaElement sourceElement, IJavaElement destinationElement, boolean isMove) {
+               if (net.sourceforge.phpdt.internal.core.Util.isExcluded(sourceElement) || net.sourceforge.phpdt.internal.core.Util.isExcluded(destinationElement)) return;
+               IJavaProject destProject = destinationElement.getJavaProject();
+               if (isMove) {
+                       IJavaProject sourceProject = sourceElement.getJavaProject();
+                       getDeltaFor(sourceProject).movedFrom(sourceElement, destinationElement);
+                       getDeltaFor(destProject).movedTo(destinationElement, sourceElement);
+               } else {
+                       getDeltaFor(destProject).added(destinationElement);
+               }
+       }
+       /**
+        * Copies/moves a compilation unit with the name <code>newCUName</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 processCompilationUnitResource(ICompilationUnit source, IPackageFragment dest) throws JavaModelException {
+               String newCUName = getNewNameFor(source);
+               String destName = (newCUName != null) ? newCUName : source.getElementName();
+               String newContent = updatedContent(source, dest, newCUName); // null if unchanged
+       
+               // copy resource
+               IFile sourceResource = (IFile)(source.isWorkingCopy() ? source.getOriginalElement() : source).getResource();
+               IContainer destFolder = (IContainer)dest.getResource(); // can be an IFolder or an IProject
+               IFile destFile = destFolder.getFile(new Path(destName));
+               if (!destFile.equals(sourceResource)) {
+                       try {
+                               if (destFile.exists()) {
+                                       if (fForce) {
+                                               // we can remove it
+                                               deleteResource(destFile, IResource.KEEP_HISTORY);
+                                       } else {
+                                               // abort
+                                               throw new JavaModelException(new JavaModelStatus(
+                                                       IJavaModelStatusConstants.NAME_COLLISION, 
+                                                       Util.bind("status.nameCollision", destFile.getFullPath().toString()))); //$NON-NLS-1$
+                                       }
+                               }
+                               int flags = fForce ? IResource.FORCE : IResource.NONE;
+                               if (this.isMove()) {
+                                       flags |= IResource.KEEP_HISTORY;
+                                       sourceResource.move(destFile.getFullPath(), flags, getSubProgressMonitor(1));
+                               } else {
+                                       if (newContent != null) flags |= IResource.KEEP_HISTORY;
+                                       sourceResource.copy(destFile.getFullPath(), flags, getSubProgressMonitor(1));
+                               }
+                               this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
+                       } catch (JavaModelException e) {
+                               throw e;
+                       } catch (CoreException e) {
+                               throw new JavaModelException(e);
+                       }
+       
+                       // update new resource content
+                       try {
+                               if (newContent != null){
+                                       String encoding = source.getJavaProject().getOption(PHPCore.CORE_ENCODING, true);
+                                       destFile.setContents(
+                                               new ByteArrayInputStream(encoding == null ? newContent.getBytes() : newContent.getBytes(encoding)), 
+                                               fForce ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY,
+                                               getSubProgressMonitor(1));
+                               }
+                       } catch(IOException e) {
+                               throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+                       } catch (CoreException e) {
+                               throw new JavaModelException(e);
+                       }
+               
+                       // register the correct change deltas
+                       ICompilationUnit destCU = dest.getCompilationUnit(destName);
+                       prepareDeltas(source, destCU, isMove());
+                       if (newCUName != null) {
+                               //the main type has been renamed
+                               String oldName = source.getElementName();
+                               oldName = oldName.substring(0, oldName.length() - 5);
+                               String newName = newCUName;
+                               newName = newName.substring(0, newName.length() - 5);
+                               prepareDeltas(source.getType(oldName), destCU.getType(newName), isMove());
+                       }
+               } else {
+                       if (!fForce) {
+                               throw new JavaModelException(new JavaModelStatus(
+                                       IJavaModelStatusConstants.NAME_COLLISION, 
+                                       Util.bind("status.nameCollision", destFile.getFullPath().toString()))); //$NON-NLS-1$
+                       }
+                       // 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
+                       try {
+                               if (newContent != null){
+                                       String encoding = source.getJavaProject().getOption(PHPCore.CORE_ENCODING, true);
+                                       destFile.setContents(
+                                               new ByteArrayInputStream(encoding == null ? newContent.getBytes() : newContent.getBytes(encoding)), 
+                                               fForce ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY, 
+                                               getSubProgressMonitor(1));
+                               }
+                       } catch(IOException e) {
+                               throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+                       } catch (CoreException e) {
+                               throw new JavaModelException(e);
+                       }
+               }
+       }
+       /**
+        * Process all of the changed deltas generated by this operation.
+        */
+       protected void processDeltas() {
+               for (Iterator deltas = this.fDeltasPerProject.values().iterator(); deltas.hasNext();){
+                       addDelta((IJavaElementDelta) deltas.next());
+               }
+       }
+       /**
+        * @see MultiOperation
+        * This method delegates to <code>processCompilationUnitResource</code> or
+        * <code>processPackageFragmentResource</code>, depending on the type of
+        * <code>element</code>.
+        */
+       protected void processElement(IJavaElement element) throws JavaModelException {
+               IJavaElement dest = getDestinationParent(element);
+               switch (element.getElementType()) {
+                       case IJavaElement.COMPILATION_UNIT :
+                               processCompilationUnitResource((ICompilationUnit) element, (IPackageFragment) dest);
+                               fCreatedElements.add(((IPackageFragment) dest).getCompilationUnit(element.getElementName()));
+                               break;
+                       case IJavaElement.PACKAGE_FRAGMENT :
+                               processPackageFragmentResource((IPackageFragment) element, (IPackageFragmentRoot) dest, getNewNameFor(element));
+                               break;
+                       default :
+                               throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element));
+               }
+       }
+       /**
+        * @see MultiOperation
+        * Overridden to allow special processing of <code>JavaElementDelta</code>s
+        * and <code>fResultElements</code>.
+        */
+       protected void processElements() throws JavaModelException {
+               fCreatedElements = new ArrayList(fElementsToProcess.length);
+               try {
+                       super.processElements();
+               } catch (JavaModelException jme) {
+                       throw jme;
+               } finally {
+                       fResultElements = new IJavaElement[fCreatedElements.size()];
+                       fCreatedElements.toArray(fResultElements);
+                       processDeltas();
+               }
+       }
+       /**
+        * Copies/moves a package fragment with the name <code>newName</code>
+        * to the destination package.<br>
+        *
+        * @exception JavaModelException if the operation is unable to
+        * complete
+        */
+       private void processPackageFragmentResource(IPackageFragment source, IPackageFragmentRoot root, String newName) throws JavaModelException {
+               try {
+                       String newFragName = (newName == null) ? source.getElementName() : newName;
+                       IPackageFragment newFrag = root.getPackageFragment(newFragName);
+                       IResource[] resources = collectResourcesOfInterest(source);
+                       
+                       // if isMove() can we move the folder itself ? (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=22458)
+                       boolean shouldMoveFolder = isMove() && !newFrag.getResource().exists(); // if new pkg fragment exists, it is an override
+                       IFolder srcFolder = (IFolder)source.getResource();
+                       IPath destPath = newFrag.getPath();
+                       if (shouldMoveFolder) {
+                               // check if destination is not included in source
+                               if (srcFolder.getFullPath().isPrefixOf(destPath)) {
+                                       shouldMoveFolder = false;
+                               } else {
+                                       // check if there are no sub-packages
+                                       IResource[] members = srcFolder.members();
+                                       for (int i = 0; i < members.length; i++) {
+                                               if ( members[i] instanceof IFolder) {
+                                                       shouldMoveFolder = false;
+                                                       break;
+                                               }
+                                       }
+                               }       
+                       }
+                       createNeededPackageFragments((IContainer) source.getParent().getResource(), root, newFragName, shouldMoveFolder);
+       
+                       // Process resources
+                       if (shouldMoveFolder) {
+                               // move underlying resource
+                               srcFolder.move(destPath, fForce, true /* keep history */, getSubProgressMonitor(1));
+                               this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
+                       } else {
+                               // process the leaf resources
+                               if (resources.length > 0) {
+                                       if (isRename()) {
+                                               if (! destPath.equals(source.getPath())) {
+                                                       moveResources(resources, destPath);
+                                               }
+                                       } else if (isMove()) {
+                                               // we need to delete this resource if this operation wants to override existing resources
+                                               for (int i = 0, max = resources.length; i < max; i++) {
+                                                       IResource destinationResource = ResourcesPlugin.getWorkspace().getRoot().findMember(destPath.append(resources[i].getName()));
+                                                       if (destinationResource != null) {
+                                                               if (fForce) {
+                                                                       deleteResource(destinationResource, IResource.KEEP_HISTORY);
+                                                               } else {
+                                                                       throw new JavaModelException(new JavaModelStatus(
+                                                                               IJavaModelStatusConstants.NAME_COLLISION, 
+                                                                               Util.bind("status.nameCollision", destinationResource.getFullPath().toString()))); //$NON-NLS-1$
+                                                               }
+                                                       }
+                                               }
+                                               moveResources(resources, destPath);
+                                       } else {
+                                               // we need to delete this resource if this operation wants to override existing resources
+                                               for (int i = 0, max = resources.length; i < max; i++) {
+                                                       IResource destinationResource = ResourcesPlugin.getWorkspace().getRoot().findMember(destPath.append(resources[i].getName()));
+                                                       if (destinationResource != null) {
+                                                               if (fForce) {
+                                                                       // we need to delete this resource if this operation wants to override existing resources
+                                                                       deleteResource(destinationResource, IResource.KEEP_HISTORY);
+                                                               } else {
+                                                                       throw new JavaModelException(new JavaModelStatus(
+                                                                               IJavaModelStatusConstants.NAME_COLLISION, 
+                                                                               Util.bind("status.nameCollision", destinationResource.getFullPath().toString()))); //$NON-NLS-1$
+                                                               }
+                                                       }
+                                               }
+                                               copyResources(resources, destPath);
+                                       }
+                               }
+                       }
+       
+                       // Discard empty old package (if still empty after the rename)
+                       boolean isEmpty = true;
+                       if (isMove()) {
+                               // delete remaining files in this package (.class file in the case where Proj=src=bin)
+                               if (srcFolder.exists()) {
+                                       IResource[] remaingFiles = srcFolder.members();
+                                       for (int i = 0, length = remaingFiles.length; i < length; i++) {
+                                               IResource file = remaingFiles[i];
+                                               if (file instanceof IFile) {
+                                                       this.deleteResource(file, IResource.FORCE | IResource.KEEP_HISTORY);
+                                               } else {
+                                                       isEmpty = false;
+                                               }
+                                       }
+                               }
+                               if (isEmpty) {
+                                       IResource rootResource;
+                                       // check if source is included in destination
+                                       if (destPath.isPrefixOf(srcFolder.getFullPath())) {
+                                               rootResource = newFrag.getResource();
+                                       } else {
+                                               rootResource =  source.getParent().getResource();
+                                       }
+                                       
+                                       // delete recursively empty folders
+                                       deleteEmptyPackageFragment(source, false, rootResource);
+                               }
+                       }
+       
+                       // Update package statement in compilation unit if needed
+                       if (!newFrag.getElementName().equals(source.getElementName())) { // if package has been renamed, update the compilation units
+                               for (int i = 0; i < resources.length; i++) {
+                                       if (resources[i].getName().endsWith(".java")) { //$NON-NLS-1$
+                                               // we only consider potential compilation units
+                                               ICompilationUnit cu = newFrag.getCompilationUnit(resources[i].getName());
+                                               IDOMCompilationUnit domCU = fFactory.createCompilationUnit(cu.getSource(), cu.getElementName());
+                                               if (domCU != null) {
+                                                       updatePackageStatement(domCU, newFragName);
+                                                       IBuffer buffer = cu.getBuffer();
+                                                       if (buffer == null) continue;
+                                                       String bufferContents = buffer.getContents();
+                                                       if (bufferContents == null) continue;
+                                                       String domCUContents = domCU.getContents();
+                                                       String cuContents = null;
+                                                       if (domCUContents != null) {
+                                                               cuContents = net.sourceforge.phpdt.internal.core.Util.normalizeCRs(domCU.getContents(), bufferContents);
+                                                       } else {
+                                                               // See PR http://dev.eclipse.org/bugs/show_bug.cgi?id=11285
+                                                               cuContents = bufferContents;//$NON-NLS-1$
+                                                       }
+                                                       buffer.setContents(cuContents);
+                                                       cu.save(null, false);
+                                               }
+                                       }
+                               }
+                       }
+       
+                       //register the correct change deltas
+                       prepareDeltas(source, newFrag, isMove() && isEmpty);
+               } catch (DOMException dom) {
+                       throw new JavaModelException(dom, IJavaModelStatusConstants.DOM_EXCEPTION);
+               } catch (JavaModelException e) {
+                       throw e;
+               } catch (CoreException ce) {
+                       throw new JavaModelException(ce);
+               }
+       }
+       /**
+        * Updates the content of <code>cu</code>, modifying the type name and/or package
+        * declaration as necessary.
+        *
+        * @return the new source
+        */
+       private String updatedContent(ICompilationUnit cu, IPackageFragment dest, String newName) throws JavaModelException {
+               String currPackageName = cu.getParent().getElementName();
+               String destPackageName = dest.getElementName();
+               if (currPackageName.equals(destPackageName) && newName == null) {
+                       return null; //nothing to change
+               } else {
+                       String typeName = cu.getElementName();
+                       typeName = typeName.substring(0, typeName.length() - 5);
+                       IDOMCompilationUnit cuDOM = null;
+                       IBuffer buffer = cu.getBuffer();
+                       if (buffer == null) return null;
+                       char[] contents = buffer.getCharacters();
+                       if (contents == null) return null;
+                       cuDOM = fFactory.createCompilationUnit(contents, typeName);
+                       updateTypeName(cu, cuDOM, cu.getElementName(), newName);
+                       updatePackageStatement(cuDOM, destPackageName);
+                       return cuDOM.getContents();
+               }
+       }
+       /**
+        * Makes sure that <code>cu</code> declares to be in the <code>pkgName</code> package.
+        */
+       private void updatePackageStatement(IDOMCompilationUnit domCU, String pkgName) throws JavaModelException {
+               boolean defaultPackage = pkgName.equals(IPackageFragment.DEFAULT_PACKAGE_NAME);
+               boolean seenPackageNode = false;
+               Enumeration enum = domCU.getChildren();
+               while (enum.hasMoreElements()) {
+                       IDOMNode node = (IDOMNode) enum.nextElement();
+                       if (node.getNodeType() == IDOMNode.PACKAGE) {
+                               if (! defaultPackage) {
+                                       node.setName(pkgName);
+                               } else {
+                                       node.remove();
+                               }
+                               seenPackageNode = true;
+                               break;
+                       }
+               }
+               if (!seenPackageNode && !defaultPackage) {
+                       //the cu was in a default package...no package declaration
+                       //create the new package declaration as the first child of the cu
+//                     IDOMPackage pkg = fFactory.createPackage("package " + pkgName + ";" + net.sourceforge.phpdt.internal.compiler.util.Util.LINE_SEPARATOR); //$NON-NLS-1$ //$NON-NLS-2$
+//                     IDOMNode firstChild = domCU.getFirstChild();
+//                     if (firstChild != null) {
+//                             firstChild.insertSibling(pkg);
+//                     } // else the cu was empty: leave it empty
+               }
+       }
+               /**
+                * Renames the main type in <code>cu</code>.
+                */
+               private void updateTypeName(ICompilationUnit cu, IDOMCompilationUnit domCU, String oldName, String newName) throws JavaModelException {
+                       if (newName != null) {
+                               if (fRenamedCompilationUnits == null) {
+                                       fRenamedCompilationUnits= new ArrayList(1);
+                               }
+                               fRenamedCompilationUnits.add(cu);
+                               String oldTypeName= oldName.substring(0, oldName.length() - 5);
+                               String newTypeName= newName.substring(0, newName.length() - 5);
+                               // update main type name
+                               IType[] types = cu.getTypes();
+                               for (int i = 0, max = types.length; i < max; i++) {
+                                       IType currentType = types[i];
+                                       if (currentType.getElementName().equals(oldTypeName)) {
+                                               IDOMNode typeNode = ((JavaElement) currentType).findNode(domCU);
+                                               if (typeNode != null) {
+                                                       typeNode.setName(newTypeName);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       /**
+        * 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 IJavaModelStatus verify() {
+               IJavaModelStatus status = super.verify();
+               if (!status.isOK()) {
+                       return status;
+               }
+       
+               if (fRenamingsList != null && fRenamingsList.length != fElementsToProcess.length) {
+                       return new JavaModelStatus(IJavaModelStatusConstants.INDEX_OUT_OF_BOUNDS);
+               }
+               return JavaModelStatus.VERIFIED_OK;
+       }
+       /**
+        * @see MultiOperation
+        */
+       protected void verify(IJavaElement element) throws JavaModelException {
+               if (element == null || !element.exists())
+                       error(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, element);
+                       
+               if (element.isReadOnly() && (isRename() || isMove()))
+                       error(IJavaModelStatusConstants.READ_ONLY, element);
+
+               IResource resource = element.getResource();
+               if (resource instanceof IFolder) {
+                       if (resource.isLinked()) {
+                               error(JavaModelStatus.INVALID_RESOURCE, element);
+                       }
+               }
+       
+               int elementType = element.getElementType();
+       
+               if (elementType == IJavaElement.COMPILATION_UNIT) {
+                       if (isMove() && ((ICompilationUnit) element).isWorkingCopy())
+                               error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
+               } else if (elementType != IJavaElement.PACKAGE_FRAGMENT) {
+                       error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
+               }
+               
+               JavaElement dest = (JavaElement) getDestinationParent(element);
+               verifyDestination(element, dest);
+               if (fRenamings != null) {
+                       verifyRenaming(element);
+               }
+}
+}