package net.sourceforge.pmd.eclipse.ui.preferences.editors; import java.util.ArrayList; import java.util.List; import net.sourceforge.pmd.PropertyDescriptor; import net.sourceforge.pmd.PropertySource; import net.sourceforge.pmd.eclipse.ui.preferences.br.ValueChangeListener; import net.sourceforge.pmd.lang.rule.properties.PropertyDescriptorWrapper; import net.sourceforge.pmd.lang.rule.properties.TypeMultiProperty; import net.sourceforge.pmd.util.ClassUtil; import net.sourceforge.pmd.util.CollectionUtil; import net.sourceforge.pmd.util.StringUtil; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Text; /** * TODO - use new TypeText widget * * @author Brian Remedios */ public class MultiTypeEditorFactory extends AbstractMultiValueEditorFactory { public static final MultiTypeEditorFactory instance = new MultiTypeEditorFactory(); private MultiTypeEditorFactory() { } public PropertyDescriptor<?> createDescriptor(String name, String optionalDescription, Control[] otherData) { return new TypeMultiProperty(name, "Type value " + name, new Class[] {String.class}, new String[] { "java.lang" } , 0.0f); } public static String[] shortNamesFor(Class<?>[] types) { String[] typeNames = new String[types.length]; for (int i=0; i<typeNames.length; i++) { typeNames[i] = ClassUtil.asShortestName(types[i]); } return typeNames; } protected void fillWidget(Text textWidget, PropertyDescriptor<?> desc, PropertySource source) { Class<?>[] values = (Class[])valueFor(source, desc); if (values == null) { textWidget.setText(""); return; } textWidget.setText(values == null ? "" : asString(values)); adjustRendering(source, desc, textWidget); } private String asString(Class<?>[] types) { String[] typeNames = shortNamesFor(types); return StringUtil.asString(typeNames, delimiter + ' '); } private Class<?>[] currentTypes(Text textWidget) { String[] typeNames = textWidgetValues(textWidget); if (typeNames.length == 0) return ClassUtil.EMPTY_CLASS_ARRAY; List<Class<?>> types = new ArrayList<Class<?>>(typeNames.length); for (String typeName : typeNames) { Class<?> newType = TypeEditorFactory.typeFor(typeName); if (newType != null) types.add(newType); } return types.toArray(new Class[types.size()]); } private static TypeMultiProperty multiTypePropertyFrom(PropertyDescriptor<?> desc) { if (desc instanceof PropertyDescriptorWrapper<?>) { return (TypeMultiProperty) ((PropertyDescriptorWrapper<?>)desc).getPropertyDescriptor(); } else { return (TypeMultiProperty)desc; } } protected Control addWidget(Composite parent, Object value, PropertyDescriptor<?> desc, PropertySource source) { TypeText typeWidget = new TypeText(parent, SWT.SINGLE | SWT.BORDER, true, "Enter type name"); setValue(typeWidget, value); return typeWidget; } protected void setValue(Control widget, Object value) { Class<?> type = (Class<?>)value; ((TypeText)widget).setType(type); } protected void configure(final Text textWidget, final PropertyDescriptor<?> desc, final PropertySource source, final ValueChangeListener listener) { final TypeMultiProperty tmp = multiTypePropertyFrom(desc); // TODO - really necessary? textWidget.addListener(SWT.FocusOut, new Listener() { public void handleEvent(Event event) { Class<?>[] newValue = currentTypes(textWidget); Class<?>[] existingValue = (Class[])valueFor(source, tmp); if (CollectionUtil.areSemanticEquals(existingValue, newValue)) return; source.setProperty(tmp, newValue); fillWidget(textWidget, desc, source); // display the accepted values listener.changed(source, desc, newValue); adjustRendering(source, desc, textWidget); } }); } protected void update(PropertySource source, PropertyDescriptor<?> desc, List<Object> newValues) { source.setProperty((TypeMultiProperty)desc, newValues.toArray(new Class[newValues.size()])); } @Override protected Object addValueIn(Control widget, PropertyDescriptor<?> desc, PropertySource source) { Class<?> enteredValue = ((TypeText) widget).getType(true); if (enteredValue == null) return null; Class<?>[] currentValues = (Class[])valueFor(source, desc); Class<?>[] newValues = CollectionUtil.addWithoutDuplicates(currentValues, enteredValue); if (currentValues.length == newValues.length) return null; source.setProperty((TypeMultiProperty)desc, newValues); return enteredValue; } protected Object valueFrom(Control valueControl) { // not necessary for this type return null; } }