KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > CopyResourceElementsOperation


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.core;
12
13 import java.util.*;
14
15 import org.eclipse.core.resources.*;
16 import org.eclipse.core.runtime.CoreException;
17 import org.eclipse.core.runtime.IPath;
18 import org.eclipse.core.runtime.Path;
19 import org.eclipse.jdt.core.*;
20 import org.eclipse.jdt.core.dom.AST;
21 import org.eclipse.jdt.core.dom.ASTParser;
22 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
23 import org.eclipse.jdt.core.dom.CompilationUnit;
24 import org.eclipse.jdt.core.dom.MethodDeclaration;
25 import org.eclipse.jdt.core.dom.Name;
26 import org.eclipse.jdt.core.dom.PackageDeclaration;
27 import org.eclipse.jdt.core.dom.SimpleName;
28 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
29 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
30 import org.eclipse.jdt.internal.core.util.Messages;
31 import org.eclipse.jdt.internal.core.util.Util;
32 import org.eclipse.jface.text.BadLocationException;
33 import org.eclipse.jface.text.IDocument;
34 import org.eclipse.text.edits.TextEdit;
35
36 /**
37  * This operation copies/moves/renames a collection of resources from their current
38  * container to a new container, optionally renaming the
39  * elements.
40  * <p>Notes:<ul>
41  * <li>If there is already an resource with the same name in
42  * the new container, the operation either overwrites or aborts,
43  * depending on the collision policy setting. The default setting is
44  * abort.
45  *
46  * <li>When a compilation unit is copied to a new package, the
47  * package declaration in the compilation unit is automatically updated.
48  *
49  * <li>The collection of elements being copied must all share the
50  * same type of container.
51  *
52  * <li>This operation can be used to copy and rename elements within
53  * the same container.
54  *
55  * <li>This operation only copies compilation units and package fragments.
56  * It does not copy package fragment roots - a platform operation must be used for that.
57  * </ul>
58  *
59  */

