0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.modules.spring.beans.completion;
0043:
0044: import java.awt.Color;
0045: import java.awt.Font;
0046: import java.awt.Graphics;
0047: import java.awt.Image;
0048: import java.awt.event.KeyEvent;
0049: import java.beans.BeanInfo;
0050: import java.io.File;
0051: import java.io.IOException;
0052: import java.util.ArrayList;
0053: import java.util.Iterator;
0054: import java.util.List;
0055: import java.util.Set;
0056: import javax.lang.model.element.Element;
0057: import javax.lang.model.element.ElementKind;
0058: import javax.lang.model.element.ExecutableElement;
0059: import javax.lang.model.element.Modifier;
0060: import javax.lang.model.element.PackageElement;
0061: import javax.lang.model.element.TypeElement;
0062: import javax.lang.model.element.VariableElement;
0063: import javax.lang.model.type.ArrayType;
0064: import javax.lang.model.type.DeclaredType;
0065: import javax.lang.model.type.ErrorType;
0066: import javax.lang.model.type.ExecutableType;
0067: import javax.lang.model.type.TypeKind;
0068: import javax.lang.model.type.TypeMirror;
0069: import javax.lang.model.type.TypeVariable;
0070: import javax.lang.model.type.WildcardType;
0071: import javax.lang.model.util.SimpleElementVisitor6;
0072: import javax.lang.model.util.SimpleTypeVisitor6;
0073: import javax.swing.Action;
0074: import javax.swing.Icon;
0075: import javax.swing.ImageIcon;
0076: import javax.swing.UIManager;
0077: import javax.swing.text.BadLocationException;
0078: import javax.swing.text.Document;
0079: import javax.swing.text.JTextComponent;
0080: import javax.swing.text.Position;
0081: import org.netbeans.api.editor.EditorRegistry;
0082: import org.netbeans.api.editor.completion.Completion;
0083: import org.netbeans.api.java.source.CompilationController;
0084: import org.netbeans.api.java.source.ElementHandle;
0085: import org.netbeans.api.java.source.JavaSource;
0086: import org.netbeans.api.java.source.JavaSource.Phase;
0087: import org.netbeans.api.java.source.SourceUtils;
0088: import org.netbeans.api.java.source.Task;
0089: import org.netbeans.editor.BaseDocument;
0090: import org.netbeans.modules.spring.api.beans.model.SpringBean;
0091: import org.netbeans.modules.spring.beans.editor.SpringXMLConfigEditorUtils;
0092: import org.netbeans.modules.spring.util.SpringBeansUIs;
0093: import org.netbeans.spi.editor.completion.CompletionDocumentation;
0094: import org.netbeans.spi.editor.completion.CompletionItem;
0095: import org.netbeans.spi.editor.completion.CompletionResultSet;
0096: import org.netbeans.spi.editor.completion.CompletionTask;
0097: import org.netbeans.spi.editor.completion.support.AsyncCompletionQuery;
0098: import org.netbeans.spi.editor.completion.support.AsyncCompletionTask;
0099: import org.netbeans.spi.editor.completion.support.CompletionUtilities;
0100: import org.openide.filesystems.FileObject;
0101: import org.openide.filesystems.FileUtil;
0102: import org.openide.filesystems.Repository;
0103: import org.openide.loaders.DataFolder;
0104: import org.openide.nodes.Node;
0105: import org.openide.util.Exceptions;
0106: import org.openide.util.Utilities;
0107: import org.openide.xml.XMLUtil;
0108:
0109: /**
0110: * A completion item shown in a valid code completion request
0111: * in a Spring XML Configuration file
0112: *
0113: * @author Rohan Ranade (Rohan.Ranade@Sun.COM)
0114: */
0115: public abstract class SpringXMLConfigCompletionItem implements
0116: CompletionItem {
0117:
0118: public static SpringXMLConfigCompletionItem createBeanRefItem(
0119: int substitutionOffset, String displayName,
0120: SpringBean bean, FileObject containerFO) {
0121: return new BeanRefItem(substitutionOffset, displayName, bean,
0122: containerFO);
0123: }
0124:
0125: public static SpringXMLConfigCompletionItem createPackageItem(
0126: int substitutionOffset, String packageName,
0127: boolean deprecated) {
0128: return new PackageItem(substitutionOffset, packageName,
0129: deprecated);
0130: }
0131:
0132: public static SpringXMLConfigCompletionItem createTypeItem(
0133: int substitutionOffset, TypeElement elem,
0134: ElementHandle<TypeElement> elemHandle, boolean deprecated,
0135: boolean smartItem) {
0136: return new ClassItem(substitutionOffset, elem, elemHandle,
0137: deprecated, smartItem);
0138: }
0139:
0140: public static SpringXMLConfigCompletionItem createMethodItem(
0141: int substitutionOffset, ExecutableElement element,
0142: boolean isInherited, boolean isDeprecated) {
0143: return new MethodItem(substitutionOffset, element, isInherited,
0144: isDeprecated);
0145: }
0146:
0147: public static SpringXMLConfigCompletionItem createPropertyItem(
0148: int substitutionOffset, ExecutableElement setter) {
0149: return new PropertyItem(substitutionOffset, setter);
0150: }
0151:
0152: public static SpringXMLConfigCompletionItem createAttribValueItem(
0153: int substitutionOffset, String displayText, String docText) {
0154: return new AttribValueItem(substitutionOffset, displayText,
0155: docText);
0156: }
0157:
0158: public static SpringXMLConfigCompletionItem createFolderItem(
0159: int substitutionOffset, FileObject folder) {
0160: return new FolderItem(substitutionOffset, folder);
0161: }
0162:
0163: public static SpringXMLConfigCompletionItem createSpringXMLFileItem(
0164: int substitutionOffset, FileObject file) {
0165: return new FileItem(substitutionOffset, file);
0166: }
0167:
0168: public static SpringXMLConfigCompletionItem createPropertyAttribItem(
0169: int substitutionOffset, String text, ExecutableElement ee) {
0170: return new PropertyAttribItem(substitutionOffset, text, ee);
0171: }
0172:
0173: protected int substitutionOffset;
0174:
0175: protected SpringXMLConfigCompletionItem(int substitutionOffset) {
0176: this .substitutionOffset = substitutionOffset;
0177: }
0178:
0179: public void defaultAction(JTextComponent component) {
0180: if (component != null) {
0181: Completion.get().hideDocumentation();
0182: Completion.get().hideCompletion();
0183: int caretOffset = component.getSelectionEnd();
0184: substituteText(component, substitutionOffset, caretOffset
0185: - substitutionOffset, null);
0186: }
0187: }
0188:
0189: protected void substituteText(JTextComponent c, int offset,
0190: int len, String toAdd) {
0191: BaseDocument doc = (BaseDocument) c.getDocument();
0192: CharSequence prefix = getSubstitutionText();
0193: String text = prefix.toString();
0194: if (toAdd != null) {
0195: text += toAdd;
0196: }
0197:
0198: doc.atomicLock();
0199: try {
0200: Position position = doc.createPosition(offset);
0201: doc.remove(offset, len);
0202: doc.insertString(position.getOffset(), text.toString(),
0203: null);
0204: } catch (BadLocationException ble) {
0205: // nothing can be done to update
0206: } finally {
0207: doc.atomicUnlock();
0208: }
0209: }
0210:
0211: protected CharSequence getSubstitutionText() {
0212: return getInsertPrefix();
0213: }
0214:
0215: public void processKeyEvent(KeyEvent evt) {
0216:
0217: }
0218:
0219: public int getPreferredWidth(Graphics g, Font defaultFont) {
0220: return CompletionUtilities.getPreferredWidth(getLeftHtmlText(),
0221: getRightHtmlText(), g, defaultFont);
0222: }
0223:
0224: public void render(Graphics g, Font defaultFont,
0225: Color defaultColor, Color backgroundColor, int width,
0226: int height, boolean selected) {
0227: CompletionUtilities.renderHtml(getIcon(), getLeftHtmlText(),
0228: getRightHtmlText(), g, defaultFont, defaultColor,
0229: width, height, selected);
0230: }
0231:
0232: public CompletionTask createDocumentationTask() {
0233: return null;
0234: }
0235:
0236: public CompletionTask createToolTipTask() {
0237: return null;
0238: }
0239:
0240: public boolean instantSubstitution(JTextComponent component) {
0241: defaultAction(component);
0242: return true;
0243: }
0244:
0245: protected String getLeftHtmlText() {
0246: return null;
0247: }
0248:
0249: protected String getRightHtmlText() {
0250: return null;
0251: }
0252:
0253: protected ImageIcon getIcon() {
0254: return null;
0255: }
0256:
0257: private static class BeanRefItem extends
0258: SpringXMLConfigCompletionItem {
0259:
0260: private static final String CLASS_COLOR = "<font color=#808080>"; //NOI18N
0261:
0262: private String beanId;
0263: private String beanClass;
0264: private List<String> beanNames;
0265: private String displayName;
0266: private String beanLocFile;
0267: private Action goToBeanAction;
0268: private String leftText;
0269:
0270: public BeanRefItem(int substitutionOffset, String displayName,
0271: SpringBean bean, FileObject containerFO) {
0272: super (substitutionOffset);
0273: this .beanId = bean.getId();
0274: this .beanClass = bean.getClassName();
0275: this .beanNames = bean.getNames();
0276: if (bean.getLocation() != null) {
0277: File file = bean.getLocation().getFile();
0278: FileObject fo = FileUtil.toFileObject(file);
0279: if (fo != null) {
0280: this .beanLocFile = FileUtil.getRelativePath(
0281: containerFO.getParent(), fo);
0282: }
0283: }
0284: goToBeanAction = SpringBeansUIs.createGoToBeanAction(bean);
0285: this .displayName = displayName;
0286: }
0287:
0288: public int getSortPriority() {
0289: return 100;
0290: }
0291:
0292: public CharSequence getSortText() {
0293: return displayName;
0294: }
0295:
0296: public CharSequence getInsertPrefix() {
0297: return displayName;
0298: }
0299:
0300: @Override
0301: protected String getLeftHtmlText() {
0302: if (leftText == null) {
0303: StringBuilder sb = new StringBuilder();
0304: sb.append(displayName);
0305: sb.append(CLASS_COLOR);
0306: sb.append(" ("); // NOI18N
0307: if (this .beanClass != null) {
0308: sb.append(beanClass);
0309: }
0310: sb.append(")"); // NOI18N
0311: sb.append(COLOR_END);
0312: leftText = sb.toString();
0313: }
0314: return leftText;
0315: }
0316:
0317: @Override
0318: protected String getRightHtmlText() {
0319: return beanLocFile;
0320: }
0321:
0322: @Override
0323: protected ImageIcon getIcon() {
0324: return new ImageIcon(
0325: Utilities
0326: .loadImage("org/netbeans/modules/spring/beans/resources/spring.png")); // NOI18N
0327: }
0328:
0329: @Override
0330: public CompletionTask createDocumentationTask() {
0331: return new AsyncCompletionTask(new AsyncCompletionQuery() {
0332: @Override
0333: protected void query(CompletionResultSet resultSet,
0334: Document doc, int caretOffset) {
0335: CompletionDocumentation docItem = SpringXMLConfigCompletionDoc
0336: .createBeanRefDoc(beanId, beanNames,
0337: beanClass, beanLocFile,
0338: goToBeanAction);
0339: resultSet.setDocumentation(docItem);
0340: resultSet.finish();
0341: }
0342: });
0343: }
0344: }
0345:
0346: public static final String COLOR_END = "</font>"; //NOI18N
0347: public static final String STRIKE = "<s>"; //NOI18N
0348: public static final String STRIKE_END = "</s>"; //NOI18N
0349: public static final String BOLD = "<b>"; //NOI18N
0350: public static final String BOLD_END = "</b>"; //NOI18N
0351:
0352: /**
0353: * Represents a class in the completion popup.
0354: *
0355: * Heavily derived from Java Editor module's JavaCompletionItem class
0356: *
0357: */
0358: private static class ClassItem extends
0359: SpringXMLConfigCompletionItem {
0360: private static final String CLASS = "org/netbeans/modules/editor/resources/completion/class_16.png"; //NOI18N
0361: private static final String CLASS_COLOR = "<font color=#560000>"; //NOI18N
0362: private static final String PKG_COLOR = "<font color=#808080>"; //NOI18N
0363:
0364: private ElementHandle<TypeElement> elemHandle;
0365: private boolean deprecated;
0366: private String displayName;
0367: private String enclName;
0368: private String sortText;
0369: private String leftText;
0370: private boolean smartItem;
0371:
0372: public ClassItem(int substitutionOffset, TypeElement elem,
0373: ElementHandle<TypeElement> elemHandle,
0374: boolean deprecated, boolean smartItem) {
0375: super (substitutionOffset);
0376: this .elemHandle = elemHandle;
0377: this .deprecated = deprecated;
0378: this .displayName = smartItem ? elem.getSimpleName()
0379: .toString() : getRelativeName(elem);
0380: this .enclName = getElementName(elem.getEnclosingElement(),
0381: true).toString();
0382: this .sortText = this .displayName
0383: + getImportanceLevel(this .enclName) + "#"
0384: + this .enclName; //NOI18N
0385: this .smartItem = smartItem;
0386: }
0387:
0388: private String getRelativeName(TypeElement elem) {
0389: StringBuilder sb = new StringBuilder();
0390: sb.append(elem.getSimpleName().toString());
0391: Element parent = elem.getEnclosingElement();
0392: while (parent.getKind() != ElementKind.PACKAGE) {
0393: sb.insert(0, parent.getSimpleName().toString() + "$"); // NOI18N
0394: parent = parent.getEnclosingElement();
0395: }
0396:
0397: return sb.toString();
0398: }
0399:
0400: public int getSortPriority() {
0401: return 200;
0402: }
0403:
0404: public CharSequence getSortText() {
0405: return sortText;
0406: }
0407:
0408: public CharSequence getInsertPrefix() {
0409: return smartItem ? "" : elemHandle.getBinaryName(); // NOI18N
0410: }
0411:
0412: @Override
0413: protected CharSequence getSubstitutionText() {
0414: return elemHandle.getBinaryName();
0415: }
0416:
0417: @Override
0418: public boolean instantSubstitution(JTextComponent component) {
0419: return false;
0420: }
0421:
0422: @Override
0423: protected String getLeftHtmlText() {
0424: if (leftText == null) {
0425: StringBuilder sb = new StringBuilder();
0426: sb.append(getColor());
0427: if (deprecated)
0428: sb.append(STRIKE);
0429: sb.append(displayName);
0430: if (deprecated)
0431: sb.append(STRIKE_END);
0432: if (smartItem && enclName != null
0433: && enclName.length() > 0) {
0434: sb.append(COLOR_END);
0435: sb.append(PKG_COLOR);
0436: sb.append(" ("); //NOI18N
0437: sb.append(enclName);
0438: sb.append(")"); //NOI18N
0439: }
0440: sb.append(COLOR_END);
0441: leftText = sb.toString();
0442: }
0443: return leftText;
0444: }
0445:
0446: protected String getColor() {
0447: return CLASS_COLOR;
0448: }
0449:
0450: @Override
0451: protected ImageIcon getIcon() {
0452: return new ImageIcon(Utilities.loadImage(CLASS));
0453: }
0454:
0455: @Override
0456: public CompletionTask createDocumentationTask() {
0457: return new AsyncCompletionTask(new JavaElementDocQuery(
0458: elemHandle), EditorRegistry.lastFocusedComponent());
0459: }
0460: }
0461:
0462: private static class PackageItem extends
0463: SpringXMLConfigCompletionItem {
0464:
0465: private static final String PACKAGE = "org/netbeans/modules/java/editor/resources/package.gif"; // NOI18N
0466: private static final String PACKAGE_COLOR = "<font color=#005600>"; //NOI18N
0467: private static ImageIcon icon;
0468:
0469: private boolean deprecated;
0470: private String simpleName;
0471: private String sortText;
0472: private String leftText;
0473:
0474: public PackageItem(int substitutionOffset, String packageFQN,
0475: boolean deprecated) {
0476: super (substitutionOffset);
0477: int idx = packageFQN.lastIndexOf('.'); // NOI18N
0478: this .simpleName = idx < 0 ? packageFQN : packageFQN
0479: .substring(idx + 1);
0480: this .deprecated = deprecated;
0481: this .sortText = this .simpleName + "#" + packageFQN; //NOI18N
0482: }
0483:
0484: public int getSortPriority() {
0485: return 50;
0486: }
0487:
0488: public CharSequence getSortText() {
0489: return sortText;
0490: }
0491:
0492: public CharSequence getInsertPrefix() {
0493: return simpleName;
0494: }
0495:
0496: @Override
0497: public void processKeyEvent(KeyEvent evt) {
0498: if (evt.getID() == KeyEvent.KEY_TYPED) {
0499: if (evt.getKeyChar() == '.') { // NOI18N
0500: Completion.get().hideDocumentation();
0501: JTextComponent component = (JTextComponent) evt
0502: .getSource();
0503: int caretOffset = component.getSelectionEnd();
0504: substituteText(component, substitutionOffset,
0505: caretOffset - substitutionOffset, Character
0506: .toString(evt.getKeyChar()));
0507: Completion.get().showCompletion();
0508: evt.consume();
0509: }
0510: }
0511: }
0512:
0513: @Override
0514: protected ImageIcon getIcon() {
0515: if (icon == null)
0516: icon = new ImageIcon(org.openide.util.Utilities
0517: .loadImage(PACKAGE));
0518: return icon;
0519: }
0520:
0521: @Override
0522: protected String getLeftHtmlText() {
0523: if (leftText == null) {
0524: StringBuilder sb = new StringBuilder();
0525: sb.append(PACKAGE_COLOR);
0526: if (deprecated)
0527: sb.append(STRIKE);
0528: sb.append(simpleName);
0529: if (deprecated)
0530: sb.append(STRIKE_END);
0531: sb.append(COLOR_END);
0532: leftText = sb.toString();
0533: }
0534: return leftText;
0535: }
0536: }
0537:
0538: private static class MethodItem extends
0539: SpringXMLConfigCompletionItem {
0540:
0541: private static final String METHOD_PUBLIC = "org/netbeans/modules/editor/resources/completion/method_16.png"; //NOI18N
0542: private static final String METHOD_PROTECTED = "org/netbeans/modules/editor/resources/completion/method_protected_16.png"; //NOI18N
0543: private static final String METHOD_PACKAGE = "org/netbeans/modules/editor/resources/completion/method_package_private_16.png"; //NOI18N
0544: private static final String METHOD_PRIVATE = "org/netbeans/modules/editor/resources/completion/method_private_16.png"; //NOI18N
0545: private static final String METHOD_ST_PUBLIC = "org/netbeans/modules/editor/resources/completion/method_static_16.png"; //NOI18N
0546: private static final String METHOD_ST_PROTECTED = "org/netbeans/modules/editor/resources/completion/method_static_protected_16.png"; //NOI18N
0547: private static final String METHOD_ST_PRIVATE = "org/netbeans/modules/editor/resources/completion/method_static_private_16.png"; //NOI18N
0548: private static final String METHOD_ST_PACKAGE = "org/netbeans/modules/editor/resources/completion/method_static_package_private_16.png"; //NOI18N
0549: private static final String METHOD_COLOR = "<font color=#000000>"; //NOI18N
0550: private static final String PARAMETER_NAME_COLOR = "<font color=#a06001>"; //NOI18N
0551: private static ImageIcon icon[][] = new ImageIcon[2][4];
0552:
0553: private ElementHandle<ExecutableElement> elementHandle;
0554: private boolean isDeprecated;
0555: private String simpleName;
0556: private Set<Modifier> modifiers;
0557: private List<ParamDesc> params;
0558: private boolean isPrimitive;
0559: private String typeName;
0560: private String sortText;
0561: private String leftText;
0562: private boolean isInherited;
0563: private String rightText;
0564:
0565: public MethodItem(int substitutionOffset,
0566: ExecutableElement element, boolean isInherited,
0567: boolean isDeprecated) {
0568: super (substitutionOffset);
0569: this .elementHandle = ElementHandle.create(element);
0570: this .isDeprecated = isDeprecated;
0571: this .isInherited = isInherited;
0572: this .simpleName = element.getSimpleName().toString();
0573: this .modifiers = element.getModifiers();
0574: this .params = new ArrayList<ParamDesc>();
0575: Iterator<? extends VariableElement> it = element
0576: .getParameters().iterator();
0577: Iterator<? extends TypeMirror> tIt = ((ExecutableType) element
0578: .asType()).getParameterTypes().iterator();
0579: while (it.hasNext() && tIt.hasNext()) {
0580: TypeMirror tm = tIt.next();
0581: this .params.add(new ParamDesc(tm.toString(),
0582: getTypeName(tm, false,
0583: element.isVarArgs() && !tIt.hasNext())
0584: .toString(), it.next().getSimpleName()
0585: .toString()));
0586: }
0587: TypeMirror retType = element.getReturnType();
0588:
0589: this .typeName = getTypeName(retType, false).toString();
0590: this .isPrimitive = retType.getKind().isPrimitive()
0591: || retType.getKind() == TypeKind.VOID;
0592: }
0593:
0594: public int getSortPriority() {
0595: return 100;
0596: }
0597:
0598: public CharSequence getSortText() {
0599: if (sortText == null) {
0600: StringBuilder sortParams = new StringBuilder();
0601: sortParams.append('('); // NOI18N
0602: int cnt = 0;
0603: for (Iterator<ParamDesc> it = params.iterator(); it
0604: .hasNext();) {
0605: ParamDesc param = it.next();
0606: sortParams.append(param.typeName);
0607: if (it.hasNext()) {
0608: sortParams.append(','); // NOI18N
0609: }
0610: cnt++;
0611: }
0612: sortParams.append(')'); // NOI18N
0613: sortText = simpleName + "#"
0614: + ((cnt < 10 ? "0" : "") + cnt) + "#"
0615: + sortParams.toString(); //NOI18N
0616: }
0617: return sortText;
0618: }
0619:
0620: public CharSequence getInsertPrefix() {
0621: return simpleName;
0622: }
0623:
0624: @Override
0625: protected String getLeftHtmlText() {
0626: if (leftText == null) {
0627: StringBuilder lText = new StringBuilder();
0628: lText.append(METHOD_COLOR);
0629: if (!isInherited)
0630: lText.append(BOLD);
0631: if (isDeprecated)
0632: lText.append(STRIKE);
0633: lText.append(simpleName);
0634: if (isDeprecated)
0635: lText.append(STRIKE_END);
0636: if (!isInherited)
0637: lText.append(BOLD_END);
0638: lText.append(COLOR_END);
0639: lText.append('('); // NOI18N
0640: for (Iterator<ParamDesc> it = params.iterator(); it
0641: .hasNext();) {
0642: ParamDesc paramDesc = it.next();
0643: lText.append(escape(paramDesc.typeName));
0644: lText.append(' ');
0645: lText.append(PARAMETER_NAME_COLOR);
0646: lText.append(paramDesc.name);
0647: lText.append(COLOR_END);
0648: if (it.hasNext()) {
0649: lText.append(", "); //NOI18N
0650: }
0651: }
0652: lText.append(')'); // NOI18N
0653: return lText.toString();
0654: }
0655: return leftText;
0656: }
0657:
0658: @Override
0659: protected String getRightHtmlText() {
0660: if (rightText == null)
0661: rightText = escape(typeName);
0662: return rightText;
0663: }
0664:
0665: @Override
0666: protected ImageIcon getIcon() {
0667: int level = getProtectionLevel(modifiers);
0668: boolean isStatic = modifiers.contains(Modifier.STATIC);
0669: ImageIcon cachedIcon = icon[isStatic ? 1 : 0][level];
0670: if (cachedIcon != null)
0671: return cachedIcon;
0672:
0673: String iconPath = METHOD_PUBLIC;
0674: if (isStatic) {
0675: switch (level) {
0676: case PRIVATE_LEVEL:
0677: iconPath = METHOD_ST_PRIVATE;
0678: break;
0679:
0680: case PACKAGE_LEVEL:
0681: iconPath = METHOD_ST_PACKAGE;
0682: break;
0683:
0684: case PROTECTED_LEVEL:
0685: iconPath = METHOD_ST_PROTECTED;
0686: break;
0687:
0688: case PUBLIC_LEVEL:
0689: iconPath = METHOD_ST_PUBLIC;
0690: break;
0691: }
0692: } else {
0693: switch (level) {
0694: case PRIVATE_LEVEL:
0695: iconPath = METHOD_PRIVATE;
0696: break;
0697:
0698: case PACKAGE_LEVEL:
0699: iconPath = METHOD_PACKAGE;
0700: break;
0701:
0702: case PROTECTED_LEVEL:
0703: iconPath = METHOD_PROTECTED;
0704: break;
0705:
0706: case PUBLIC_LEVEL:
0707: iconPath = METHOD_PUBLIC;
0708: break;
0709: }
0710: }
0711: ImageIcon newIcon = new ImageIcon(
0712: org.openide.util.Utilities.loadImage(iconPath));
0713: icon[isStatic ? 1 : 0][level] = newIcon;
0714: return newIcon;
0715: }
0716:
0717: @Override
0718: public CompletionTask createDocumentationTask() {
0719: return new AsyncCompletionTask(new JavaElementDocQuery(
0720: elementHandle), EditorRegistry
0721: .lastFocusedComponent());
0722: }
0723:
0724: private static final int PUBLIC_LEVEL = 3;
0725: private static final int PROTECTED_LEVEL = 2;
0726: private static final int PACKAGE_LEVEL = 1;
0727: private static final int PRIVATE_LEVEL = 0;
0728:
0729: private static int getProtectionLevel(Set<Modifier> modifiers) {
0730: if (modifiers.contains(Modifier.PUBLIC)) {
0731: return PUBLIC_LEVEL;
0732: }
0733: if (modifiers.contains(Modifier.PROTECTED)) {
0734: return PROTECTED_LEVEL;
0735: }
0736: if (modifiers.contains(Modifier.PRIVATE)) {
0737: return PRIVATE_LEVEL;
0738: }
0739: return PACKAGE_LEVEL;
0740: }
0741:
0742: static class ParamDesc {
0743:
0744: private String fullTypeName;
0745: private String typeName;
0746: private String name;
0747:
0748: public ParamDesc(String fullTypeName, String typeName,
0749: String name) {
0750: this .fullTypeName = fullTypeName;
0751: this .typeName = typeName;
0752: this .name = name;
0753: }
0754: }
0755: }
0756:
0757: private static class AttribValueItem extends
0758: SpringXMLConfigCompletionItem {
0759:
0760: private String displayText;
0761: private String docText;
0762:
0763: public AttribValueItem(int substitutionOffset,
0764: String displayText, String docText) {
0765: super (substitutionOffset);
0766: this .displayText = displayText;
0767: this .docText = docText;
0768: }
0769:
0770: public int getSortPriority() {
0771: return 50;
0772: }
0773:
0774: public CharSequence getSortText() {
0775: return displayText;
0776: }
0777:
0778: public CharSequence getInsertPrefix() {
0779: return displayText;
0780: }
0781:
0782: @Override
0783: protected String getLeftHtmlText() {
0784: return displayText;
0785: }
0786:
0787: @Override
0788: public CompletionTask createDocumentationTask() {
0789: return new AsyncCompletionTask(new AsyncCompletionQuery() {
0790: @Override
0791: protected void query(CompletionResultSet resultSet,
0792: Document doc, int caretOffset) {
0793: if (docText != null) {
0794: CompletionDocumentation documentation = SpringXMLConfigCompletionDoc
0795: .getAttribValueDoc(docText);
0796: resultSet.setDocumentation(documentation);
0797: }
0798: resultSet.finish();
0799: }
0800: });
0801: }
0802: }
0803:
0804: private static class FolderItem extends
0805: SpringXMLConfigCompletionItem {
0806:
0807: private FileObject folder;
0808:
0809: public FolderItem(int substitutionOffset, FileObject folder) {
0810: super (substitutionOffset);
0811: this .folder = folder;
0812: }
0813:
0814: @Override
0815: public void processKeyEvent(KeyEvent evt) {
0816: if (evt.getID() == KeyEvent.KEY_TYPED) {
0817: if (evt.getKeyChar() == '/') { // NOI18N
0818: Completion.get().hideDocumentation();
0819: JTextComponent component = (JTextComponent) evt
0820: .getSource();
0821: int caretOffset = component.getSelectionEnd();
0822: substituteText(component, substitutionOffset,
0823: caretOffset - substitutionOffset, Character
0824: .toString(evt.getKeyChar()));
0825: Completion.get().showCompletion();
0826: evt.consume();
0827: }
0828: }
0829: }
0830:
0831: public int getSortPriority() {
0832: return 300;
0833: }
0834:
0835: public CharSequence getSortText() {
0836: return folder.getName();
0837: }
0838:
0839: public CharSequence getInsertPrefix() {
0840: return folder.getName();
0841: }
0842:
0843: @Override
0844: public boolean instantSubstitution(JTextComponent component) {
0845: return false;
0846: }
0847:
0848: @Override
0849: protected ImageIcon getIcon() {
0850: return new ImageIcon(getTreeFolderIcon());
0851: }
0852:
0853: @Override
0854: protected String getLeftHtmlText() {
0855: return folder.getName();
0856: }
0857:
0858: private static final String ICON_KEY_UIMANAGER = "Tree.closedIcon"; // NOI18N
0859: private static final String ICON_KEY_UIMANAGER_NB = "Nb.Explorer.Folder.icon"; // NOI18N
0860:
0861: /**
0862: * Returns default folder icon as {@link java.awt.Image}. Never returns
0863: * <code>null</code>.Adapted from J2SELogicalViewProvider
0864: */
0865: private static Image getTreeFolderIcon() {
0866: Image base = null;
0867: Icon baseIcon = UIManager.getIcon(ICON_KEY_UIMANAGER); // #70263
0868: if (baseIcon != null) {
0869: base = Utilities.icon2Image(baseIcon);
0870: } else {
0871: base = (Image) UIManager.get(ICON_KEY_UIMANAGER_NB); // #70263
0872: if (base == null) { // fallback to our owns
0873: final Node n = DataFolder.findFolder(
0874: Repository.getDefault()
0875: .getDefaultFileSystem().getRoot())
0876: .getNodeDelegate();
0877: base = n.getIcon(BeanInfo.ICON_COLOR_16x16);
0878: }
0879: }
0880: assert base != null;
0881: return base;
0882: }
0883: }
0884:
0885: private static class PropertyItem extends
0886: SpringXMLConfigCompletionItem {
0887:
0888: private ElementHandle<ExecutableElement> eh;
0889: private String displayName;
0890:
0891: public PropertyItem(int substitutionOffset,
0892: ExecutableElement setter) {
0893: super (substitutionOffset);
0894: char[] propertyName = setter.getSimpleName().toString()
0895: .substring(3).toCharArray();
0896: propertyName[0] = Character.toLowerCase(propertyName[0]);
0897: this .displayName = new String(propertyName);
0898: this .eh = ElementHandle.create(setter);
0899: }
0900:
0901: public int getSortPriority() {
0902: return 100;
0903: }
0904:
0905: public CharSequence getSortText() {
0906: return displayName;
0907: }
0908:
0909: public CharSequence getInsertPrefix() {
0910: return displayName;
0911: }
0912:
0913: @Override
0914: protected String getLeftHtmlText() {
0915: return displayName;
0916: }
0917: }
0918:
0919: private static class PropertyAttribItem extends
0920: SpringXMLConfigCompletionItem {
0921:
0922: private ElementHandle<ExecutableElement> eh;
0923: private String text;
0924:
0925: public PropertyAttribItem(int substitutionOffset, String text,
0926: ExecutableElement ee) {
0927: super (substitutionOffset);
0928: this .eh = ElementHandle.create(ee);
0929: this .text = text;
0930: }
0931:
0932: public int getSortPriority() {
0933: return 200;
0934: }
0935:
0936: public CharSequence getSortText() {
0937: return text;
0938: }
0939:
0940: public CharSequence getInsertPrefix() {
0941: return text;
0942: }
0943:
0944: @Override
0945: protected CharSequence getSubstitutionText() {
0946: return text + "=\"\""; // NOI18N
0947: }
0948:
0949: @Override
0950: protected String getLeftHtmlText() {
0951: return text;
0952: }
0953:
0954: @Override
0955: protected void substituteText(JTextComponent c, int offset,
0956: int len, String toAdd) {
0957: super .substituteText(c, offset, len, toAdd);
0958: int newCaretPos = c.getCaretPosition() - 1; // for achieving p:something-ref="|" on completion
0959: c.setCaretPosition(newCaretPos);
0960: }
0961: }
0962:
0963: private static class FileItem extends SpringXMLConfigCompletionItem {
0964:
0965: private FileObject file;
0966:
0967: public FileItem(int substitutionOffset, FileObject file) {
0968: super (substitutionOffset);
0969: this .file = file;
0970: }
0971:
0972: public int getSortPriority() {
0973: return 100;
0974: }
0975:
0976: public CharSequence getSortText() {
0977: return file.getNameExt();
0978: }
0979:
0980: public CharSequence getInsertPrefix() {
0981: return file.getNameExt();
0982: }
0983:
0984: @Override
0985: protected ImageIcon getIcon() {
0986: return new ImageIcon(
0987: Utilities
0988: .loadImage("org/netbeans/modules/spring/beans/resources/spring.png")); // NOI18N
0989: }
0990:
0991: @Override
0992: protected String getLeftHtmlText() {
0993: return file.getNameExt();
0994: }
0995: }
0996:
0997: public static CharSequence getElementName(Element el, boolean fqn) {
0998: if (el == null || el.asType().getKind() == TypeKind.NONE)
0999: return ""; //NOI18N
1000: return new ElementNameVisitor().visit(el, fqn);
1001: }
1002:
1003: private static class ElementNameVisitor extends
1004: SimpleElementVisitor6<StringBuilder, Boolean> {
1005:
1006: private ElementNameVisitor() {
1007: super (new StringBuilder());
1008: }
1009:
1010: @Override
1011: public StringBuilder visitPackage(PackageElement e, Boolean p) {
1012: return DEFAULT_VALUE.append((p ? e.getQualifiedName() : e
1013: .getSimpleName()).toString());
1014: }
1015:
1016: @Override
1017: public StringBuilder visitType(TypeElement e, Boolean p) {
1018: return DEFAULT_VALUE.append((p ? e.getQualifiedName() : e
1019: .getSimpleName()).toString());
1020: }
1021: }
1022:
1023: public static int getImportanceLevel(String fqn) {
1024: int weight = 50;
1025: if (fqn.startsWith("java.lang") || fqn.startsWith("java.util")) // NOI18N
1026: weight -= 10;
1027: else if (fqn.startsWith("org.omg")
1028: || fqn.startsWith("org.apache")) // NOI18N
1029: weight += 10;
1030: else if (fqn.startsWith("com.sun") || fqn.startsWith("com.ibm")
1031: || fqn.startsWith("com.apple")) // NOI18N
1032: weight += 20;
1033: else if (fqn.startsWith("sun") || fqn.startsWith("sunw")
1034: || fqn.startsWith("netscape")) // NOI18N
1035: weight += 30;
1036: return weight;
1037: }
1038:
1039: public static CharSequence getTypeName(TypeMirror type, boolean fqn) {
1040: return getTypeName(type, fqn, false);
1041: }
1042:
1043: public static CharSequence getTypeName(TypeMirror type,
1044: boolean fqn, boolean varArg) {
1045: if (type == null)
1046: return ""; //NOI18N
1047: return new TypeNameVisitor(varArg).visit(type, fqn);
1048: }
1049:
1050: private static final String UNKNOWN = "<unknown>"; //NOI18N
1051: private static final String CAPTURED_WILDCARD = "<captured wildcard>"; //NOI18N
1052:
1053: private static class TypeNameVisitor extends
1054: SimpleTypeVisitor6<StringBuilder, Boolean> {
1055:
1056: private boolean varArg;
1057:
1058: private TypeNameVisitor(boolean varArg) {
1059: super (new StringBuilder());
1060: this .varArg = varArg;
1061: }
1062:
1063: @Override
1064: public StringBuilder defaultAction(TypeMirror t, Boolean p) {
1065: return DEFAULT_VALUE.append(t);
1066: }
1067:
1068: @Override
1069: public StringBuilder visitDeclared(DeclaredType t, Boolean p) {
1070: Element e = t.asElement();
1071: if (e instanceof TypeElement) {
1072: TypeElement te = (TypeElement) e;
1073: DEFAULT_VALUE.append((p ? te.getQualifiedName() : te
1074: .getSimpleName()).toString());
1075: Iterator<? extends TypeMirror> it = t
1076: .getTypeArguments().iterator();
1077: if (it.hasNext()) {
1078: DEFAULT_VALUE.append("<"); //NOI18N
1079: while (it.hasNext()) {
1080: visit(it.next(), p);
1081: if (it.hasNext())
1082: DEFAULT_VALUE.append(", "); //NOI18N
1083: }
1084: DEFAULT_VALUE.append(">"); //NOI18N
1085: }
1086: return DEFAULT_VALUE;
1087: } else {
1088: return DEFAULT_VALUE.append(UNKNOWN); //NOI18N
1089: }
1090: }
1091:
1092: @Override
1093: public StringBuilder visitArray(ArrayType t, Boolean p) {
1094: boolean isVarArg = varArg;
1095: varArg = false;
1096: visit(t.getComponentType(), p);
1097: return DEFAULT_VALUE.append(isVarArg ? "..." : "[]"); //NOI18N
1098: }
1099:
1100: @Override
1101: public StringBuilder visitTypeVariable(TypeVariable t, Boolean p) {
1102: Element e = t.asElement();
1103: if (e != null) {
1104: String name = e.getSimpleName().toString();
1105: if (!CAPTURED_WILDCARD.equals(name))
1106: return DEFAULT_VALUE.append(name);
1107: }
1108: DEFAULT_VALUE.append("?"); //NOI18N
1109: TypeMirror bound = t.getLowerBound();
1110: if (bound != null && bound.getKind() != TypeKind.NULL) {
1111: DEFAULT_VALUE.append(" super "); //NOI18N
1112: visit(bound, p);
1113: } else {
1114: bound = t.getUpperBound();
1115: if (bound != null && bound.getKind() != TypeKind.NULL) {
1116: DEFAULT_VALUE.append(" extends "); //NOI18N
1117: if (bound.getKind() == TypeKind.TYPEVAR)
1118: bound = ((TypeVariable) bound).getLowerBound();
1119: visit(bound, p);
1120: }
1121: }
1122: return DEFAULT_VALUE;
1123: }
1124:
1125: @Override
1126: public StringBuilder visitWildcard(WildcardType t, Boolean p) {
1127: DEFAULT_VALUE.append("?"); //NOI18N
1128: TypeMirror bound = t.getSuperBound();
1129: if (bound == null) {
1130: bound = t.getExtendsBound();
1131: if (bound != null) {
1132: DEFAULT_VALUE.append(" extends "); //NOI18N
1133: if (bound.getKind() == TypeKind.WILDCARD)
1134: bound = ((WildcardType) bound).getSuperBound();
1135: visit(bound, p);
1136: } else {
1137: bound = SourceUtils.getBound(t);
1138: if (bound != null
1139: && (bound.getKind() != TypeKind.DECLARED || !((TypeElement) ((DeclaredType) bound)
1140: .asElement()).getQualifiedName()
1141: .contentEquals("java.lang.Object"))) { //NOI18N
1142: DEFAULT_VALUE.append(" extends "); //NOI18N
1143: visit(bound, p);
1144: }
1145: }
1146: } else {
1147: DEFAULT_VALUE.append(" super "); //NOI18N
1148: visit(bound, p);
1149: }
1150: return DEFAULT_VALUE;
1151: }
1152:
1153: @Override
1154: public StringBuilder visitError(ErrorType t, Boolean p) {
1155: Element e = t.asElement();
1156: if (e instanceof TypeElement) {
1157: TypeElement te = (TypeElement) e;
1158: return DEFAULT_VALUE.append((p ? te.getQualifiedName()
1159: : te.getSimpleName()).toString());
1160: }
1161: return DEFAULT_VALUE;
1162: }
1163: }
1164:
1165: private static String escape(String s) {
1166: if (s != null) {
1167: try {
1168: return XMLUtil.toAttributeValue(s);
1169: } catch (Exception ex) {
1170: }
1171: }
1172: return s;
1173: }
1174:
1175: private static class JavaElementDocQuery extends
1176: AsyncCompletionQuery {
1177:
1178: private ElementHandle<?> elemHandle;
1179:
1180: public JavaElementDocQuery(ElementHandle<?> elemHandle) {
1181: this .elemHandle = elemHandle;
1182: }
1183:
1184: @Override
1185: protected void query(final CompletionResultSet resultSet,
1186: Document doc, int caretOffset) {
1187: try {
1188: JavaSource js = SpringXMLConfigEditorUtils
1189: .getJavaSource(doc);
1190: if (js == null) {
1191: return;
1192: }
1193:
1194: js.runUserActionTask(new Task<CompilationController>() {
1195:
1196: public void run(CompilationController cc)
1197: throws Exception {
1198: cc.toPhase(Phase.RESOLVED);
1199: Element element = elemHandle.resolve(cc);
1200: if (element == null) {
1201: return;
1202: }
1203: SpringXMLConfigCompletionDoc doc = SpringXMLConfigCompletionDoc
1204: .createJavaDoc(cc, element);
1205: resultSet.setDocumentation(doc);
1206: }
1207: }, false);
1208: resultSet.finish();
1209: } catch (IOException ex) {
1210: Exceptions.printStackTrace(ex);
1211: }
1212: }
1213: }
1214: }
|