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.codemanipulation;
011:
012: import java.util.ArrayList;
013: import java.util.List;
014:
015: import org.eclipse.text.edits.MultiTextEdit;
016: import org.eclipse.text.edits.TextEdit;
017:
018: import org.eclipse.core.runtime.CoreException;
019: import org.eclipse.core.runtime.IProgressMonitor;
020: import org.eclipse.core.runtime.NullProgressMonitor;
021: import org.eclipse.core.runtime.SubProgressMonitor;
022: import org.eclipse.core.runtime.jobs.ISchedulingRule;
023:
024: import org.eclipse.core.resources.IWorkspaceRunnable;
025: import org.eclipse.core.resources.ResourcesPlugin;
026:
027: import org.eclipse.jdt.core.ICompilationUnit;
028: import org.eclipse.jdt.core.dom.AST;
029: import org.eclipse.jdt.core.dom.ASTNode;
030: import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
031: import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
032: import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
033: import org.eclipse.jdt.core.dom.CompilationUnit;
034: import org.eclipse.jdt.core.dom.IMethodBinding;
035: import org.eclipse.jdt.core.dom.ITypeBinding;
036: import org.eclipse.jdt.core.dom.MethodDeclaration;
037: import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
038: import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
039: import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
040: import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
041:
042: import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
043:
044: import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
045:
046: /**
047: * Workspace runnable to add unimplemented methods.
048: *
049: * @since 3.1
050: */
051: public final class AddUnimplementedMethodsOperation implements
052: IWorkspaceRunnable {
053:
054: /** Should the resulting edit be applied? */
055: private final boolean fApply;
056:
057: /** The qualified names of the generated imports */
058: private String[] fCreatedImports;
059:
060: /** The method binding keys for which a method was generated */
061: private final List fCreatedMethods = new ArrayList();
062:
063: /** Should the import edits be applied? */
064: private final boolean fImports;
065:
066: /** The insertion point, or <code>-1</code> */
067: private final int fInsertPos;
068:
069: /** The method bindings to implement */
070: private final IMethodBinding[] fMethodsToImplement;
071:
072: /** Should the compilation unit content be saved? */
073: private final boolean fSave;
074:
075: /** Specified if comments should be created */
076: private boolean fDoCreateComments;
077:
078: /** The type declaration to add the methods to */
079: private final ITypeBinding fType;
080:
081: /** The compilation unit AST node */
082: private final CompilationUnit fASTRoot;
083:
084: /**
085: * Creates a new add unimplemented methods operation.
086: *
087: * @param astRoot the compilation unit AST node
088: * @param type the type to add the methods to
089: * @param methodsToImplement the method bindings to implement or <code>null</code> to implement all unimplemented methods
090: * @param insertPos the insertion point, or <code>-1</code>
091: * @param imports <code>true</code> if the import edits should be applied, <code>false</code> otherwise
092: * @param apply <code>true</code> if the resulting edit should be applied, <code>false</code> otherwise
093: * @param save <code>true</code> if the changed compilation unit should be saved, <code>false</code> otherwise
094: */
095: public AddUnimplementedMethodsOperation(CompilationUnit astRoot,
096: ITypeBinding type, IMethodBinding[] methodsToImplement,
097: int insertPos, final boolean imports, final boolean apply,
098: final boolean save) {
099: if (astRoot == null
100: || !(astRoot.getJavaElement() instanceof ICompilationUnit)) {
101: throw new IllegalArgumentException(
102: "AST must not be null and has to be created from a ICompilationUnit"); //$NON-NLS-1$
103: }
104: if (type == null) {
105: throw new IllegalArgumentException(
106: "The type must not be null"); //$NON-NLS-1$
107: }
108: ASTNode node = astRoot.findDeclaringNode(type);
109: if (!(node instanceof AnonymousClassDeclaration || node instanceof AbstractTypeDeclaration)) {
110: throw new IllegalArgumentException(
111: "type has to map to a type declaration in the AST"); //$NON-NLS-1$
112: }
113:
114: fType = type;
115: fInsertPos = insertPos;
116: fASTRoot = astRoot;
117: fMethodsToImplement = methodsToImplement;
118: fSave = save;
119: fApply = apply;
120: fImports = imports;
121:
122: fDoCreateComments = StubUtility.doAddComments(astRoot
123: .getJavaElement().getJavaProject());
124: }
125:
126: public void setCreateComments(boolean createComments) {
127: fDoCreateComments = createComments;
128: }
129:
130: /**
131: * Returns the qualified names of the generated imports.
132: *
133: * @return the generated imports
134: */
135: public final String[] getCreatedImports() {
136: if (fCreatedImports != null) {
137: return fCreatedImports;
138: }
139: return new String[0];
140: }
141:
142: /**
143: * Returns the method binding keys for which a method has been generated.
144: *
145: * @return the method binding keys
146: */
147: public final String[] getCreatedMethods() {
148: final String[] keys = new String[fCreatedMethods.size()];
149: fCreatedMethods.toArray(keys);
150: return keys;
151: }
152:
153: /**
154: * Returns the scheduling rule for this operation.
155: *
156: * @return the scheduling rule
157: */
158: public final ISchedulingRule getSchedulingRule() {
159: return ResourcesPlugin.getWorkspace().getRoot();
160: }
161:
162: /*
163: * @see org.eclipse.core.resources.IWorkspaceRunnable#run(org.eclipse.core.runtime.IProgressMonitor)
164: */
165: public final void run(IProgressMonitor monitor)
166: throws CoreException {
167: if (monitor == null)
168: monitor = new NullProgressMonitor();
169: try {
170: monitor.beginTask("", 2); //$NON-NLS-1$
171: monitor
172: .setTaskName(CodeGenerationMessages.AddUnimplementedMethodsOperation_description);
173: fCreatedMethods.clear();
174: ICompilationUnit cu = (ICompilationUnit) fASTRoot
175: .getJavaElement();
176:
177: AST ast = fASTRoot.getAST();
178:
179: ASTRewrite astRewrite = ASTRewrite.create(ast);
180: ImportRewrite importRewrite = StubUtility
181: .createImportRewrite(fASTRoot, true);
182:
183: ITypeBinding currTypeBinding = fType;
184: ListRewrite memberRewriter = null;
185:
186: ASTNode node = fASTRoot.findDeclaringNode(currTypeBinding);
187: if (node instanceof AnonymousClassDeclaration) {
188: memberRewriter = astRewrite
189: .getListRewrite(
190: node,
191: AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY);
192: } else if (node instanceof AbstractTypeDeclaration) {
193: ChildListPropertyDescriptor property = ((AbstractTypeDeclaration) node)
194: .getBodyDeclarationsProperty();
195: memberRewriter = astRewrite.getListRewrite(node,
196: property);
197: } else {
198: throw new IllegalArgumentException();
199: // not possible, we checked this in the constructor
200: }
201:
202: final CodeGenerationSettings settings = JavaPreferencesSettings
203: .getCodeGenerationSettings(cu.getJavaProject());
204: settings.createComments = fDoCreateComments;
205:
206: ASTNode insertion = getNodeToInsertBefore(memberRewriter);
207:
208: IMethodBinding[] methodsToImplement = fMethodsToImplement;
209: if (methodsToImplement == null) {
210: methodsToImplement = StubUtility2
211: .getUnimplementedMethods(currTypeBinding);
212: }
213:
214: ImportRewriteContext context = null;
215: int insertionPosition = fInsertPos;
216: if (insertionPosition == -1 && fASTRoot.types().size() > 0) {
217: AbstractTypeDeclaration firstTypeDecl = (AbstractTypeDeclaration) fASTRoot
218: .types().get(0);
219: insertionPosition = firstTypeDecl.getStartPosition();
220: if (insertionPosition != -1) {
221: context = new ContextSensitiveImportRewriteContext(
222: fASTRoot, insertionPosition, importRewrite);
223: }
224: }
225:
226: for (int i = 0; i < methodsToImplement.length; i++) {
227: IMethodBinding curr = methodsToImplement[i];
228: MethodDeclaration stub = StubUtility2
229: .createImplementationStub(cu, astRewrite,
230: importRewrite, context, curr,
231: currTypeBinding.getName(), settings,
232: currTypeBinding.isInterface());
233: if (stub != null) {
234: fCreatedMethods.add(curr.getKey());
235: if (insertion != null)
236: memberRewriter.insertBefore(stub, insertion,
237: null);
238: else
239: memberRewriter.insertLast(stub, null);
240: }
241: }
242: MultiTextEdit edit = new MultiTextEdit();
243:
244: TextEdit importEdits = importRewrite
245: .rewriteImports(new SubProgressMonitor(monitor, 1));
246: fCreatedImports = importRewrite.getCreatedImports();
247: if (fImports) {
248: edit.addChild(importEdits);
249: }
250: edit.addChild(astRewrite.rewriteAST());
251:
252: if (fApply) {
253: JavaModelUtil.applyEdit(cu, edit, fSave,
254: new SubProgressMonitor(monitor, 1));
255: }
256: } finally {
257: monitor.done();
258: }
259: }
260:
261: private ASTNode getNodeToInsertBefore(ListRewrite rewriter) {
262: if (fInsertPos != -1) {
263: List members = rewriter.getOriginalList();
264: for (int i = 0; i < members.size(); i++) {
265: ASTNode curr = (ASTNode) members.get(i);
266: if (curr.getStartPosition() >= fInsertPos) {
267: return curr;
268: }
269: }
270: }
271: return null;
272: }
273:
274: }
|