60 public class CopyResourceElementsOperation extends MultiOperation implements SuffixConstants {
61     /**
62      * The list of new resources created during this operation.
63      */

64     protected ArrayList createdElements;
65     /**
66      * Table specifying deltas for elements being
67      * copied/moved/renamed. Keyed by elements' project(s), and
68      * values are the corresponding deltas.
69      */

70     protected Map deltasPerProject = new HashMap(1);
71     /**
72      * The <code>ASTParser</code> used to manipulate the source code of
73      * <code>ICompilationUnit</code>.
74      */

75     protected ASTParser parser;
76     /**
77      * When executed, this operation will copy the given resources to the
78      * given container.
79      */

80     public CopyResourceElementsOperation(IJavaElement[] resourcesToCopy, IJavaElement destContainer, boolean force) {
81         this(resourcesToCopy, new IJavaElement[]{destContainer}, force);
82     }
83     /**
84      * When executed, this operation will copy the given resources to the
85      * given containers. The resources and destination containers must be in
86      * the correct order. If there is > 1 destination, the number of destinations
87      * must be the same as the number of resources being copied/moved.
88      */

89     public CopyResourceElementsOperation(IJavaElement[] resourcesToCopy, IJavaElement[] destContainers, boolean force) {
90         super(resourcesToCopy, destContainers, force);
91         initializeASTParser();
92     }
93     private void initializeASTParser() {
94         this.parser = ASTParser.newParser(AST.JLS3);
95     }
96     /**
97      * Returns the children of <code>source</code> which are affected by this operation.
98      * If <code>source</code> is a <code>K_SOURCE</code>, these are the <code>.java</code>
99      * files, if it is a <code>K_BINARY</code>, they are the <code>.class</code> files.
100      */

101     private IResource[] collectResourcesOfInterest(IPackageFragment source) throws JavaModelException {
102         IJavaElement[] children = source.getChildren();
103         int childOfInterest = IJavaElement.COMPILATION_UNIT;
104         if (source.getKind() == IPackageFragmentRoot.K_BINARY) {
105             childOfInterest = IJavaElement.CLASS_FILE;
106         }
107         ArrayList correctKindChildren = new ArrayList(children.length);
108         for (int i = 0; i < children.length; i++) {
109             IJavaElement child = children[i];
110             if (child.getElementType() == childOfInterest) {
111                 correctKindChildren.add(child.getResource());
112             }
113         }
114         // Gather non-java resources
115
Object JavaDoc[] nonJavaResources = source.getNonJavaResources();
116         int actualNonJavaResourceCount = 0;
117         for (int i = 0, max = nonJavaResources.length; i < max; i++){
118             if (nonJavaResources[i] instanceof IResource) actualNonJavaResourceCount++;
119         }
120         IResource[] actualNonJavaResources = new IResource[actualNonJavaResourceCount];
121         for (int i = 0, max = nonJavaResources.length, index = 0; i < max; i++){
122             if (nonJavaResources[i] instanceof IResource) actualNonJavaResources[index++] = (IResource)nonJavaResources[i];
123         }
124         
125         if (actualNonJavaResourceCount != 0) {
126             int correctKindChildrenSize = correctKindChildren.size();
127             IResource[] result = new IResource[correctKindChildrenSize + actualNonJavaResourceCount];
128             correctKindChildren.toArray(result);
129             System.arraycopy(actualNonJavaResources, 0, result, correctKindChildrenSize, actualNonJavaResourceCount);
130             return result;
131         } else {
132             IResource[] result = new IResource[correctKindChildren.size()];
133             correctKindChildren.toArray(result);
134             return result;
135         }
136     }
137     /**
138      * Creates any destination package fragment(s) which do not exists yet.
139      * Return true if a read-only package fragment has been found among package fragments, false otherwise
140      */

141     private boolean createNeededPackageFragments(IContainer sourceFolder, PackageFragmentRoot root, String JavaDoc[] newFragName, boolean moveFolder) throws JavaModelException {
142         boolean containsReadOnlyPackageFragment = false;
143         IContainer parentFolder = (IContainer) root.getResource();
144         JavaElementDelta projectDelta = null;
145         String JavaDoc[] sideEffectPackageName = null;
146         char[][] inclusionPatterns = root.fullInclusionPatternChars();
147         char[][] exclusionPatterns = root.fullExclusionPatternChars();
148         for (int i = 0; i < newFragName.length; i++) {
149             String JavaDoc subFolderName = newFragName[i];
150             sideEffectPackageName = Util.arrayConcat(sideEffectPackageName, subFolderName);
151             IResource subFolder = parentFolder.findMember(subFolderName);
152             if (subFolder == null) {
153                 // create deepest folder only if not a move (folder will be moved in processPackageFragmentResource)
154
if (!(moveFolder && i == newFragName.length-1)) {
155                     createFolder(parentFolder, subFolderName, force);
156                 }
157                 parentFolder = parentFolder.getFolder(new Path(subFolderName));
158                 sourceFolder = sourceFolder.getFolder(new Path(subFolderName));
159                 if (Util.isReadOnly(sourceFolder)) {
160                     containsReadOnlyPackageFragment = true;
161                 }
162                 IPackageFragment sideEffectPackage = root.getPackageFragment(sideEffectPackageName);
163                 if (i < newFragName.length - 1 // all but the last one are side effect packages
164
&& !Util.isExcluded(parentFolder, inclusionPatterns, exclusionPatterns)) {
165                     if (projectDelta == null) {
166                         projectDelta = getDeltaFor(root.getJavaProject());
167                     }
168                     projectDelta.added(sideEffectPackage);
169                 }
170                 createdElements.add(sideEffectPackage);
171             } else {
172                 parentFolder = (IContainer) subFolder;
173             }
174         }
175         return containsReadOnlyPackageFragment;
176     }
177     
178     /**
179      * Returns the <code>JavaElementDelta</code> for <code>javaProject</code>,
180      * creating it and putting it in <code>fDeltasPerProject</code> if
181      * it does not exist yet.
182      */

183     private JavaElementDelta getDeltaFor(IJavaProject javaProject) {
184         JavaElementDelta delta = (JavaElementDelta) deltasPerProject.get(javaProject);
185         if (delta == null) {
186             delta = new JavaElementDelta(javaProject);
187             deltasPerProject.put(javaProject, delta);
188         }
189         return delta;
190     }
191     /**
192      * @see MultiOperation
193      */

194     protected String JavaDoc getMainTaskName() {
195         return Messages.operation_copyResourceProgress;
196     }
197     /**
198      * Sets the deltas to register the changes resulting from this operation
199      * for this source element and its destination.
200      * If the operation is a cross project operation<ul>
201      * <li>On a copy, the delta should be rooted in the dest project
202      * <li>On a move, two deltas are generated<ul>
203      * <li>one rooted in the source project
204      * <li>one rooted in the destination project</ul></ul>
205      * If the operation is rooted in a single project, the delta is rooted in that project
206      *
207      */

208     protected void prepareDeltas(IJavaElement sourceElement, IJavaElement destinationElement, boolean isMove) {
209         if (Util.isExcluded(sourceElement) || Util.isExcluded(destinationElement)) return;
210         IJavaProject destProject = destinationElement.getJavaProject();
211         if (isMove) {
212             IJavaProject sourceProject = sourceElement.getJavaProject();
213             getDeltaFor(sourceProject).movedFrom(sourceElement, destinationElement);
214             getDeltaFor(destProject).movedTo(destinationElement, sourceElement);
215         } else {
216             getDeltaFor(destProject).added(destinationElement);
217         }
218     }
219     /**
220      * Copies/moves a compilation unit with the name <code>newCUName</code>
221      * to the destination package.<br>
222      * The package statement in the compilation unit is updated if necessary.
223      * The main type of the compilation unit is renamed if necessary.
224      *
225      * @exception JavaModelException if the operation is unable to
226      * complete
227      */

228     private void processCompilationUnitResource(ICompilationUnit source, PackageFragment dest) throws JavaModelException {
229         String JavaDoc newCUName = getNewNameFor(source);
230         String JavaDoc destName = (newCUName != null) ? newCUName : source.getElementName();
231         ASTRewrite rewrite = updateContent(source, dest, newCUName); // null if unchanged
232

233         // TODO (frederic) remove when bug 67606 will be fixed (bug 67823)
234
// store encoding (fix bug 66898)
235
IFile sourceResource = (IFile)source.getResource();
236         String JavaDoc sourceEncoding = null;
237         try {
238             sourceEncoding = sourceResource.getCharset(false);
239         }
240         catch (CoreException ce) {
241             // no problem, use default encoding
242
}
243         // end todo
244
// copy resource
245
IContainer destFolder = (IContainer)dest.getResource(); // can be an IFolder or an IProject
246
IFile destFile = destFolder.getFile(new Path(destName));
247         org.eclipse.jdt.internal.core.CompilationUnit destCU = new org.eclipse.jdt.internal.core.CompilationUnit(dest, destName, DefaultWorkingCopyOwner.PRIMARY);
248         if (!destFile.equals(sourceResource)) {
249             try {
250                 if (!destCU.isWorkingCopy()) {
251                     if (destFile.exists()) {
252                         if (this.force) {
253                             // we can remove it
254
deleteResource(destFile, IResource.KEEP_HISTORY);
255                             destCU.close(); // ensure the in-memory buffer for the dest CU is closed
256
} else {
257                             // abort
258
throw new JavaModelException(new JavaModelStatus(
259                                 IJavaModelStatusConstants.NAME_COLLISION,
260                                 Messages.bind(Messages.status_nameCollision, destFile.getFullPath().toString())));
261                         }
262                     }
263                     int flags = this.force ? IResource.FORCE : IResource.NONE;
264                     if (this.isMove()) {
265                         flags |= IResource.KEEP_HISTORY;
266                         sourceResource.move(destFile.getFullPath(), flags, getSubProgressMonitor(1));
267                     } else {
268                         if (rewrite != null) flags |= IResource.KEEP_HISTORY;
269                         sourceResource.copy(destFile.getFullPath(), flags, getSubProgressMonitor(1));
270                     }
271                     setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
272                 } else {
273                     destCU.getBuffer().setContents(source.getBuffer().getContents());
274                 }
275             } catch (JavaModelException e) {
276                 throw e;
277             } catch (CoreException e) {
278                 throw new JavaModelException(e);
279             }
280     
281             // update new resource content
282
if (rewrite != null){
283                 boolean wasReadOnly = destFile.isReadOnly();
284                 try {
285                     saveContent(dest, destName, rewrite, sourceEncoding, destFile);
286                 } catch (CoreException e) {
287                     if (e instanceof JavaModelException) throw (JavaModelException) e;
288                     throw new JavaModelException(e);
289                 } finally {
290                     Util.setReadOnly(destFile, wasReadOnly);
291                 }
292             }
293         
294             // register the correct change deltas
295
prepareDeltas(source, destCU, isMove());
296             if (newCUName != null) {
297                 //the main type has been renamed
298
String JavaDoc oldName = Util.getNameWithoutJavaLikeExtension(source.getElementName());
299                 String JavaDoc newName = Util.getNameWithoutJavaLikeExtension(newCUName);
300                 prepareDeltas(source.getType(oldName), destCU.getType(newName), isMove());
301             }
302         } else {
303             if (!this.force) {
304                 throw new JavaModelException(new JavaModelStatus(
305                     IJavaModelStatusConstants.NAME_COLLISION,
306                     Messages.bind(Messages.status_nameCollision, destFile.getFullPath().toString())));
307             }
308             // update new resource content
309
// in case we do a saveas on the same resource we have to simply update the contents
310
// see http://dev.eclipse.org/bugs/show_bug.cgi?id=9351
311
if (rewrite != null){
312                 saveContent(dest, destName, rewrite, sourceEncoding, destFile);
313             }
314         }
315     }
316     /**
317      * Process all of the changed deltas generated by this operation.
318      */

319     protected void processDeltas() {
320         for (Iterator deltas = this.deltasPerProject.values().iterator(); deltas.hasNext();){
321             addDelta((IJavaElementDelta) deltas.next());
322         }
323     }
324     /**
325      * @see MultiOperation
326      * This method delegates to <code>processCompilationUnitResource</code> or
327      * <code>processPackageFragmentResource</code>, depending on the type of
328      * <code>element</code>.
329      */

330     protected void processElement(IJavaElement element) throws JavaModelException {
331         IJavaElement dest = getDestinationParent(element);
332         switch (element.getElementType()) {
333             case IJavaElement.COMPILATION_UNIT :
334                 processCompilationUnitResource((ICompilationUnit) element, (PackageFragment) dest);
335                 createdElements.add(((IPackageFragment) dest).getCompilationUnit(element.getElementName()));
336                 break;
337             case IJavaElement.PACKAGE_FRAGMENT :
338                 processPackageFragmentResource((PackageFragment) element, (PackageFragmentRoot) dest, getNewNameFor(element));
339                 break;
340             default :
341                 throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element));
342         }
343     }
344     /**
345      * @see MultiOperation
346      * Overridden to allow special processing of <code>JavaElementDelta</code>s
347      * and <code>fResultElements</code>.
348      */

