KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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.List JavaDoc;
14 import java.util.Map JavaDoc;
15
16 import org.eclipse.jdt.core.ICompilationUnit;
17 import org.eclipse.jdt.core.IJavaElement;
18 import org.eclipse.jdt.core.IJavaModelStatus;
19 import org.eclipse.jdt.core.IJavaModelStatusConstants;
20 import org.eclipse.jdt.core.IJavaProject;
21 import org.eclipse.jdt.core.IType;
22 import org.eclipse.jdt.core.JavaModelException;
23 import org.eclipse.jdt.core.dom.AST;
24 import org.eclipse.jdt.core.dom.ASTNode;
25 import org.eclipse.jdt.core.dom.ASTParser;
26 import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
27 import org.eclipse.jdt.core.dom.CompilationUnit;
28 import org.eclipse.jdt.core.dom.EnumDeclaration;
29 import org.eclipse.jdt.core.dom.SimpleName;
30 import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
31 import org.eclipse.jdt.core.dom.TypeDeclaration;
32 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
33 import org.eclipse.jdt.core.formatter.IndentManipulation;
34 import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
35 import org.eclipse.jface.text.IDocument;
36 import org.eclipse.jface.text.TextUtilities;
37
38 /**
39  * Implements functionality common to
40  * operations that create type members.
41  */

42 public abstract class CreateTypeMemberOperation extends CreateElementInCUOperation {
43     /**
44      * The source code for the new member.
45      */

46     protected String JavaDoc source = null;
47     /**
48      * The name of the <code>ASTNode</code> that may be used to
49      * create this new element.
50      * Used by the <code>CopyElementsOperation</code> for renaming
51      */

52     protected String JavaDoc alteredName;
53     /**
54      * The AST node representing the element that
55      * this operation created.
56      */

57      protected ASTNode createdNode;
58 /**
59  * When executed, this operation will create a type member
60  * in the given parent element with the specified source.
61  */

62 public CreateTypeMemberOperation(IJavaElement parentElement, String JavaDoc source, boolean force) {
63     super(parentElement);
64     this.source = source;
65     this.force = force;
66 }
67 protected StructuralPropertyDescriptor getChildPropertyDescriptor(ASTNode parent) {
68     switch (parent.getNodeType()) {
69         case ASTNode.COMPILATION_UNIT:
70             return CompilationUnit.TYPES_PROPERTY;
71         case ASTNode.ENUM_DECLARATION:
72             return EnumDeclaration.BODY_DECLARATIONS_PROPERTY;
73         case ASTNode.ANNOTATION_TYPE_DECLARATION:
74             return AnnotationTypeDeclaration.BODY_DECLARATIONS_PROPERTY;
75         default:
76             return TypeDeclaration.BODY_DECLARATIONS_PROPERTY;
77     }
78 }
79 protected ASTNode generateElementAST(ASTRewrite rewriter, IDocument document, ICompilationUnit cu) throws JavaModelException {
80     if (this.createdNode == null) {
81         this.source = removeIndentAndNewLines(this.source, document, cu);
82         ASTParser parser = ASTParser.newParser(AST.JLS3);
83         parser.setSource(this.source.toCharArray());
84         parser.setProject(getCompilationUnit().getJavaProject());
85         parser.setKind(ASTParser.K_CLASS_BODY_DECLARATIONS);
86         ASTNode node = parser.createAST(this.progressMonitor);
87         String JavaDoc createdNodeSource;
88         if (node.getNodeType() != ASTNode.TYPE_DECLARATION) {
89             createdNodeSource = generateSyntaxIncorrectAST();
90             if (this.createdNode == null)
91                 throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_CONTENTS));
92         } else {
93             TypeDeclaration typeDeclaration = (TypeDeclaration) node;
94             this.createdNode = (ASTNode) typeDeclaration.bodyDeclarations().iterator().next();
95             createdNodeSource = this.source;
96         }
97         if (this.alteredName != null) {
98             SimpleName newName = this.createdNode.getAST().newSimpleName(this.alteredName);
99             SimpleName oldName = rename(this.createdNode, newName);
100             int nameStart = oldName.getStartPosition();
101             int nameEnd = nameStart + oldName.getLength();
102             StringBuffer JavaDoc newSource = new StringBuffer JavaDoc();
103             if (this.source.equals(createdNodeSource)) {
104                 newSource.append(createdNodeSource.substring(0, nameStart));
105                 newSource.append(this.alteredName);
106                 newSource.append(createdNodeSource.substring(nameEnd));
107             } else {
108                 // syntactically incorrect source
109
int createdNodeStart = this.createdNode.getStartPosition();
110                 int createdNodeEnd = createdNodeStart + this.createdNode.getLength();
111                 newSource.append(createdNodeSource.substring(createdNodeStart, nameStart));
112                 newSource.append(this.alteredName);
113                 newSource.append(createdNodeSource.substring(nameEnd, createdNodeEnd));
114                 
115             }
116             this.source = newSource.toString();
117         }
118     }
119     if (rewriter == null) return this.createdNode;
120     // return a string place holder (instead of the created node) so has to not lose comments and formatting
121
return rewriter.createStringPlaceholder(this.source, this.createdNode.getNodeType());
122 }
123 private String JavaDoc removeIndentAndNewLines(String JavaDoc code, IDocument document, ICompilationUnit cu) {
124     IJavaProject project = cu.getJavaProject();
125     Map JavaDoc options = project.getOptions(true/*inherit JavaCore options*/);
126     int tabWidth = IndentManipulation.getTabWidth(options);
127     int indentWidth = IndentManipulation.getIndentWidth(options);
128     int indent = IndentManipulation.measureIndentUnits(code, tabWidth, indentWidth);
129     int firstNonWhiteSpace = -1;
130     int length = code.length();
131     while (firstNonWhiteSpace < length-1)
132         if (!ScannerHelper.isWhitespace(code.charAt(++firstNonWhiteSpace)))
133             break;
134     int lastNonWhiteSpace = length;
135     while (lastNonWhiteSpace > 0)
136         if (!ScannerHelper.isWhitespace(code.charAt(--lastNonWhiteSpace)))
137             break;
138     String JavaDoc lineDelimiter = TextUtilities.getDefaultLineDelimiter(document);
139     return IndentManipulation.changeIndent(code.substring(firstNonWhiteSpace, lastNonWhiteSpace+1), indent, tabWidth, indentWidth, "", lineDelimiter); //$NON-NLS-1$
140
}
141 /*
142  * Renames the given node to the given name.
143  * Returns the old name.
144  */

