001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.corext.refactoring.reorg;
011:
012: import java.util.ArrayList;
013: import java.util.Arrays;
014: import java.util.Iterator;
015: import java.util.List;
016:
017: import org.eclipse.core.runtime.CoreException;
018:
019: import org.eclipse.core.resources.IContainer;
020: import org.eclipse.core.resources.IFile;
021: import org.eclipse.core.resources.IFolder;
022: import org.eclipse.core.resources.IResource;
023: import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
024:
025: import org.eclipse.ltk.core.refactoring.RefactoringStatus;
026: import org.eclipse.ltk.core.refactoring.participants.DeleteArguments;
027: import org.eclipse.ltk.core.refactoring.participants.ParticipantManager;
028: import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant;
029: import org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor;
030: import org.eclipse.ltk.core.refactoring.participants.SharableParticipants;
031:
032: import org.eclipse.jdt.core.ICompilationUnit;
033: import org.eclipse.jdt.core.IJavaElement;
034: import org.eclipse.jdt.core.IJavaProject;
035: import org.eclipse.jdt.core.IPackageFragment;
036: import org.eclipse.jdt.core.IPackageFragmentRoot;
037: import org.eclipse.jdt.core.IType;
038: import org.eclipse.jdt.core.JavaCore;
039: import org.eclipse.jdt.core.JavaModelException;
040:
041: import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil;
042:
043: /**
044: * A modification collector for Java element delete operations.
045: */
046: public class DeleteModifications extends RefactoringModifications {
047:
048: private List/*<IJavaElement>*/fDelete;
049:
050: /**
051: * Contains the actual packages when executing
052: * <code>handlePackageFragmentDelete</code>. This is part of the
053: * algorithm to check if a parent folder can be deleted.
054: */
055: private List/*<IPackageFragment>*/fPackagesToDelete;
056:
057: public DeleteModifications() {
058: fDelete = new ArrayList();
059: fPackagesToDelete = new ArrayList();
060: }
061:
062: public void delete(IResource resource) {
063: getResourceModifications().addDelete(resource);
064: }
065:
066: public void delete(IResource[] resources) {
067: for (int i = 0; i < resources.length; i++) {
068: delete(resources[i]);
069: }
070: }
071:
072: public void delete(IJavaElement[] elements) throws CoreException {
073: for (int i = 0; i < elements.length; i++) {
074: delete(elements[i]);
075: }
076: }
077:
078: public void delete(IJavaElement element) throws CoreException {
079: switch (element.getElementType()) {
080: case IJavaElement.JAVA_MODEL:
081: return;
082: case IJavaElement.JAVA_PROJECT:
083: fDelete.add(element);
084: if (element.getResource() != null)
085: getResourceModifications().addDelete(
086: element.getResource());
087: return;
088: case IJavaElement.PACKAGE_FRAGMENT_ROOT:
089: fDelete.add(element);
090: IResource resource = element.getResource();
091: // Flag an resource change even if we have an archive. If it is
092: // internal (we have a underlying resource then we have a resource
093: // change.
094: if (resource != null)
095: getResourceModifications().addDelete(resource);
096: IJavaProject[] referencingProjects = JavaElementUtil
097: .getReferencingProjects((IPackageFragmentRoot) element);
098: for (int i = 0; i < referencingProjects.length; i++) {
099: IFile classpath = referencingProjects[i].getProject()
100: .getFile(".classpath"); //$NON-NLS-1$
101: getResourceModifications().addChanged(classpath);
102: }
103: return;
104: case IJavaElement.PACKAGE_FRAGMENT:
105: fDelete.add(element);
106: fPackagesToDelete.add(element);
107: return;
108: case IJavaElement.COMPILATION_UNIT:
109: fDelete.add(element);
110: IType[] types = ((ICompilationUnit) element).getTypes();
111: fDelete.addAll(Arrays.asList(types));
112: if (element.getResource() != null)
113: getResourceModifications().addDelete(
114: element.getResource());
115: return;
116: default:
117: fDelete.add(element);
118: }
119:
120: }
121:
122: /**
123: * @return a List of IResources that are removed by package deletes
124: */
125: public List/*<IResource>*/postProcess() throws CoreException {
126: ArrayList resourcesCollector = new ArrayList();
127: for (Iterator iter = fPackagesToDelete.iterator(); iter
128: .hasNext();) {
129: IPackageFragment pack = (IPackageFragment) iter.next();
130: handlePackageFragmentDelete(pack, resourcesCollector);
131: }
132: return resourcesCollector;
133: }
134:
135: public void buildDelta(
136: IResourceChangeDescriptionFactory deltaFactory) {
137: getResourceModifications().buildDelta(deltaFactory);
138: }
139:
140: public RefactoringParticipant[] loadParticipants(
141: RefactoringStatus status, RefactoringProcessor owner,
142: String[] natures, SharableParticipants shared) {
143: List result = new ArrayList();
144: for (Iterator iter = fDelete.iterator(); iter.hasNext();) {
145: result.addAll(Arrays.asList(ParticipantManager
146: .loadDeleteParticipants(status, owner, iter.next(),
147: new DeleteArguments(), natures, shared)));
148: }
149: result.addAll(Arrays.asList(getResourceModifications()
150: .getParticipants(status, owner, natures, shared)));
151: return (RefactoringParticipant[]) result
152: .toArray(new RefactoringParticipant[result.size()]);
153: }
154:
155: /**
156: * This method collects file and folder deletion for notifying
157: * participants. Participants will get notified of
158: *
159: * * deletion of the package (in any case)
160: * * deletion of files within the package if only the files are deleted without
161: * the package folder ("package cleaning")
162: * * deletion of the package folder if it is not only cleared and if its parent
163: * is not removed as well.
164: *
165: * All deleted resources are added to <code>resourcesCollector</code>
166: *
167: * @param resourcesCollector a collector for IResources to be deleted
168: */
169: private void handlePackageFragmentDelete(IPackageFragment pack,
170: ArrayList resourcesCollector) throws CoreException {
171: final IContainer container = (IContainer) pack.getResource();
172: if (container == null)
173: return;
174:
175: final IResource[] members = container.members();
176:
177: /*
178: * Check whether this package is removed completely or only cleared.
179: * The default package can never be removed completely.
180: */
181: if (!pack.isDefaultPackage() && canRemoveCompletely(pack)) {
182: // This package is removed completely, which means its folder will be
183: // deleted as well. We only notify participants of the folder deletion
184: // if the parent folder of this folder will not be deleted as well:
185: boolean parentIsMarked = false;
186: final IPackageFragment parent = JavaElementUtil
187: .getParentSubpackage(pack);
188: if (parent == null) {
189: // "Parent" is the default package which will never be
190: // deleted physically
191: parentIsMarked = false;
192: } else {
193: // Parent is marked if it is in the list
194: parentIsMarked = fPackagesToDelete.contains(parent);
195: }
196:
197: if (parentIsMarked) {
198: // Parent is marked, but is it really deleted or only cleared?
199: if (canRemoveCompletely(parent)) {
200: // Parent can be removed completely, so we do not add
201: // this folder to the list.
202: } else {
203: // Parent cannot be removed completely, but as this folder
204: // can be removed, we notify the participant
205: resourcesCollector.add(container);
206: getResourceModifications().addDelete(container);
207: }
208: } else {
209: // Parent will not be removed, but we will
210: resourcesCollector.add(container);
211: getResourceModifications().addDelete(container);
212: }
213: } else {
214: // This package is only cleared because it has subpackages (=subfolders)
215: // which are not deleted. As the package is only cleared, its folder
216: // will not be removed and so we must notify the participant of the deleted children.
217: for (int m = 0; m < members.length; m++) {
218: IResource member = members[m];
219: if (member instanceof IFile) {
220: IFile file = (IFile) member;
221: if ("class".equals(file.getFileExtension()) && file.isDerived()) //$NON-NLS-1$
222: continue;
223: if (pack.isDefaultPackage()
224: && !JavaCore.isJavaLikeFileName(file
225: .getName()))
226: continue;
227: resourcesCollector.add(member);
228: getResourceModifications().addDelete(member);
229: }
230: if (!pack.isDefaultPackage()
231: && member instanceof IFolder) {
232: // Normally, folder children of packages are packages
233: // as well, but in case they have been removed from the build
234: // path, notify the participant
235: IPackageFragment frag = (IPackageFragment) JavaCore
236: .create(member);
237: if (frag == null) {
238: resourcesCollector.add(member);
239: getResourceModifications().addDelete(member);
240: }
241: }
242: }
243: }
244: }
245:
246: /**
247: * Returns true if this initially selected package is really deletable
248: * (if it has non-selected sub packages, it may only be cleared).
249: */
250: private boolean canRemoveCompletely(IPackageFragment pack)
251: throws JavaModelException {
252: final IPackageFragment[] subPackages = JavaElementUtil
253: .getPackageAndSubpackages(pack);
254: for (int i = 0; i < subPackages.length; i++) {
255: if (!(subPackages[i].equals(pack))
256: && !(fPackagesToDelete.contains(subPackages[i])))
257: return false;
258: }
259: return true;
260: }
261: }
|