349     protected void processElements() throws JavaModelException {
350         createdElements = new ArrayList(elementsToProcess.length);
351         try {
352             super.processElements();
353         } catch (JavaModelException jme) {
354             throw jme;
355         } finally {
356             resultElements = new IJavaElement[createdElements.size()];
357             createdElements.toArray(resultElements);
358             processDeltas();
359         }
360     }
361     /**
362      * Copies/moves a package fragment with the name <code>newName</code>
363      * to the destination package.<br>
364      *
365      * @exception JavaModelException if the operation is unable to
366      * complete
367      */

368     private void processPackageFragmentResource(PackageFragment source, PackageFragmentRoot root, String JavaDoc newName) throws JavaModelException {
369         try {
370             String JavaDoc[] newFragName = (newName == null) ? source.names : Util.getTrimmedSimpleNames(newName);
371             IPackageFragment newFrag = root.getPackageFragment(newFragName);
372             IResource[] resources = collectResourcesOfInterest(source);
373             
374             // if isMove() can we move the folder itself ? (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=22458)
375
boolean shouldMoveFolder = isMove() && !newFrag.getResource().exists(); // if new pkg fragment exists, it is an override
376
IFolder srcFolder = (IFolder)source.getResource();
377             IPath destPath = newFrag.getPath();
378             if (shouldMoveFolder) {
379                 // check if destination is not included in source
380
if (srcFolder.getFullPath().isPrefixOf(destPath)) {
381                     shouldMoveFolder = false;
382                 } else {
383                     // check if there are no sub-packages
384
IResource[] members = srcFolder.members();
385                     for (int i = 0; i < members.length; i++) {
386                         if ( members[i] instanceof IFolder) {
387                             shouldMoveFolder = false;
388                             break;
389                         }
390                     }
391                 }
392             }
393             boolean containsReadOnlySubPackageFragments = createNeededPackageFragments((IContainer) source.getParent().getResource(), root, newFragName, shouldMoveFolder);
394             boolean sourceIsReadOnly = Util.isReadOnly(srcFolder);
395     
396             // Process resources
397
if (shouldMoveFolder) {
398                 // move underlying resource
399
// TODO Revisit once bug 43044 is fixed
400
if (sourceIsReadOnly) {
401                     Util.setReadOnly(srcFolder, false);
402                 }
403                 srcFolder.move(destPath, force, true /* keep history */, getSubProgressMonitor(1));
404                 if (sourceIsReadOnly) {
405                     Util.setReadOnly(srcFolder, true);
406                 }
407                 setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
408             } else {
409                 // process the leaf resources
410
if (resources.length > 0) {
411                     if (isRename()) {
412                         if (! destPath.equals(source.getPath())) {
413                             moveResources(resources, destPath);
414                         }
415                     } else if (isMove()) {
416                         // we need to delete this resource if this operation wants to override existing resources
417
for (int i = 0, max = resources.length; i < max; i++) {
418                             IResource destinationResource = ResourcesPlugin.getWorkspace().getRoot().findMember(destPath.append(resources[i].getName()));
419                             if (destinationResource != null) {
420                                 if (force) {
421                                     deleteResource(destinationResource, IResource.KEEP_HISTORY);
422                                 } else {
423                                     throw new JavaModelException(new JavaModelStatus(
424                                         IJavaModelStatusConstants.NAME_COLLISION,
425                                         Messages.bind(Messages.status_nameCollision, destinationResource.getFullPath().toString())));
426                                 }
427                             }
428                         }
429                         moveResources(resources, destPath);
430                     } else {
431                         // we need to delete this resource if this operation wants to override existing resources
432
for (int i = 0, max = resources.length; i < max; i++) {
433                             IResource destinationResource = ResourcesPlugin.getWorkspace().getRoot().findMember(destPath.append(resources[i].getName()));
434                             if (destinationResource != null) {
435                                 if (force) {
436                                     // we need to delete this resource if this operation wants to override existing resources
437
deleteResource(destinationResource, IResource.KEEP_HISTORY);
438                                 } else {
439                                     throw new JavaModelException(new JavaModelStatus(
440                                         IJavaModelStatusConstants.NAME_COLLISION,
441                                         Messages.bind(Messages.status_nameCollision, destinationResource.getFullPath().toString())));
442                                 }
443                             }
444                         }
445                         copyResources(resources, destPath);
446                     }
447                 }
448             }
449     
450             // Update package statement in compilation unit if needed
451
if (!Util.equalArraysOrNull(newFragName, source.names)) { // if package has been renamed, update the compilation units
452
char[][] inclusionPatterns = root.fullInclusionPatternChars();
453                 char[][] exclusionPatterns = root.fullExclusionPatternChars();
454                 for (int i = 0; i < resources.length; i++) {
455                     String JavaDoc resourceName = resources[i].getName();
456                     if (Util.isJavaLikeFileName(resourceName)) {
457                         // we only consider potential compilation units
458
ICompilationUnit cu = newFrag.getCompilationUnit(resourceName);
459                         if (Util.isExcluded(cu.getPath(), inclusionPatterns, exclusionPatterns, false/*not a folder*/)) continue;
460                         this.parser.setSource(cu);
461                         CompilationUnit astCU = (CompilationUnit) this.parser.createAST(this.progressMonitor);
462                         AST ast = astCU.getAST();
463                         ASTRewrite rewrite = ASTRewrite.create(ast);
464                         updatePackageStatement(astCU, newFragName, rewrite);
465                         IDocument document = getDocument(cu);
466                         TextEdit edits = rewrite.rewriteAST(document, null);
467                         try {
468                             edits.apply(document);
469                         } catch (BadLocationException e) {
470                             throw new JavaModelException(e, IJavaModelStatusConstants.INVALID_CONTENTS);
471                         }
472                         cu.save(null, false);
473                     }
474                 }
475             }
476             
477             // Discard empty old package (if still empty after the rename)
478
boolean isEmpty = true;
479             if (isMove()) {
480                 // delete remaining files in this package (.class file in the case where Proj=src=bin)
481
// in case of a copy
482
updateReadOnlyPackageFragmentsForMove((IContainer) source.getParent().getResource(), root, newFragName, sourceIsReadOnly);
483                 if (srcFolder.exists()) {
484                     IResource[] remaining = srcFolder.members();
485                     for (int i = 0, length = remaining.length; i < length; i++) {
486                         IResource file = remaining[i];
487                         if (file instanceof IFile) {
488                             if (Util.isReadOnly(file)) {
489                                 Util.setReadOnly(file, false);
490                             }
491                             this.deleteResource(file, IResource.FORCE | IResource.KEEP_HISTORY);
492                         } else {
493                             isEmpty = false;
494                         }
495                     }
496                 }
497                 if (isEmpty) {
498                     IResource rootResource;
499                     // check if source is included in destination
500
if (destPath.isPrefixOf(srcFolder.getFullPath())) {
501                         rootResource = newFrag.getResource();
502                     } else {
503                         rootResource = source.getParent().getResource();
504                     }
505                     
506                     // delete recursively empty folders
507
deleteEmptyPackageFragment(source, false, rootResource);
508                 }
509             } else if (containsReadOnlySubPackageFragments) {
510                 // in case of a copy
511
updateReadOnlyPackageFragmentsForCopy((IContainer) source.getParent().getResource(), root, newFragName);
512             }
513             // workaround for bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=24505
514
if (isEmpty && isMove() && !(Util.isExcluded(source) || Util.isExcluded(newFrag))) {
515                 IJavaProject sourceProject = source.getJavaProject();
516                 getDeltaFor(sourceProject).movedFrom(source, newFrag);
517                 IJavaProject destProject = newFrag.getJavaProject();
518                 getDeltaFor(destProject).movedTo(newFrag, source);
519             }
520         } catch (JavaModelException e) {
521             throw e;
522         } catch (CoreException ce) {
523             throw new JavaModelException(ce);
524         }
525     }
526     private void saveContent(PackageFragment dest, String JavaDoc destName, ASTRewrite rewrite, String JavaDoc sourceEncoding, IFile destFile) throws JavaModelException {
527         try {
528             // TODO (frederic) remove when bug 67606 will be fixed (bug 67823)
529
// fix bug 66898
530
if (sourceEncoding != null) destFile.setCharset(sourceEncoding, this.progressMonitor);
531             // end todo
532
}
533         catch (CoreException ce) {
534             // use no encoding
535
}
536         // when the file was copied, its read-only flag was preserved -> temporary set it to false
537
// note this doesn't interfer with repository providers as this is a new resource that cannot be under
538
// version control yet
539
Util.setReadOnly(destFile, false);
540         ICompilationUnit destCU = dest.getCompilationUnit(destName);
541         IDocument document = getDocument(destCU);
542         TextEdit edits = rewrite.rewriteAST(document, null);
543         try {
544             edits.apply(document);
545         } catch (BadLocationException e) {
546             throw new JavaModelException(e, IJavaModelStatusConstants.INVALID_CONTENTS);
547         }
548         destCU.save(getSubProgressMonitor(1), this.force);
549     }
550     /**
551      * Updates the content of <code>cu</code>, modifying the type name and/or package
552      * declaration as necessary.
553      *
554      * @return an AST rewrite or null if no rewrite needed
555      */