145 protected abstract SimpleName rename(ASTNode node, SimpleName newName);
146 /**
147  * Generates an <code>ASTNode</code> based on the source of this operation
148  * when there is likely a syntax error in the source.
149  * Returns the source used to generate this node.
150  */

151 protected String JavaDoc generateSyntaxIncorrectAST() {
152     //create some dummy source to generate an ast node
153
StringBuffer JavaDoc buff = new StringBuffer JavaDoc();
154     IType type = getType();
155     String JavaDoc lineSeparator = org.eclipse.jdt.internal.core.util.Util.getLineSeparator(this.source, type == null ? null : type.getJavaProject());
156     buff.append(lineSeparator + " public class A {" + lineSeparator); //$NON-NLS-1$
157
buff.append(this.source);
158     buff.append(lineSeparator).append('}');
159     ASTParser parser = ASTParser.newParser(AST.JLS3);
160     parser.setSource(buff.toString().toCharArray());
161     CompilationUnit compilationUnit = (CompilationUnit) parser.createAST(null);
162     TypeDeclaration typeDeclaration = (TypeDeclaration) compilationUnit.types().iterator().next();
163     List JavaDoc bodyDeclarations = typeDeclaration.bodyDeclarations();
164     if (bodyDeclarations.size() != 0)
165         this.createdNode = (ASTNode) bodyDeclarations.iterator().next();
166     return buff.toString();
167 }
168 /**
169  * Returns the IType the member is to be created in.
170  */

171 protected IType getType() {
172     return (IType)getParentElement();
173 }
174 /**
175  * Sets the name of the <code>ASTNode</code> that will be used to
176  * create this new element.
177  * Used by the <code>CopyElementsOperation</code> for renaming
178  */

179 protected void setAlteredName(String JavaDoc newName) {
180     this.alteredName = newName;
181 }
182 /**
183  * Possible failures: <ul>
184  * <li>NO_ELEMENTS_TO_PROCESS - the parent element supplied to the operation is
185  * <code>null</code>.
186  * <li>INVALID_CONTENTS - The source is <code>null</code> or has serious syntax errors.
187   * <li>NAME_COLLISION - A name collision occurred in the destination
188  * </ul>
189  */

190 public IJavaModelStatus verify() {
191     IJavaModelStatus status = super.verify();
192     if (!status.isOK()) {
193         return status;
194     }
195     if (this.source == null) {
196         return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CONTENTS);
197     }
198     if (!force) {
199         //check for name collisions
200
try {
201             ICompilationUnit cu = getCompilationUnit();
202             generateElementAST(null, getDocument(cu), cu);
203         } catch (JavaModelException jme) {
204             return jme.getJavaModelStatus();
205         }
206         return verifyNameCollision();
207     }
208     
209     return JavaModelStatus.VERIFIED_OK;
210 }
211 /**
212  * Verify for a name collision in the destination container.
213  */

214 protected IJavaModelStatus verifyNameCollision() {
215     return JavaModelStatus.VERIFIED_OK;
216 }
217 }
218
Popular Tags