/* * 03/21/2010 * * Copyright (C) 2010 Robert Futrell * robert_futrell at users.sourceforge.net * http://fifesoft.com/rsyntaxtextarea * * This library is distributed under a modified BSD license. See the included * RSTALanguageSupport.License.txt file for details. */ package org.fife.rsta.ac.java; import java.awt.Color; import java.awt.FontMetrics; import java.awt.Graphics; import java.util.ArrayList; import java.util.List; import javax.swing.Icon; import javax.swing.text.JTextComponent; import org.fife.rsta.ac.java.classreader.MethodInfo; import org.fife.rsta.ac.java.rjc.ast.FormalParameter; import org.fife.rsta.ac.java.rjc.ast.Method; import org.fife.rsta.ac.java.rjc.lang.Type; import org.fife.ui.autocomplete.Completion; import org.fife.ui.autocomplete.CompletionProvider; import org.fife.ui.autocomplete.FunctionCompletion; import org.fife.ui.autocomplete.ParameterizedCompletion; /** * A completion for a Java method. This completion gets its information from * one of two sources: * * <ul> * <li>A {@link MethodInfo} instance, which is loaded by parsing a class * file. This is used when this completion represents a method found * in a compiled library.</li> * <li>A {@link Method} instance, which is created when parsing a Java * source file. This is used when the completion represents a method * found in uncompiled source, such as the source in an * <tt>RSyntaxTextArea</tt>, or in a loose file on disk.</li> * </ul> * * @author Robert Futrell * @version 1.0 */ class MethodCompletion extends FunctionCompletion implements MemberCompletion { /** * The data source for our completion attributes. */ private Data data; /** * Used to compare this method completion with another. */ private String compareString; /** * The relevance of methods. This allows methods to be "higher" in * the completion list than other types. */ private static final int NON_CONSTRUCTOR_RELEVANCE = 2; /** * Creates a completion for a method discovered when parsing a Java * source file. * * @param provider * @param m Meta data about the method. */ public MethodCompletion(CompletionProvider provider, Method m) { // NOTE: "void" might not be right - I think this might be constructors super(provider, m.getName(), m.getType()==null ? "void" : m.getType().toString()); setDefinedIn(m.getParentTypeDeclaration().getName()); this.data = new MethodData(m); setRelevanceAppropriately(); int count = m.getParameterCount(); List params = new ArrayList(count); for (int i=0; i<count; i++) { FormalParameter param = m.getParameter(i); Type type = param.getType(); String name = param.getName(); params.add(new ParameterizedCompletion.Parameter(type, name)); } setParams(params); } /** * Creates a completion for a method discovered when parsing a compiled * class file. * * @param provider * @param info Meta data about the method. */ public MethodCompletion(CompletionProvider provider, MethodInfo info) { super(provider, info.getName(), info.getReturnTypeString(false)); setDefinedIn(info.getClassFile().getClassName(false)); this.data = new MethodInfoData(info, (SourceCompletionProvider)provider); setRelevanceAppropriately(); String[] paramTypes = info.getParameterTypes(); List params = new ArrayList(paramTypes.length); for (int i=0; i<paramTypes.length; i++) { String name = ((MethodInfoData)data).getParameterName(i); String type = paramTypes[i].substring(paramTypes[i].lastIndexOf('.')+1); params.add(new ParameterizedCompletion.Parameter(type, name)); } setParams(params); } /** * Overridden to compare methods by their comparison strings. * * @param o A <code>Completion</code> to compare to. * @return The sort order. */ @Override public int compareTo(Completion o) { int rc = -1; if (o==this) { rc = 0; } else if (o instanceof MethodCompletion) { rc = getCompareString().compareTo( ((MethodCompletion)o).getCompareString()); } else if (o instanceof Completion) { Completion c2 = (Completion)o; rc = toString().compareToIgnoreCase(c2.toString()); if (rc==0) { // Same text value String clazz1 = getClass().getName(); clazz1 = clazz1.substring(clazz1.lastIndexOf('.')); String clazz2 = c2.getClass().getName(); clazz2 = clazz2.substring(clazz2.lastIndexOf('.')); rc = clazz1.compareTo(clazz2); } } return rc; } public boolean equals(Object obj) { return (obj instanceof MethodCompletion) && //((MethodCompletion)obj).getSignature().equals(getSignature()); ((MethodCompletion)obj).getCompareString().equals(getCompareString()); } public String getAlreadyEntered(JTextComponent comp) { String temp = getProvider().getAlreadyEnteredText(comp); int lastDot = temp.lastIndexOf('.'); if (lastDot>-1) { temp = temp.substring(lastDot+1); } return temp; } /** * Returns a string used to compare this method completion to another. * * @return The comparison string. */ private String getCompareString() { /* * This string compares the following parts of methods in this order, * to optimize sort order in completion lists. * * 1. First, by name * 2. Next, by number of parameters. * 3. Finally, by parameter type. */ if (compareString==null) { StringBuffer sb = new StringBuffer(getName()); // NOTE: This will fail if a method has > 99 parameters (!) int paramCount = getParamCount(); if (paramCount<10) { sb.append('0'); } sb.append(paramCount); for (int i=0; i<paramCount; i++) { String type = getParam(i).getType(); sb.append(type); if (i<paramCount-1) { sb.append(','); } } compareString = sb.toString(); } return compareString; } public String getEnclosingClassName(boolean fullyQualified) { return data.getEnclosingClassName(fullyQualified); } public Icon getIcon() { return IconFactory.get().getIcon(data); } public String getSignature() { return data.getSignature(); } public String getSummary() { String summary = data.getSummary(); // Could be just the method name // If it's the Javadoc for the method... if (summary!=null && summary.startsWith("/**")) { summary = org.fife.rsta.ac.java.Util.docCommentToHtml(summary); } return summary; } public int hashCode() { return getCompareString().hashCode(); } public boolean isDeprecated() { return data.isDeprecated(); } /** * {@inheritDoc} */ public void rendererText(Graphics g, int x, int y, boolean selected) { rendererText(this, g, x, y, selected); } /** * Sets the relevance of this constructor based on its properties. */ private void setRelevanceAppropriately() { // Only change relevance from the default if this isn't a constructor. if (!data.isConstructor()) { setRelevance(NON_CONSTRUCTOR_RELEVANCE); } } /** * Renders a member completion. * * @param mc * @param g * @param x * @param y * @param selected */ public static void rendererText(MemberCompletion mc, Graphics g, int x, int y, boolean selected) { String shortType = mc.getType(); int dot = shortType.lastIndexOf('.'); if (dot>-1) { shortType = shortType.substring(dot+1); } // Draw the method signature String sig = mc.getSignature(); FontMetrics fm = g.getFontMetrics(); g.drawString(sig, x, y); int newX = x + fm.stringWidth(sig); if (mc.isDeprecated()) { int midY = y + fm.getDescent() - fm.getHeight()/2; g.drawLine(x, midY, newX, midY); } x = newX; // Append the return type StringBuffer sb = new StringBuffer(" : ").append(shortType); sb.append(" - "); String s = sb.toString(); g.drawString(s, x, y); x += fm.stringWidth(s); // Append the type of the containing class of this member. Color origColor = g.getColor(); if (!selected) { g.setColor(Color.GRAY); } g.drawString(mc.getEnclosingClassName(false), x, y); if (!selected) { g.setColor(origColor); } } /** * {@inheritDoc} */ public String toString() { return getSignature(); } }