ddf268c1e1a33f96d0e57f8714702ef64ef42e06
[phpeclipse.git] /
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
12
13 import java.io.ByteArrayInputStream;
14 import java.io.IOException;
15 import java.util.ArrayList;
16 import java.util.Enumeration;
17 import java.util.HashMap;
18 import java.util.Iterator;
19 import java.util.Map;
20
21 import net.sourceforge.phpdt.core.IBuffer;
22 import net.sourceforge.phpdt.core.ICompilationUnit;
23 import net.sourceforge.phpdt.core.IJavaElement;
24 import net.sourceforge.phpdt.core.IJavaElementDelta;
25 import net.sourceforge.phpdt.core.IJavaModelStatus;
26 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
27 import net.sourceforge.phpdt.core.IJavaProject;
28 import net.sourceforge.phpdt.core.IPackageFragment;
29 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
30 import net.sourceforge.phpdt.core.IType;
31 import net.sourceforge.phpdt.core.JavaModelException;
32 import net.sourceforge.phpdt.core.JavaCore;
33 import net.sourceforge.phpdt.core.jdom.DOMException;
34 import net.sourceforge.phpdt.core.jdom.DOMFactory;
35 import net.sourceforge.phpdt.core.jdom.IDOMCompilationUnit;
36 import net.sourceforge.phpdt.core.jdom.IDOMNode;
37 import net.sourceforge.phpdt.core.jdom.IDOMPackage;
38 import net.sourceforge.phpdt.internal.core.util.Util;
39
40 import org.eclipse.core.resources.IContainer;
41 import org.eclipse.core.resources.IFile;
42 import org.eclipse.core.resources.IFolder;
43 import org.eclipse.core.resources.IResource;
44 import org.eclipse.core.resources.ResourcesPlugin;
45 import org.eclipse.core.runtime.CoreException;
46 import org.eclipse.core.runtime.IPath;
47 import org.eclipse.core.runtime.Path;
48
49 /**
50  * This operation copies/moves/renames a collection of resources from their current
51  * container to a new container, optionally renaming the
52  * elements.
53  * <p>Notes:<ul>
54  *    <li>If there is already an resource with the same name in
55  *    the new container, the operation either overwrites or aborts,
56  *    depending on the collision policy setting. The default setting is
57  *        abort.
58  *
59  *    <li>When a compilation unit is copied to a new package, the
60  *    package declaration in the compilation unit is automatically updated.
61  *
62  *    <li>The collection of elements being copied must all share the
63  *    same type of container.
64  *
65  *    <li>This operation can be used to copy and rename elements within
66  *    the same container. 
67  *
68  *    <li>This operation only copies compilation units and package fragments.
69  *    It does not copy package fragment roots - a platform operation must be used for that.
70  * </ul>
71  *
72  */
73 public class CopyResourceElementsOperation extends MultiOperation {
74         /**
75          * A collection of renamed compilation units.  These cus do
76          * not need to be saved as they no longer exist.
77          */
78         protected ArrayList fRenamedCompilationUnits = null;
79         /**
80          * Table specifying deltas for elements being 
81          * copied/moved/renamed. Keyed by elements' project(s), and
82          * values are the corresponding deltas.
83          */
84         protected Map fDeltasPerProject= new HashMap(1);
85         /**
86          * The <code>DOMFactory</code> used to manipulate the source code of
87          * <code>ICompilationUnit</code>.
88          */
89         protected DOMFactory fFactory;
90         /**
91          * The list of new resources created during this operation.
92          */
93         protected ArrayList fCreatedElements;
94         /**
95          * When executed, this operation will copy the given resources to the
96          * given containers.  The resources and destination containers must be in
97          * the correct order. If there is > 1 destination, the number of destinations
98          * must be the same as the number of resources being copied/moved.
99          */
100         public CopyResourceElementsOperation(IJavaElement[] resourcesToCopy, IJavaElement[] destContainers, boolean force) {
101                 super(resourcesToCopy, destContainers, force);
102                 fFactory = new DOMFactory();
103         }
104         /**
105          * When executed, this operation will copy the given resources to the
106          * given container.
107          */
108         public CopyResourceElementsOperation(IJavaElement[] resourcesToCopy, IJavaElement destContainer, boolean force) {
109                 this(resourcesToCopy, new IJavaElement[]{destContainer}, force);
110         }
111         /**
112          * Returns the children of <code>source</code> which are affected by this operation.
113          * If <code>source</code> is a <code>K_SOURCE</code>, these are the <code>.java</code>
114          * files, if it is a <code>K_BINARY</code>, they are the <code>.class</code> files.
115          */
116         private IResource[] collectResourcesOfInterest(IPackageFragment source) throws JavaModelException {
117                 IJavaElement[] children = source.getChildren();
118                 int childOfInterest = IJavaElement.COMPILATION_UNIT;
119 //              if (source.getKind() == IPackageFragmentRoot.K_BINARY) {
120 //                      childOfInterest = IJavaElement.CLASS_FILE;
121 //              }
122                 ArrayList correctKindChildren = new ArrayList(children.length);
123                 for (int i = 0; i < children.length; i++) {
124                         IJavaElement child = children[i];
125                         if (child.getElementType() == childOfInterest) {
126                                 correctKindChildren.add(child.getResource());
127                         }
128                 }
129                 // Gather non-java resources
130 //              Object[] nonJavaResources = source.getNonJavaResources();
131 //              int actualNonJavaResourceCount = 0;
132 //              for (int i = 0, max = nonJavaResources.length; i < max; i++){
133 //                      if (nonJavaResources[i] instanceof IResource) actualNonJavaResourceCount++;
134 //              }
135 //              IResource[] actualNonJavaResources = new IResource[actualNonJavaResourceCount];
136 //              for (int i = 0, max = nonJavaResources.length, index = 0; i < max; i++){
137 //                      if (nonJavaResources[i] instanceof IResource) actualNonJavaResources[index++] = (IResource)nonJavaResources[i];
138 //              }
139                 
140 //              if (actualNonJavaResourceCount != 0) {
141 //                      int correctKindChildrenSize = correctKindChildren.size();
142 //                      IResource[] result = new IResource[correctKindChildrenSize + actualNonJavaResourceCount];
143 //                      correctKindChildren.toArray(result);
144 //                      System.arraycopy(actualNonJavaResources, 0, result, correctKindChildrenSize, actualNonJavaResourceCount);
145 //                      return result;
146 //              } else {
147                         IResource[] result = new IResource[correctKindChildren.size()];
148                         correctKindChildren.toArray(result);
149                         return result;
150 //              }
151         }
152         /**
153          * Creates any destination package fragment(s) which do not exists yet.
154          */
155         private void createNeededPackageFragments(IContainer sourceFolder, IPackageFragmentRoot root, String newFragName, boolean moveFolder) throws JavaModelException {
156                 IContainer parentFolder = (IContainer) root.getResource();
157                 JavaElementDelta projectDelta = null;
158                 String[] names = net.sourceforge.phpdt.internal.core.util.Util.getTrimmedSimpleNames(newFragName);
159                 StringBuffer sideEffectPackageName = new StringBuffer();
160                 char[][] exclusionsPatterns = ((PackageFragmentRoot)root).fullExclusionPatternChars();
161                 for (int i = 0; i < names.length; i++) {
162                         String subFolderName = names[i];
163                         sideEffectPackageName.append(subFolderName);
164                         IResource subFolder = parentFolder.findMember(subFolderName);
165                         if (subFolder == null) {
166                                 // create deepest folder only if not a move (folder will be moved in processPackageFragmentResource)
167                                 if (!(moveFolder && i == names.length-1)) {
168                                         createFolder(parentFolder, subFolderName, force);
169                                 }
170                                 parentFolder = parentFolder.getFolder(new Path(subFolderName));
171                                 sourceFolder = sourceFolder.getFolder(new Path(subFolderName));
172                                 if (sourceFolder.isReadOnly()) {
173                                         parentFolder.setReadOnly(true);
174                                 }
175                                 IPackageFragment sideEffectPackage = root.getPackageFragment(sideEffectPackageName.toString());
176                                 if (i < names.length - 1 // all but the last one are side effect packages
177                                                 && !net.sourceforge.phpdt.internal.core.util.Util.isExcluded(parentFolder, exclusionsPatterns)) { 
178                                         if (projectDelta == null) {
179                                                 projectDelta = getDeltaFor(root.getJavaProject());
180                                         }
181                                         projectDelta.added(sideEffectPackage);
182                                 }
183                                 fCreatedElements.add(sideEffectPackage);
184                         } else {
185                                 parentFolder = (IContainer) subFolder;
186                         }
187                         sideEffectPackageName.append('.');
188                 }
189         }
190         /**
191          * Returns the <code>JavaElementDelta</code> for <code>javaProject</code>,
192          * creating it and putting it in <code>fDeltasPerProject</code> if
193          * it does not exist yet.
194          */
195         private JavaElementDelta getDeltaFor(IJavaProject javaProject) {
196                 JavaElementDelta delta = (JavaElementDelta) fDeltasPerProject.get(javaProject);
197                 if (delta == null) {
198                         delta = new JavaElementDelta(javaProject);
199                         fDeltasPerProject.put(javaProject, delta);
200                 }
201                 return delta;
202         }
203         /**
204          * @see MultiOperation
205          */
206         protected String getMainTaskName() {
207                 return net.sourceforge.phpdt.internal.core.util.Util.bind("operation.copyResourceProgress"); //$NON-NLS-1$
208         }
209         /**
210          * Sets the deltas to register the changes resulting from this operation
211          * for this source element and its destination.
212          * If the operation is a cross project operation<ul>
213          * <li>On a copy, the delta should be rooted in the dest project
214          * <li>On a move, two deltas are generated<ul>
215          *                      <li>one rooted in the source project
216          *                      <li>one rooted in the destination project</ul></ul>
217          * If the operation is rooted in a single project, the delta is rooted in that project
218          *       
219          */
220         protected void prepareDeltas(IJavaElement sourceElement, IJavaElement destinationElement, boolean isMove) {
221                 if (net.sourceforge.phpdt.internal.core.util.Util.isExcluded(sourceElement) || net.sourceforge.phpdt.internal.core.util.Util.isExcluded(destinationElement)) return;
222                 IJavaProject destProject = destinationElement.getJavaProject();
223                 if (isMove) {
224                         IJavaProject sourceProject = sourceElement.getJavaProject();
225                         getDeltaFor(sourceProject).movedFrom(sourceElement, destinationElement);
226                         getDeltaFor(destProject).movedTo(destinationElement, sourceElement);
227                 } else {
228                         getDeltaFor(destProject).added(destinationElement);
229                 }
230         }
231         /**
232          * Copies/moves a compilation unit with the name <code>newCUName</code>
233          * to the destination package.<br>
234          * The package statement in the compilation unit is updated if necessary.
235          * The main type of the compilation unit is renamed if necessary.
236          *
237          * @exception JavaModelException if the operation is unable to
238          * complete
239          */
240         private void processCompilationUnitResource(ICompilationUnit source, IPackageFragment dest) throws JavaModelException {
241                 String newCUName = getNewNameFor(source);
242                 String destName = (newCUName != null) ? newCUName : source.getElementName();
243                 String newContent = updatedContent(source, dest, newCUName); // null if unchanged
244         
245                 // copy resource
246                 IFile sourceResource = (IFile)(source.isWorkingCopy() ? source.getOriginalElement() : source).getResource();
247                 IContainer destFolder = (IContainer)dest.getResource(); // can be an IFolder or an IProject
248                 IFile destFile = destFolder.getFile(new Path(destName));
249                 if (!destFile.equals(sourceResource)) {
250                         try {
251                                 if (destFile.exists()) {
252                                         if (force) {
253                                                 // we can remove it
254                                                 deleteResource(destFile, IResource.KEEP_HISTORY);
255                                         } else {
256                                                 // abort
257                                                 throw new JavaModelException(new JavaModelStatus(
258                                                         IJavaModelStatusConstants.NAME_COLLISION, 
259                                                         Util.bind("status.nameCollision", destFile.getFullPath().toString()))); //$NON-NLS-1$
260                                         }
261                                 }
262                                 int flags = force ? IResource.FORCE : IResource.NONE;
263                                 if (this.isMove()) {
264                                         flags |= IResource.KEEP_HISTORY;
265                                         sourceResource.move(destFile.getFullPath(), flags, getSubProgressMonitor(1));
266                                 } else {
267                                         if (newContent != null) flags |= IResource.KEEP_HISTORY;
268                                         sourceResource.copy(destFile.getFullPath(), flags, getSubProgressMonitor(1));
269                                 }
270                                 this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
271                         } catch (JavaModelException e) {
272                                 throw e;
273                         } catch (CoreException e) {
274                                 throw new JavaModelException(e);
275                         }
276         
277                         // update new resource content
278                         try {
279                                 if (newContent != null){
280                                         String encoding = source.getJavaProject().getOption(JavaCore.CORE_ENCODING, true);
281                                         destFile.setContents(
282                                                 new ByteArrayInputStream(encoding == null ? newContent.getBytes() : newContent.getBytes(encoding)), 
283                                                 force ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY,
284                                                 getSubProgressMonitor(1));
285                                 }
286                         } catch(IOException e) {
287                                 throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
288                         } catch (CoreException e) {
289                                 throw new JavaModelException(e);
290                         }
291                 
292                         // register the correct change deltas
293                         ICompilationUnit destCU = dest.getCompilationUnit(destName);
294                         prepareDeltas(source, destCU, isMove());
295                         if (newCUName != null) {
296                                 //the main type has been renamed
297                                 String oldName = source.getElementName();
298                                 oldName = oldName.substring(0, oldName.length() - 5);
299                                 String newName = newCUName;
300                                 newName = newName.substring(0, newName.length() - 5);
301                                 prepareDeltas(source.getType(oldName), destCU.getType(newName), isMove());
302                         }
303                 } else {
304                         if (!force) {
305                                 throw new JavaModelException(new JavaModelStatus(
306                                         IJavaModelStatusConstants.NAME_COLLISION, 
307                                         Util.bind("status.nameCollision", destFile.getFullPath().toString()))); //$NON-NLS-1$
308                         }
309                         // update new resource content
310                         // in case we do a saveas on the same resource we have to simply update the contents
311                         // see http://dev.eclipse.org/bugs/show_bug.cgi?id=9351
312                         try {
313                                 if (newContent != null){
314                                         String encoding = source.getJavaProject().getOption(JavaCore.CORE_ENCODING, true);
315                                         destFile.setContents(
316                                                 new ByteArrayInputStream(encoding == null ? newContent.getBytes() : newContent.getBytes(encoding)), 
317                                                 force ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY, 
318                                                 getSubProgressMonitor(1));
319                                 }
320                         } catch(IOException e) {
321                                 throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
322                         } catch (CoreException e) {
323                                 throw new JavaModelException(e);
324                         }
325                 }
326         }
327         /**
328          * Process all of the changed deltas generated by this operation.
329          */
330         protected void processDeltas() {
331                 for (Iterator deltas = this.fDeltasPerProject.values().iterator(); deltas.hasNext();){
332                         addDelta((IJavaElementDelta) deltas.next());
333                 }
334         }
335         /**
336          * @see MultiOperation
337          * This method delegates to <code>processCompilationUnitResource</code> or
338          * <code>processPackageFragmentResource</code>, depending on the type of
339          * <code>element</code>.
340          */
341         protected void processElement(IJavaElement element) throws JavaModelException {
342                 IJavaElement dest = getDestinationParent(element);
343                 switch (element.getElementType()) {
344                         case IJavaElement.COMPILATION_UNIT :
345                                 processCompilationUnitResource((ICompilationUnit) element, (IPackageFragment) dest);
346                                 fCreatedElements.add(((IPackageFragment) dest).getCompilationUnit(element.getElementName()));
347                                 break;
348                         case IJavaElement.PACKAGE_FRAGMENT :
349                                 processPackageFragmentResource((IPackageFragment) element, (IPackageFragmentRoot) dest, getNewNameFor(element));
350                                 break;
351                         default :
352                                 throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element));
353                 }
354         }
355         /**
356          * @see MultiOperation
357          * Overridden to allow special processing of <code>JavaElementDelta</code>s
358          * and <code>fResultElements</code>.
359          */
360         protected void processElements() throws JavaModelException {
361                 fCreatedElements = new ArrayList(fElementsToProcess.length);
362                 try {
363                         super.processElements();
364                 } catch (JavaModelException jme) {
365                         throw jme;
366                 } finally {
367                         resultElements = new IJavaElement[fCreatedElements.size()];
368                         fCreatedElements.toArray(resultElements);
369                         processDeltas();
370                 }
371         }
372         
373         /**
374          * Copies/moves a package fragment with the name <code>newName</code>
375          * to the destination package.<br>
376          *
377          * @exception JavaModelException if the operation is unable to
378          * complete
379          */
380         private void processPackageFragmentResource(IPackageFragment source, IPackageFragmentRoot root, String newName) throws JavaModelException {
381                 try {
382                         String newFragName = (newName == null) ? source.getElementName() : newName;
383                         IPackageFragment newFrag = root.getPackageFragment(newFragName);
384                         IResource[] resources = collectResourcesOfInterest(source);
385                         
386                         // if isMove() can we move the folder itself ? (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=22458)
387                         boolean shouldMoveFolder = isMove() && !newFrag.getResource().exists(); // if new pkg fragment exists, it is an override
388                         IFolder srcFolder = (IFolder)source.getResource();
389                         IPath destPath = newFrag.getPath();
390                         if (shouldMoveFolder) {
391                                 // check if destination is not included in source
392                                 if (srcFolder.getFullPath().isPrefixOf(destPath)) {
393                                         shouldMoveFolder = false;
394                                 } else {
395                                         // check if there are no sub-packages
396                                         IResource[] members = srcFolder.members();
397                                         for (int i = 0; i < members.length; i++) {
398                                                 if ( members[i] instanceof IFolder) {
399                                                         shouldMoveFolder = false;
400                                                         break;
401                                                 }
402                                         }
403                                 }       
404                         }
405                         createNeededPackageFragments((IContainer) source.getParent().getResource(), root, newFragName, shouldMoveFolder);
406         
407                         // Process resources
408                         if (shouldMoveFolder) {
409                                 // move underlying resource
410                                 srcFolder.move(destPath, force, true /* keep history */, getSubProgressMonitor(1));
411                                 this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
412                         } else {
413                                 // process the leaf resources
414                                 if (resources.length > 0) {
415                                         if (isRename()) {
416                                                 if (! destPath.equals(source.getPath())) {
417                                                         moveResources(resources, destPath);
418                                                 }
419                                         } else if (isMove()) {
420                                                 // we need to delete this resource if this operation wants to override existing resources
421                                                 for (int i = 0, max = resources.length; i < max; i++) {
422                                                         IResource destinationResource = ResourcesPlugin.getWorkspace().getRoot().findMember(destPath.append(resources[i].getName()));
423                                                         if (destinationResource != null) {
424                                                                 if (force) {
425                                                                         deleteResource(destinationResource, IResource.KEEP_HISTORY);
426                                                                 } else {
427                                                                         throw new JavaModelException(new JavaModelStatus(
428                                                                                 IJavaModelStatusConstants.NAME_COLLISION, 
429                                                                                 Util.bind("status.nameCollision", destinationResource.getFullPath().toString()))); //$NON-NLS-1$
430                                                                 }
431                                                         }
432                                                 }
433                                                 moveResources(resources, destPath);
434                                         } else {
435                                                 // we need to delete this resource if this operation wants to override existing resources
436                                                 for (int i = 0, max = resources.length; i < max; i++) {
437                                                         IResource destinationResource = ResourcesPlugin.getWorkspace().getRoot().findMember(destPath.append(resources[i].getName()));
438                                                         if (destinationResource != null) {
439                                                                 if (force) {
440                                                                         // we need to delete this resource if this operation wants to override existing resources
441                                                                         deleteResource(destinationResource, IResource.KEEP_HISTORY);
442                                                                 } else {
443                                                                         throw new JavaModelException(new JavaModelStatus(
444                                                                                 IJavaModelStatusConstants.NAME_COLLISION, 
445                                                                                 Util.bind("status.nameCollision", destinationResource.getFullPath().toString()))); //$NON-NLS-1$
446                                                                 }
447                                                         }
448                                                 }
449                                                 copyResources(resources, destPath);
450                                         }
451                                 }
452                         }
453         
454                         // Discard empty old package (if still empty after the rename)
455                         boolean isEmpty = true;
456                         if (isMove()) {
457                                 // delete remaining files in this package (.class file in the case where Proj=src=bin)
458                                 if (srcFolder.exists()) {
459                                         IResource[] remaingFiles = srcFolder.members();
460                                         for (int i = 0, length = remaingFiles.length; i < length; i++) {
461                                                 IResource file = remaingFiles[i];
462                                                 if (file instanceof IFile) {
463                                                         this.deleteResource(file, IResource.FORCE | IResource.KEEP_HISTORY);
464                                                 } else {
465                                                         isEmpty = false;
466                                                 }
467                                         }
468                                 }
469                                 if (isEmpty) {
470                                         IResource rootResource;
471                                         // check if source is included in destination
472                                         if (destPath.isPrefixOf(srcFolder.getFullPath())) {
473                                                 rootResource = newFrag.getResource();
474                                         } else {
475                                                 rootResource =  source.getParent().getResource();
476                                         }
477                                         
478                                         // delete recursively empty folders
479                                         deleteEmptyPackageFragment(source, false, rootResource);
480                                 }
481                         }
482         
483                         // Update package statement in compilation unit if needed
484                         if (!newFrag.getElementName().equals(source.getElementName())) { // if package has been renamed, update the compilation units
485                                 for (int i = 0; i < resources.length; i++) {
486                                         if (resources[i].getName().endsWith(".java")) { //$NON-NLS-1$
487                                                 // we only consider potential compilation units
488                                                 ICompilationUnit cu = newFrag.getCompilationUnit(resources[i].getName());
489                                                 IDOMCompilationUnit domCU = fFactory.createCompilationUnit(cu.getSource(), cu.getElementName());
490                                                 if (domCU != null) {
491                                                         updatePackageStatement(domCU, newFragName);
492                                                         IBuffer buffer = cu.getBuffer();
493                                                         if (buffer == null) continue;
494                                                         String bufferContents = buffer.getContents();
495                                                         if (bufferContents == null) continue;
496                                                         String domCUContents = domCU.getContents();
497                                                         String cuContents = null;
498                                                         if (domCUContents != null) {
499                                                                 cuContents = net.sourceforge.phpdt.internal.core.util.Util.normalizeCRs(domCU.getContents(), bufferContents);
500                                                         } else {
501                                                                 // See PR http://dev.eclipse.org/bugs/show_bug.cgi?id=11285
502                                                                 cuContents = bufferContents;//$NON-NLS-1$
503                                                         }
504                                                         buffer.setContents(cuContents);
505                                                         cu.save(null, false);
506                                                 }
507                                         }
508                                 }
509                         }
510         
511                         //register the correct change deltas
512                         prepareDeltas(source, newFrag, isMove() && isEmpty);
513                 } catch (DOMException dom) {
514                         throw new JavaModelException(dom, IJavaModelStatusConstants.DOM_EXCEPTION);
515                 } catch (JavaModelException e) {
516                         throw e;
517                 } catch (CoreException ce) {
518                         throw new JavaModelException(ce);
519                 }
520         }
521         /**
522          * Updates the content of <code>cu</code>, modifying the type name and/or package
523          * declaration as necessary.
524          *
525          * @return the new source
526          */
527         private String updatedContent(ICompilationUnit cu, IPackageFragment dest, String newName) throws JavaModelException {
528                 String currPackageName = cu.getParent().getElementName();
529                 String destPackageName = dest.getElementName();
530                 if (currPackageName.equals(destPackageName) && newName == null) {
531                         return null; //nothing to change
532                 } else {
533                         String typeName = cu.getElementName();
534                         typeName = typeName.substring(0, typeName.length() - 5);
535                         IDOMCompilationUnit cuDOM = null;
536                         IBuffer buffer = cu.getBuffer();
537                         if (buffer == null) return null;
538                         char[] contents = buffer.getCharacters();
539                         if (contents == null) return null;
540                         cuDOM = fFactory.createCompilationUnit(contents, typeName);
541                         updateTypeName(cu, cuDOM, cu.getElementName(), newName);
542                         updatePackageStatement(cuDOM, destPackageName);
543                         return cuDOM.getContents();
544                 }
545         }
546         /**
547          * Makes sure that <code>cu</code> declares to be in the <code>pkgName</code> package.
548          */
549         private void updatePackageStatement(IDOMCompilationUnit domCU, String pkgName) throws JavaModelException {
550                 boolean defaultPackage = pkgName.equals(IPackageFragment.DEFAULT_PACKAGE_NAME);
551                 boolean seenPackageNode = false;
552                 Enumeration enum = domCU.getChildren();
553                 while (enum.hasMoreElements()) {
554                         IDOMNode node = (IDOMNode) enum.nextElement();
555                         if (node.getNodeType() == IDOMNode.PACKAGE) {
556                                 if (! defaultPackage) {
557                                         node.setName(pkgName);
558                                 } else {
559                                         node.remove();
560                                 }
561                                 seenPackageNode = true;
562                                 break;
563                         }
564                 }
565                 if (!seenPackageNode && !defaultPackage) {
566                         //the cu was in a default package...no package declaration
567                         //create the new package declaration as the first child of the cu
568 //                      IDOMPackage pkg = fFactory.createPackage("package " + pkgName + ";" + net.sourceforge.phpdt.internal.compiler.util.Util.LINE_SEPARATOR); //$NON-NLS-1$ //$NON-NLS-2$
569 //                      IDOMNode firstChild = domCU.getFirstChild();
570 //                      if (firstChild != null) {
571 //                              firstChild.insertSibling(pkg);
572 //                      } // else the cu was empty: leave it empty
573                 }
574         }
575                 /**
576                  * Renames the main type in <code>cu</code>.
577                  */
578                 private void updateTypeName(ICompilationUnit cu, IDOMCompilationUnit domCU, String oldName, String newName) throws JavaModelException {
579                         if (newName != null) {
580                                 if (fRenamedCompilationUnits == null) {
581                                         fRenamedCompilationUnits= new ArrayList(1);
582                                 }
583                                 fRenamedCompilationUnits.add(cu);
584                                 String oldTypeName= oldName.substring(0, oldName.length() - 5);
585                                 String newTypeName= newName.substring(0, newName.length() - 5);
586                                 // update main type name
587                                 IType[] types = cu.getTypes();
588                                 for (int i = 0, max = types.length; i < max; i++) {
589                                         IType currentType = types[i];
590                                         if (currentType.getElementName().equals(oldTypeName)) {
591                                                 IDOMNode typeNode = ((JavaElement) currentType).findNode(domCU);
592                                                 if (typeNode != null) {
593                                                         typeNode.setName(newTypeName);
594                                                 }
595                                         }
596                                 }
597                         }
598                 }
599         /**
600          * Possible failures:
601          * <ul>
602          *  <li>NO_ELEMENTS_TO_PROCESS - no elements supplied to the operation
603          *      <li>INDEX_OUT_OF_BOUNDS - the number of renamings supplied to the operation
604          *              does not match the number of elements that were supplied.
605          * </ul>
606          */
607         protected IJavaModelStatus verify() {
608                 IJavaModelStatus status = super.verify();
609                 if (!status.isOK()) {
610                         return status;
611                 }
612         
613                 if (fRenamingsList != null && fRenamingsList.length != fElementsToProcess.length) {
614                         return new JavaModelStatus(IJavaModelStatusConstants.INDEX_OUT_OF_BOUNDS);
615                 }
616                 return JavaModelStatus.VERIFIED_OK;
617         }
618         /**
619          * @see MultiOperation
620          */
621         protected void verify(IJavaElement element) throws JavaModelException {
622                 if (element == null || !element.exists())
623                         error(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, element);
624                         
625                 if (element.isReadOnly() && (isRename() || isMove()))
626                         error(IJavaModelStatusConstants.READ_ONLY, element);
627
628                 IResource resource = element.getResource();
629                 if (resource instanceof IFolder) {
630                         if (resource.isLinked()) {
631                                 error(JavaModelStatus.INVALID_RESOURCE, element);
632                         }
633                 }
634         
635                 int elementType = element.getElementType();
636         
637                 if (elementType == IJavaElement.COMPILATION_UNIT) {
638                         if (isMove() && ((ICompilationUnit) element).isWorkingCopy())
639                                 error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
640                 } else if (elementType != IJavaElement.PACKAGE_FRAGMENT) {
641                         error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
642                 }
643                 
644                 JavaElement dest = (JavaElement) getDestinationParent(element);
645                 verifyDestination(element, dest);
646                 if (fRenamings != null) {
647                         verifyRenaming(element);
648                 }
649 }
650 }