556     private ASTRewrite updateContent(ICompilationUnit cu, PackageFragment dest, String JavaDoc newName) throws JavaModelException {
557         String JavaDoc[] currPackageName = ((PackageFragment) cu.getParent()).names;
558         String JavaDoc[] destPackageName = dest.names;
559         if (Util.equalArraysOrNull(currPackageName, destPackageName) && newName == null) {
560             return null; //nothing to change
561
} else {
562             // ensure cu is consistent (noop if already consistent)
563
cu.makeConsistent(this.progressMonitor);
564             this.parser.setSource(cu);
565             CompilationUnit astCU = (CompilationUnit) this.parser.createAST(this.progressMonitor);
566             AST ast = astCU.getAST();
567             ASTRewrite rewrite = ASTRewrite.create(ast);
568             updateTypeName(cu, astCU, cu.getElementName(), newName, rewrite);
569             updatePackageStatement(astCU, destPackageName, rewrite);
570             return rewrite;
571         }
572     }
573     private void updatePackageStatement(CompilationUnit astCU, String JavaDoc[] pkgName, ASTRewrite rewriter) throws JavaModelException {
574         boolean defaultPackage = pkgName.length == 0;
575         AST ast = astCU.getAST();
576         if (defaultPackage) {
577             // remove existing package statement
578
if (astCU.getPackage() != null)
579                 rewriter.set(astCU, CompilationUnit.PACKAGE_PROPERTY, null, null);
580         } else {
581             org.eclipse.jdt.core.dom.PackageDeclaration pkg = astCU.getPackage();
582             if (pkg != null) {
583                 // rename package statement
584
Name name = ast.newName(pkgName);
585                 rewriter.set(pkg, PackageDeclaration.NAME_PROPERTY, name, null);
586             } else {
587                 // create new package statement
588
pkg = ast.newPackageDeclaration();
589                 pkg.setName(ast.newName(pkgName));
590                 rewriter.set(astCU, CompilationUnit.PACKAGE_PROPERTY, pkg, null);
591             }
592         }
593     }
594     
595     private void updateReadOnlyPackageFragmentsForCopy(IContainer sourceFolder, IPackageFragmentRoot root, String JavaDoc[] newFragName) {
596         IContainer parentFolder = (IContainer) root.getResource();
597         for (int i = 0, length = newFragName.length; i <length; i++) {
598             String JavaDoc subFolderName = newFragName[i];
599             parentFolder = parentFolder.getFolder(new Path(subFolderName));
600             sourceFolder = sourceFolder.getFolder(new Path(subFolderName));
601             if (sourceFolder.exists() && Util.isReadOnly(sourceFolder)) {
602                 Util.setReadOnly(parentFolder, true);
603             }
604         }
605     }
606
607     private void updateReadOnlyPackageFragmentsForMove(IContainer sourceFolder, IPackageFragmentRoot root, String JavaDoc[] newFragName, boolean sourceFolderIsReadOnly) {
608         IContainer parentFolder = (IContainer) root.getResource();
609         for (int i = 0, length = newFragName.length; i < length; i++) {
610             String JavaDoc subFolderName = newFragName[i];
611             parentFolder = parentFolder.getFolder(new Path(subFolderName));
612             sourceFolder = sourceFolder.getFolder(new Path(subFolderName));
613             if ((sourceFolder.exists() && Util.isReadOnly(sourceFolder)) || (i == length - 1 && sourceFolderIsReadOnly)) {
614                 Util.setReadOnly(parentFolder, true);
615                 // the source folder will be deleted anyway (move operation)
616
Util.setReadOnly(sourceFolder, false);
617             }
618         }
619     }
620             /**
621          * Renames the main type in <code>cu</code>.
622          */

