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.core;
011:
012: import java.util.Iterator;
013:
014: import org.eclipse.core.runtime.IStatus;
015: import org.eclipse.jdt.core.Flags;
016: import org.eclipse.jdt.core.ICompilationUnit;
017: import org.eclipse.jdt.core.IImportDeclaration;
018: import org.eclipse.jdt.core.IJavaElement;
019: import org.eclipse.jdt.core.IJavaModelStatus;
020: import org.eclipse.jdt.core.IJavaModelStatusConstants;
021: import org.eclipse.jdt.core.IJavaProject;
022: import org.eclipse.jdt.core.IType;
023: import org.eclipse.jdt.core.JavaConventions;
024: import org.eclipse.jdt.core.JavaCore;
025: import org.eclipse.jdt.core.JavaModelException;
026: import org.eclipse.jdt.core.compiler.CharOperation;
027: import org.eclipse.jdt.core.dom.AST;
028: import org.eclipse.jdt.core.dom.ASTNode;
029: import org.eclipse.jdt.core.dom.CompilationUnit;
030: import org.eclipse.jdt.core.dom.ImportDeclaration;
031: import org.eclipse.jdt.core.dom.Name;
032: import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
033: import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
034: import org.eclipse.jdt.internal.core.util.Messages;
035: import org.eclipse.jface.text.IDocument;
036:
037: /**
038: * <p>This operation adds an import declaration to an existing compilation unit.
039: * If the compilation unit already includes the specified import declaration,
040: * the import is not generated (it does not generate duplicates).
041: * Note that it is valid to specify both a single-type import and an on-demand import
042: * for the same package, for example <code>"java.io.File"</code> and
043: * <code>"java.io.*"</code>, in which case both are preserved since the semantics
044: * of this are not the same as just importing <code>"java.io.*"</code>.
045: * Importing <code>"java.lang.*"</code>, or the package in which the compilation unit
046: * is defined, are not treated as special cases. If they are specified, they are
047: * included in the result.
048: *
049: * <p>Required Attributes:<ul>
050: * <li>Compilation unit
051: * <li>Import name - the name of the import to add to the
052: * compilation unit. For example: <code>"java.io.File"</code> or <code>"java.awt.*"</code>
053: * </ul>
054: */
055: public class CreateImportOperation extends CreateElementInCUOperation {
056:
057: /*
058: * The name of the import to be created.
059: */
060: protected String importName;
061:
062: /*
063: * The flags of the import to be created (either Flags#AccDefault or Flags#AccStatic)
064: */
065: protected int flags;
066:
067: /**
068: * When executed, this operation will add an import to the given compilation unit.
069: */
070: public CreateImportOperation(String importName,
071: ICompilationUnit parentElement, int flags) {
072: super (parentElement);
073: this .importName = importName;
074: this .flags = flags;
075: }
076:
077: protected StructuralPropertyDescriptor getChildPropertyDescriptor(
078: ASTNode parent) {
079: return CompilationUnit.IMPORTS_PROPERTY;
080: }
081:
082: protected ASTNode generateElementAST(ASTRewrite rewriter,
083: IDocument document, ICompilationUnit cu)
084: throws JavaModelException {
085: // ensure no duplicate
086: Iterator imports = this .cuAST.imports().iterator();
087: boolean onDemand = this .importName.endsWith(".*"); //$NON-NLS-1$
088: String importActualName = this .importName;
089: if (onDemand) {
090: importActualName = this .importName.substring(0,
091: this .importName.length() - 2);
092: }
093: while (imports.hasNext()) {
094: ImportDeclaration importDeclaration = (ImportDeclaration) imports
095: .next();
096: if (importActualName.equals(importDeclaration.getName()
097: .getFullyQualifiedName())
098: && (onDemand == importDeclaration.isOnDemand())
099: && (Flags.isStatic(this .flags) == importDeclaration
100: .isStatic())) {
101: this .creationOccurred = false;
102: return null;
103: }
104: }
105:
106: AST ast = this .cuAST.getAST();
107: ImportDeclaration importDeclaration = ast
108: .newImportDeclaration();
109: importDeclaration.setStatic(Flags.isStatic(this .flags));
110: // split import name into individual fragments, checking for on demand imports
111: char[][] charFragments = CharOperation.splitOn('.',
112: importActualName.toCharArray(), 0, importActualName
113: .length());
114: int length = charFragments.length;
115: String[] strFragments = new String[length];
116: for (int i = 0; i < length; i++) {
117: strFragments[i] = String.valueOf(charFragments[i]);
118: }
119: Name name = ast.newName(strFragments);
120: importDeclaration.setName(name);
121: if (onDemand)
122: importDeclaration.setOnDemand(true);
123: return importDeclaration;
124: }
125:
126: /**
127: * @see CreateElementInCUOperation#generateResultHandle
128: */
129: protected IJavaElement generateResultHandle() {
130: return getCompilationUnit().getImport(this .importName);
131: }
132:
133: /**
134: * @see CreateElementInCUOperation#getMainTaskName()
135: */
136: public String getMainTaskName() {
137: return Messages.operation_createImportsProgress;
138: }
139:
140: /**
141: * Sets the correct position for the new import:<ul>
142: * <li> after the last import
143: * <li> if no imports, before the first type
144: * <li> if no type, after the package statement
145: * <li> and if no package statement - first thing in the CU
146: */
147: protected void initializeDefaultPosition() {
148: try {
149: ICompilationUnit cu = getCompilationUnit();
150: IImportDeclaration[] imports = cu.getImports();
151: if (imports.length > 0) {
152: createAfter(imports[imports.length - 1]);
153: return;
154: }
155: IType[] types = cu.getTypes();
156: if (types.length > 0) {
157: createBefore(types[0]);
158: return;
159: }
160: IJavaElement[] children = cu.getChildren();
161: //look for the package declaration
162: for (int i = 0; i < children.length; i++) {
163: if (children[i].getElementType() == IJavaElement.PACKAGE_DECLARATION) {
164: createAfter(children[i]);
165: return;
166: }
167: }
168: } catch (JavaModelException e) {
169: // cu doesn't exit: ignore
170: }
171: }
172:
173: /**
174: * Possible failures: <ul>
175: * <li>NO_ELEMENTS_TO_PROCESS - the compilation unit supplied to the operation is
176: * <code>null</code>.
177: * <li>INVALID_NAME - not a valid import declaration name.
178: * </ul>
179: * @see IJavaModelStatus
180: * @see JavaConventions
181: */
182: public IJavaModelStatus verify() {
183: IJavaModelStatus status = super .verify();
184: if (!status.isOK()) {
185: return status;
186: }
187: IJavaProject project = getParentElement().getJavaProject();
188: if (JavaConventions.validateImportDeclaration(this .importName,
189: project.getOption(JavaCore.COMPILER_SOURCE, true),
190: project.getOption(JavaCore.COMPILER_COMPLIANCE, true))
191: .getSeverity() == IStatus.ERROR) {
192: return new JavaModelStatus(
193: IJavaModelStatusConstants.INVALID_NAME,
194: this.importName);
195: }
196: return JavaModelStatus.VERIFIED_OK;
197: }
198: }
|