package net.sourceforge.pmd.eclipse.ui.preferences.editors; import java.lang.reflect.Method; import java.util.Arrays; import net.sourceforge.pmd.eclipse.util.Util; import net.sourceforge.pmd.util.StringUtil; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; /** * A general purpose selection widget that deals with methods. Once the user types in a valid type * in the left-most text field, all methods that are part of it are listed in the combobox on the * right. * * Note: Uses the default class loader to lookup the class, we'll probably want to supply an * external one in the future? * * @author Brian Remedios */ public class MethodPicker extends Composite { private TypeText typeText; private Combo methodList; private Method[] methods; private String[] unwantedPrefixes; public MethodPicker(Composite parent, int style, String[] theUnwantedPrefixes) { super(parent, SWT.None); unwantedPrefixes = theUnwantedPrefixes == null ? StringUtil.getEmptyStrings() : theUnwantedPrefixes; GridLayout layout = new GridLayout(2, true); layout.verticalSpacing = 0; layout.horizontalSpacing = 0; layout.marginHeight = 0; layout.marginWidth = 0; this.setLayout(layout); typeText = new TypeText(this, style, false, "Enter a type name"); // TODO i18l typeText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); typeText.addListener(SWT.FocusOut, new Listener() { public void handleEvent(Event event) { reviseMethodListFor(typeText.getType(true)); } }); typeText.addListener(SWT.Modify, new Listener() { public void handleEvent(Event event) { reviseMethodListFor(typeText.getType(false)); // no cleanup, avoid event loop & overflow } }); methodList = new Combo(this, style); methodList.setLayoutData(new GridData(GridData.FILL_BOTH)); } private void reviseMethodListFor(Class<?> cls) { if (cls == null) { methodList.removeAll(); methodList.setEnabled(false); return; } methodList.setEnabled(true); methods = cls.getMethods(); Arrays.sort(methods, Util.MethodNameComparator); String[] items = new String[methods.length]; for (int i=0; i<methods.length; i++) items[i] = Util.signatureFor(methods[i], unwantedPrefixes); methodList.setItems(items); methodList.select(0); } public void setBackground(Color clr) { typeText.setBackground(clr); methodList.setBackground(clr); } public Point computeSize(int wHint, int hHint, boolean changed) { Point pt = typeText.computeSize(wHint, hHint, changed); pt.x *= 2; pt.y += 2; // !@#$ combobox is taller than text box, need to avoid cropping it return pt; } public void setType(Class<?> cls) { typeText.setType(cls); } public void setEnabled(boolean flag) { super.setEnabled(flag); typeText.setEnabled(flag); methodList.setEnabled(flag); } public void setEditable(boolean flag) { typeText.setEditable(flag); } public Class<?> getType(boolean doCleanup) { return typeText.getType(doCleanup); } private int indexOf(Method method) { if (methods == null) return -1; for (int i=0; i<methods.length; i++) { if (methods[i].equals(method)) return i; } return -1; } public void setMethod(Method method) { if (method == null) { typeText.setType(null); return; } Class<?> cls = method.getDeclaringClass(); typeText.setType(cls); reviseMethodListFor(cls); methodList.select(indexOf(method)); } public Method getMethod() { return methods == null ? null : methods[methodList.getSelectionIndex()]; } public void addSelectionListener(SelectionListener listener) { methodList.addSelectionListener(listener); } }