/*******************************************************************************
* Copyright (c) 2007, 2011 Spring IDE Developers
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Spring IDE Developers - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.beans.ui.editor.contentassist;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.internal.corext.util.TypeFilter;
import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider;
import org.eclipse.swt.graphics.Image;
import org.eclipse.wst.xml.ui.internal.contentassist.ContentAssistRequest;
import org.springframework.ide.eclipse.beans.ui.editor.Activator;
import org.springframework.ide.eclipse.core.java.AndMethodFilter;
import org.springframework.ide.eclipse.core.java.IMethodFilter;
import org.springframework.ide.eclipse.core.java.Introspector;
import org.springframework.ide.eclipse.core.java.JdtUtils;
/**
* {@link IContentAssistCalculator} that can be used to calculate proposals for {@link IMethod}.
* <p>
* This implementation uses a customizable {@link IMethodFilter} to filter for appropriate methods.
* @author Christian Dupuis
* @author Martin Lippert
* @since 2.0.2
*/
@SuppressWarnings("restriction")
public abstract class MethodContentAssistCalculator implements IContentAssistCalculator {
public static final int METHOD_RELEVANCE = 10;
protected final IMethodFilter filter;
/**
* Constructor
* @param filter filter to be used for filtering {@link IMethod}s
*/
public MethodContentAssistCalculator(IMethodFilter filter) {
AndMethodFilter andFilter = new AndMethodFilter();
andFilter.addMethodFilter(new TypeFilterMethodFilterAdapter());
andFilter.addMethodFilter(filter);
this.filter = andFilter;
}
/**
* Calculate the {@link IType} that should be searched for matching methods. This method is
* intended to be implemented by subclasses as there is no common approach to locate the
* {@link IType}.
* @param context the current context of the content assist request
* @return the {@link IType} that should be used for searching
*/
protected abstract IType calculateType(IContentAssistContext context);
/**
* Calculate proposals. This implementation calls {@link #calculateType} to get the root for the
* search and passes the returned {@link IType} and the instance's {@link IMethodFilter} to
* {@link Introspector#findAllMethods(IType, String, IMethodFilter)}.
* <p>
* If a match is found the {@link #createMethodProposal} is called to report the match as a
* proposal in the content assist request.
*/
public void computeProposals(IContentAssistContext context,
IContentAssistProposalRecorder recorder) {
Set<String> proposedMethods = new HashSet<String>();
for (IMethod method : Introspector.findAllMethods(calculateType(context), context
.getMatchString(), filter)) {
if (!proposedMethods.contains(method.getElementName())) {
proposedMethods.add(method.getElementName());
createMethodProposal(recorder, method);
}
}
}
/**
* Create a {@link BeansJavaCompletionProposal} for the given {@link IMethod} and report it on
* the {@link ContentAssistRequest}.
*/
protected void createMethodProposal(IContentAssistProposalRecorder recorder, IMethod method) {
try {
String[] parameterNames = method.getParameterNames();
String[] parameterTypes = JdtUtils.getParameterTypesString(method);
String returnType = JdtUtils.getReturnTypeString(method, true);
String methodName = JdtUtils.getMethodName(method);
String replaceText = methodName;
StringBuilder buf = new StringBuilder();
// add method name
buf.append(replaceText);
// add method parameters
if (parameterTypes.length > 0 && parameterNames.length > 0) {
buf.append(" (");
for (int i = 0; i < parameterTypes.length; i++) {
buf.append(parameterTypes[i]);
buf.append(' ');
buf.append(parameterNames[i]);
if (i < (parameterTypes.length - 1)) {
buf.append(", ");
}
}
buf.append(") ");
}
else {
buf.append("() ");
}
// add return type
if (returnType != null) {
buf.append(Signature.getSimpleName(returnType));
buf.append(" - ");
}
else {
buf.append(" void - ");
}
// add class name
buf.append(JdtUtils.getParentName(method));
String displayText = buf.toString();
Image image = Activator.getDefault().getJavaElementLabelProvider().getImageLabel(
method, method.getFlags() | JavaElementImageProvider.SMALL_ICONS);
recorder.recordProposal(image, METHOD_RELEVANCE, displayText, replaceText, method);
}
catch (JavaModelException e) {
// do nothing
}
}
/**
* Internal {@link IMethodFilter} that delegates to JDT's type filter infrastructure.
*/
class TypeFilterMethodFilterAdapter implements IMethodFilter {
/**
* {@inheritDoc}
*/
public boolean matches(IMethod method, String prefix) {
return !TypeFilter.isFiltered(method.getDeclaringType());
}
}
}