623         private void updateTypeName(ICompilationUnit cu, CompilationUnit astCU, String JavaDoc oldName, String JavaDoc newName, ASTRewrite rewriter) throws JavaModelException {
624             if (newName != null) {
625                 String JavaDoc oldTypeName= Util.getNameWithoutJavaLikeExtension(oldName);
626                 String JavaDoc newTypeName= Util.getNameWithoutJavaLikeExtension(newName);
627                 AST ast = astCU.getAST();
628                 // update main type name
629
IType[] types = cu.getTypes();
630                 for (int i = 0, max = types.length; i < max; i++) {
631                     IType currentType = types[i];
632                     if (currentType.getElementName().equals(oldTypeName)) {
633                         AbstractTypeDeclaration typeNode = (AbstractTypeDeclaration) ((JavaElement) currentType).findNode(astCU);
634                         if (typeNode != null) {
635                             // rename type
636
rewriter.replace(typeNode.getName(), ast.newSimpleName(newTypeName), null);
637                             // rename constructors
638
Iterator bodyDeclarations = typeNode.bodyDeclarations().iterator();
639                             while (bodyDeclarations.hasNext()) {
640                                 Object JavaDoc bodyDeclaration = bodyDeclarations.next();
641                                 if (bodyDeclaration instanceof MethodDeclaration) {
642                                     MethodDeclaration methodDeclaration = (MethodDeclaration) bodyDeclaration;
643                                     if (methodDeclaration.isConstructor()) {
644                                         SimpleName methodName = methodDeclaration.getName();
645                                         if (methodName.getIdentifier().equals(oldTypeName)) {
646                                             rewriter.replace(methodName, ast.newSimpleName(newTypeName), null);
647                                         }
648                                     }
649                                 }
650                             }
651                         }
652                     }
653                 }
654             }
655         }
656     /**
657      * Possible failures:
658      * <ul>
659      * <li>NO_ELEMENTS_TO_PROCESS - no elements supplied to the operation
660      * <li>INDEX_OUT_OF_BOUNDS - the number of renamings supplied to the operation
661      * does not match the number of elements that were supplied.
662      * </ul>
663      */

