001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 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.Iterator;
014: import java.util.List;
015: import java.util.Map;
016:
017: import org.eclipse.text.edits.TextEdit;
018:
019: import org.eclipse.core.runtime.Assert;
020: import org.eclipse.core.runtime.CoreException;
021:
022: import org.eclipse.core.filebuffers.ITextFileBuffer;
023:
024: import org.eclipse.core.resources.IFile;
025: import org.eclipse.core.resources.IFolder;
026: import org.eclipse.core.resources.IProject;
027: import org.eclipse.core.resources.IResource;
028: import org.eclipse.core.resources.IWorkspaceRoot;
029:
030: import org.eclipse.ltk.core.refactoring.Change;
031: import org.eclipse.ltk.core.refactoring.CompositeChange;
032: import org.eclipse.ltk.core.refactoring.NullChange;
033: import org.eclipse.ltk.core.refactoring.TextChange;
034: import org.eclipse.ltk.core.refactoring.TextFileChange;
035:
036: import org.eclipse.jdt.core.IClassFile;
037: import org.eclipse.jdt.core.ICompilationUnit;
038: import org.eclipse.jdt.core.IJavaElement;
039: import org.eclipse.jdt.core.IPackageFragment;
040: import org.eclipse.jdt.core.IPackageFragmentRoot;
041: import org.eclipse.jdt.core.ISourceManipulation;
042: import org.eclipse.jdt.core.JavaModelException;
043: import org.eclipse.jdt.core.dom.CompilationUnit;
044: import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
045:
046: import org.eclipse.jdt.internal.corext.refactoring.Checks;
047: import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
048: import org.eclipse.jdt.internal.corext.refactoring.changes.ClasspathChange;
049: import org.eclipse.jdt.internal.corext.refactoring.changes.DeleteFileChange;
050: import org.eclipse.jdt.internal.corext.refactoring.changes.DeleteFolderChange;
051: import org.eclipse.jdt.internal.corext.refactoring.changes.DeletePackageFragmentRootChange;
052: import org.eclipse.jdt.internal.corext.refactoring.changes.DeleteSourceManipulationChange;
053: import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationStateChange;
054: import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility;
055: import org.eclipse.jdt.internal.corext.refactoring.changes.UndoablePackageDeleteChange;
056: import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
057: import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
058: import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringFileBuffers;
059: import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
060:
061: class DeleteChangeCreator {
062: private DeleteChangeCreator() {
063: //private
064: }
065:
066: /**
067: * @param manager the text change manager
068: * @param resources the resources to delete
069: * @param javaElements the Java elements to delete
070: * @param changeName the name of the change
071: * @param packageDeletes a list of {@link IResource}s that will be deleted
072: * by the delete operation of the {@link IPackageFragment}s in
073: * <code>javaElements</code>, or <code>null</code> iff
074: * <code>javaElements</code> does not contain package fragments
075: * @return the created change
076: * @throws CoreException
077: */
078: static Change createDeleteChange(TextChangeManager manager,
079: IResource[] resources, IJavaElement[] javaElements,
080: String changeName, List/*<IResource>*/packageDeletes)
081: throws CoreException {
082: /*
083: * Problem: deleting a package and subpackages can result in
084: * multiple package fragments in fJavaElements but only
085: * one folder in packageDeletes. The way to handle this is to make the undo
086: * change of individual package delete changes an empty change, and
087: * add take care of the undo in UndoablePackageDeleteChange.
088: */
089: DynamicValidationStateChange result;
090: if (packageDeletes.size() > 0) {
091: result = new UndoablePackageDeleteChange(changeName,
092: packageDeletes);
093: } else {
094: result = new DynamicValidationStateChange(changeName);
095: }
096:
097: for (int i = 0; i < javaElements.length; i++) {
098: IJavaElement element = javaElements[i];
099: if (!ReorgUtils.isInsideCompilationUnit(element))
100: result.add(createDeleteChange(element));
101: }
102:
103: for (int i = 0; i < resources.length; i++) {
104: result.add(createDeleteChange(resources[i]));
105: }
106:
107: Map grouped = ReorgUtils
108: .groupByCompilationUnit(getElementsSmallerThanCu(javaElements));
109: if (grouped.size() != 0) {
110: Assert.isNotNull(manager);
111: for (Iterator iter = grouped.keySet().iterator(); iter
112: .hasNext();) {
113: ICompilationUnit cu = (ICompilationUnit) iter.next();
114: result.add(createDeleteChange(cu, (List) grouped
115: .get(cu), manager));
116: }
117: }
118:
119: return result;
120: }
121:
122: private static Change createDeleteChange(IResource resource) {
123: Assert.isTrue(!(resource instanceof IWorkspaceRoot));//cannot be done
124: Assert.isTrue(!(resource instanceof IProject)); //project deletion is handled by the workbench
125: if (resource instanceof IFile)
126: return new DeleteFileChange((IFile) resource, true);
127: if (resource instanceof IFolder)
128: return new DeleteFolderChange((IFolder) resource, true);
129: Assert.isTrue(false);//there're no more kinds
130: return null;
131: }
132:
133: /*
134: * List<IJavaElement> javaElements
135: */
136: private static Change createDeleteChange(ICompilationUnit cu,
137: List javaElements, TextChangeManager manager)
138: throws CoreException {
139: CompilationUnit cuNode = RefactoringASTParser
140: .parseWithASTProvider(cu, false, null);
141: CompilationUnitRewrite rewriter = new CompilationUnitRewrite(
142: cu, cuNode);
143: IJavaElement[] elements = (IJavaElement[]) javaElements
144: .toArray(new IJavaElement[javaElements.size()]);
145: ASTNodeDeleteUtil.markAsDeleted(elements, rewriter, null);
146: return addTextEditFromRewrite(manager, cu, rewriter
147: .getASTRewrite());
148: }
149:
150: private static TextChange addTextEditFromRewrite(
151: TextChangeManager manager, ICompilationUnit cu,
152: ASTRewrite rewrite) throws CoreException {
153: try {
154: ITextFileBuffer buffer = RefactoringFileBuffers.acquire(cu);
155: TextEdit resultingEdits = rewrite.rewriteAST(buffer
156: .getDocument(), cu.getJavaProject()
157: .getOptions(true));
158: TextChange textChange = manager.get(cu);
159: if (textChange instanceof TextFileChange) {
160: TextFileChange tfc = (TextFileChange) textChange;
161: tfc.setSaveMode(TextFileChange.KEEP_SAVE_STATE);
162: }
163: String message = RefactoringCoreMessages.DeleteChangeCreator_1;
164: TextChangeCompatibility.addTextEdit(textChange, message,
165: resultingEdits);
166: return textChange;
167: } finally {
168: RefactoringFileBuffers.release(cu);
169: }
170: }
171:
172: //List<IJavaElement>
173: private static List getElementsSmallerThanCu(
174: IJavaElement[] javaElements) {
175: List result = new ArrayList();
176: for (int i = 0; i < javaElements.length; i++) {
177: IJavaElement element = javaElements[i];
178: if (ReorgUtils.isInsideCompilationUnit(element))
179: result.add(element);
180: }
181: return result;
182: }
183:
184: private static Change createDeleteChange(IJavaElement javaElement)
185: throws JavaModelException {
186: Assert.isTrue(!ReorgUtils.isInsideCompilationUnit(javaElement));
187:
188: switch (javaElement.getElementType()) {
189: case IJavaElement.PACKAGE_FRAGMENT_ROOT:
190: return createPackageFragmentRootDeleteChange((IPackageFragmentRoot) javaElement);
191:
192: case IJavaElement.PACKAGE_FRAGMENT:
193: return createSourceManipulationDeleteChange((IPackageFragment) javaElement);
194:
195: case IJavaElement.COMPILATION_UNIT:
196: return createSourceManipulationDeleteChange((ICompilationUnit) javaElement);
197:
198: case IJavaElement.CLASS_FILE:
199: //if this assert fails, it means that a precondition is missing
200: Assert
201: .isTrue(((IClassFile) javaElement).getResource() instanceof IFile);
202: return createDeleteChange(((IClassFile) javaElement)
203: .getResource());
204:
205: case IJavaElement.JAVA_MODEL: //cannot be done
206: Assert.isTrue(false);
207: return null;
208:
209: case IJavaElement.JAVA_PROJECT: //handled differently
210: Assert.isTrue(false);
211: return null;
212:
213: case IJavaElement.TYPE:
214: case IJavaElement.FIELD:
215: case IJavaElement.METHOD:
216: case IJavaElement.INITIALIZER:
217: case IJavaElement.PACKAGE_DECLARATION:
218: case IJavaElement.IMPORT_CONTAINER:
219: case IJavaElement.IMPORT_DECLARATION:
220: Assert.isTrue(false);//not done here
221: return new NullChange();
222: default:
223: Assert.isTrue(false);//there's no more kinds
224: return new NullChange();
225: }
226: }
227:
228: private static Change createSourceManipulationDeleteChange(
229: ISourceManipulation element) {
230: //XXX workaround for bug 31384, in case of linked ISourceManipulation delete the resource
231: if (element instanceof ICompilationUnit
232: || element instanceof IPackageFragment) {
233: IResource resource;
234: if (element instanceof ICompilationUnit)
235: resource = ReorgUtils
236: .getResource((ICompilationUnit) element);
237: else
238: resource = ((IPackageFragment) element).getResource();
239: if (resource != null && resource.isLinked())
240: return createDeleteChange(resource);
241: }
242: return new DeleteSourceManipulationChange(element, true);
243: }
244:
245: private static Change createPackageFragmentRootDeleteChange(
246: IPackageFragmentRoot root) throws JavaModelException {
247: IResource resource = root.getResource();
248: if (resource != null && resource.isLinked()) {
249: //XXX using this code is a workaround for jcore bug 31998
250: //jcore cannot handle linked stuff
251: //normally, we should always create DeletePackageFragmentRootChange
252: CompositeChange composite = new DynamicValidationStateChange(
253: RefactoringCoreMessages.DeleteRefactoring_delete_package_fragment_root);
254:
255: ClasspathChange change = ClasspathChange.removeEntryChange(
256: root.getJavaProject(), root.getRawClasspathEntry());
257: if (change != null) {
258: composite.add(change);
259: }
260: Assert.isTrue(!Checks.isClasspathDelete(root));//checked in preconditions
261: composite.add(createDeleteChange(resource));
262:
263: return composite;
264: } else {
265: Assert.isTrue(!root.isExternal());
266: // TODO remove the query argument
267: return new DeletePackageFragmentRootChange(root, true, null);
268: }
269: }
270: }
|