package net.sourceforge.pmd.eclipse.ui.preferences.editors;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.pmd.NumericPropertyDescriptor;
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.IntegerMultiProperty;
import net.sourceforge.pmd.lang.rule.properties.PropertyDescriptorWrapper;
import net.sourceforge.pmd.util.CollectionUtil;
import net.sourceforge.pmd.util.NumericConstants;
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.Spinner;
import org.eclipse.swt.widgets.Text;
/**
* Behaviour:
* Provide a set of widgets that allows the user to pick a range of integer values. The selected values can only exist once.
*
* Provide a spin box for each value selected while ensuring that their choices only contain unselected values. If the last spin box holds the only
* remaining choice then ensure it gets disabled, the user can only delete it or the previous ones. If the user deletes a previous one then re-enable
* the last one and add the deleted value to its set of choices.
*
* @author Brian Remedios
*/
public class MultiIntegerEditorFactory extends AbstractMultiValueEditorFactory {
public static final MultiIntegerEditorFactory instance = new MultiIntegerEditorFactory();
private static final Integer[] emptyIntSet = new Integer[0];
private MultiIntegerEditorFactory() { }
public PropertyDescriptor<?> createDescriptor(String name, String optionalDescription, Control[] otherData) {
return new IntegerMultiProperty(name, "Integer values " + name, NumericConstants.ZERO, Integer.valueOf(10), new Integer[] {NumericConstants.ZERO}, 0.0f);
}
protected Object valueFrom(Control valueControl) {
return currentIntegers((Text)valueControl);
}
private Integer[] currentIntegers(Text textWidget) {
String[] numberStrings = textWidgetValues(textWidget);
if (numberStrings.length == 0) return emptyIntSet;
List<Integer> ints = new ArrayList<Integer>(numberStrings.length);
for (String numString : numberStrings) {
try {
Integer intrg = Integer.parseInt(numString);
ints.add(intrg);
} catch (Exception e) {
// just eat it for now
}
}
return ints.toArray(new Integer[ints.size()]);
}
private static NumericPropertyDescriptor<?> numericPropertyFrom(PropertyDescriptor<?> desc) {
if (desc instanceof PropertyDescriptorWrapper<?>) {
return (NumericPropertyDescriptor<?>) ((PropertyDescriptorWrapper<?>)desc).getPropertyDescriptor();
} else {
return (NumericPropertyDescriptor<?>)desc;
}
}
protected Control addWidget(Composite parent, Object value, PropertyDescriptor<?> desc, PropertySource source) {
NumericPropertyDescriptor<?> ip = numericPropertyFrom(desc); // TODO - do I really have to do this?
return IntegerEditorFactory.newSpinner(parent, ip, value);
}
protected void setValue(Control widget, Object valueIn) {
Spinner spinner = (Spinner)widget;
int value = valueIn == null ? spinner.getMinimum() : ((Number)valueIn).intValue();
spinner.setSelection(value);
}
protected void configure(final Text textWidget, final PropertyDescriptor<?> desc, final PropertySource source, final ValueChangeListener listener) {
final IntegerMultiProperty imp = (IntegerMultiProperty)numericPropertyFrom(desc);
textWidget.addListener(SWT.FocusOut, new Listener() {
public void handleEvent(Event event) {
Integer[] newValue = currentIntegers(textWidget);
Integer[] existingValue = (Integer[])valueFor(source, imp);
if (CollectionUtil.areSemanticEquals(existingValue, newValue)) return;
source.setProperty(imp, newValue);
fillWidget(textWidget, desc, source); // display the accepted values
listener.changed(source, desc, newValue);
}
});
}
protected void update(PropertySource source, PropertyDescriptor<?> desc, List<Object> newValues) {
source.setProperty((IntegerMultiProperty)desc, newValues.toArray(new Integer[newValues.size()]));
}
@Override
protected Object addValueIn(Control widget, PropertyDescriptor<?> desc, PropertySource source) {
Integer newValue= Integer.valueOf(((Spinner)widget).getSelection());
Integer[] currentValues = (Integer[])valueFor(source, desc);
Integer[] newValues = CollectionUtil.addWithoutDuplicates(currentValues, newValue);
if (currentValues.length == newValues.length) return null;
source.setProperty((IntegerMultiProperty)desc, newValues);
return newValue;
}
}