664     protected IJavaModelStatus verify() {
665         IJavaModelStatus status = super.verify();
666         if (!status.isOK()) {
667             return status;
668         }
669     
670         if (this.renamingsList != null && this.renamingsList.length != elementsToProcess.length) {
671             return new JavaModelStatus(IJavaModelStatusConstants.INDEX_OUT_OF_BOUNDS);
672         }
673         return JavaModelStatus.VERIFIED_OK;
674     }
675     /**
676      * @see MultiOperation
677      */

678     protected void verify(IJavaElement element) throws JavaModelException {
679         if (element == null || !element.exists())
680             error(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, element);
681             
682         if (element.isReadOnly() && (isRename() || isMove()))
683             error(IJavaModelStatusConstants.READ_ONLY, element);
684
685         IResource resource = element.getResource();
686         if (resource instanceof IFolder) {
687             if (resource.isLinked()) {
688                 error(IJavaModelStatusConstants.INVALID_RESOURCE, element);
689             }
690         }
691     
692         int elementType = element.getElementType();
693     
694         if (elementType == IJavaElement.COMPILATION_UNIT) {
695             org.eclipse.jdt.internal.core.CompilationUnit compilationUnit = (org.eclipse.jdt.internal.core.CompilationUnit) element;
696             if (isMove() && compilationUnit.isWorkingCopy() && !compilationUnit.isPrimary())
697                 error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
698         } else if (elementType != IJavaElement.PACKAGE_FRAGMENT) {
699             error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
700         }
701         
702         JavaElement dest = (JavaElement) getDestinationParent(element);
703         verifyDestination(element, dest);
704         if (this.renamings != null) {
705             verifyRenaming(element);
706         }
707 }
708 }
709
Popular Tags