/*
* JBoss by Red Hat
* Copyright 2006-2009, Red Hat Middleware, LLC, and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.ide.eclipse.freemarker.model.interpolation;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.jface.text.contentassist.CompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.source.ISourceViewer;
import org.jboss.ide.eclipse.freemarker.configuration.ConfigurationManager;
import org.jboss.ide.eclipse.freemarker.configuration.ContextValue;
/**
* @author <a href="mailto:joe@binamics.com">Joe Hudson</a>
*/
public class NameFragment extends AbstractFragment {
public NameFragment(int offset, String content) {
super(offset, content);
}
public ICompletionProposal[] getCompletionProposals (int subOffset, int offset, Class parentClass,
List fragments, ISourceViewer sourceViewer, Map context, IResource file, IProject project) {
if (isStartFragment()) {
// pull from context
String prefix = getContent().substring(0, subOffset);
List proposals = new ArrayList();
for (Iterator i=context.keySet().iterator(); i.hasNext(); ) {
String key = (String) i.next();
if (key.startsWith(prefix)) proposals.add(getCompletionProposal(
offset, subOffset, key, getContent()));
}
return completionProposals(proposals);
}
else {
if (null == parentClass) return null;
return getMethodCompletionProposals (subOffset, offset, parentClass, file);
}
}
private Class returnClass;
public Class getReturnClass (Class parentClass, List fragments, Map context, IResource resource, IProject project){
if (null == returnClass) {
String content = getContent();
if (isStartFragment()) {
returnClass = (Class) context.get(content);
}
else {
if (null == parentClass) {
returnClass = Object.class;
}
else {
content = Character.toUpperCase(content.charAt(1)) + content.substring(2, getContent().length());
String getcontent = "get" + content; //$NON-NLS-1$
for (int i=0; i<parentClass.getMethods().length; i++) {
Method m = parentClass.getMethods()[i];
if (m.getName().equals(content) || m.getName().equals(getcontent)) {
returnClass = m.getReturnType();
break;
}
}
}
}
}
return returnClass;
}
private Class singulaReturnClass;
public Class getSingularReturnClass(Class parentClass, List fragments, Map context, IResource resource, IProject project) {
if (null == singulaReturnClass) {
String content = getContent();
if (isStartFragment()) {
ContextValue contextValue = ConfigurationManager.getInstance(project).getContextValue(content, resource, true);
if (null == contextValue || null == contextValue.singularClass)
singulaReturnClass = Object.class;
else
singulaReturnClass = contextValue.singularClass;
}
else {
if (null == parentClass) {
singulaReturnClass = Object.class;
}
else {
content = Character.toUpperCase(content.charAt(1)) + content.substring(2, getContent().length());
String getcontent = "get" + content; //$NON-NLS-1$
for (int i=0; i<parentClass.getMethods().length; i++) {
Method m = parentClass.getMethods()[i];
if (m.getName().equals(content) || m.getName().equals(getcontent)) {
Type type = m.getGenericReturnType();
if (type instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) type;
if (pType.getActualTypeArguments().length > 0) {
singulaReturnClass = (Class) pType.getActualTypeArguments()[0];
break;
}
}
singulaReturnClass = Object.class;
break;
}
}
}
}
}
return singulaReturnClass;
}
public boolean isStartFragment () {
return !getContent().startsWith("."); //$NON-NLS-1$
}
public static final String[] invalidMethods = {
"clone", "equals", "finalize", "getClass", "hashCode", "notify", "notifyAll", "toString", "wait"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$
public ICompletionProposal[] getMethodCompletionProposals (int subOffset, int offset, Class parentClass, IResource file) {
if (instanceOf(parentClass, String.class)
|| instanceOf(parentClass, Number.class)
|| instanceOf(parentClass, Date.class)
|| instanceOf(parentClass, Collection.class)
|| instanceOf(parentClass, List.class)
|| instanceOf(parentClass, Map.class))
return null;
String prefix = getContent().substring(1, subOffset);
List proposals = new ArrayList();
String pUpper = prefix.toUpperCase();
try {
BeanInfo bi = Introspector.getBeanInfo(parentClass);
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
for (int i=0; i<pds.length; i++) {
PropertyDescriptor pd = pds[i];
String propertyName = pd.getName();
if (!propertyName.equals("class") && propertyName.toUpperCase().startsWith(pUpper)) { //$NON-NLS-1$
proposals.add(new CompletionProposal(
propertyName,
offset - subOffset + 1,
getContent().length()-1,
propertyName.length(),
null, propertyName + " - " + pd.getReadMethod().getReturnType().getName(), null, null)); //$NON-NLS-1$
}
}
for (int i=0; i<parentClass.getMethods().length; i++) {
Method m = parentClass.getMethods()[i];
String mName = m.getName();
if (m.getParameterTypes().length > 0 && mName.startsWith("get") && mName.toUpperCase().startsWith(pUpper)) { //$NON-NLS-1$
StringBuffer display = new StringBuffer();
display.append(mName);
display.append("("); //$NON-NLS-1$
for (int j=0; j<m.getParameterTypes().length; j++) {
if (j > 0) display.append(", "); //$NON-NLS-1$
display.append(m.getParameterTypes()[j].getName());
}
display.append(")"); //$NON-NLS-1$
String actual = mName + "()"; //$NON-NLS-1$
int tLength = actual.length();
if (m.getParameterTypes().length > 0) tLength--;
proposals.add(new CompletionProposal(actual,
offset - subOffset + 1, getContent().length()-1, tLength,
null, display.toString() + " - " + m.getReturnType().getName(), null, null)); //$NON-NLS-1$
}
}
return completionProposals(proposals);
}
catch (IntrospectionException e) {
return null;
}
}
}