/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2014, Geomatys * * This library 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; * version 2.1 of the License. * * This library 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. */ package org.geotoolkit.gui.javafx.parameter; import java.util.Collection; import java.util.logging.Level; import javafx.beans.property.Property; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.scene.Node; import javafx.scene.control.Spinner; import javafx.scene.control.SpinnerValueFactory; import javafx.util.StringConverter; import org.apache.sis.util.Numbers; import org.apache.sis.util.ObjectConverter; import org.apache.sis.util.ObjectConverters; import org.geotoolkit.internal.Loggers; import org.opengis.feature.AttributeType; import org.opengis.parameter.ParameterDescriptor; /** * * @author Johann Sorel (Geomatys) */ public class FXNumberEditor extends FXValueEditor { private final Spinner spinner = new Spinner(); public FXNumberEditor(Spi originatingSpi) { super(originatingSpi); currentAttributeType.addListener(this::updateValueFactory); currentParamDesc.addListener(this::updateValueFactory); updateValueFactory(null, null, null); } @Override public Node getComponent() { return spinner; } @Override public Property valueProperty() { return spinner.getValueFactory().valueProperty(); } @Override protected Class getValueClass() { Class valueClass = super.getValueClass(); if (valueClass.isPrimitive()) return Numbers.primitiveToWrapper(valueClass); else if (Number.class.isAssignableFrom(valueClass)) return valueClass; else return Double.class; } /** * Update spinner configuration according to given descriptor/ type. * @param observable Not used * @param oldValue Not used * @param newValue Not used */ protected void updateValueFactory(final ObservableValue observable, final Object oldValue, final Object newValue) { final Class valueClass = getValueClass(); final Object minValue; final Object maxValue; final Collection valueList; if (newValue instanceof ParameterDescriptor) { final ParameterDescriptor desc = (ParameterDescriptor) newValue; minValue = desc.getMinimumValue(); maxValue = desc.getMaximumValue(); valueList = desc.getValidValues(); } else if (newValue instanceof AttributeType) { final AttributeType aType = (AttributeType) newValue; valueList = extractChoices(aType); // TODO : extract min and max minValue = null; maxValue = null; } else { minValue = null; maxValue = null; valueList = null; } final SpinnerValueFactory factory; if (valueList != null && !valueList.isEmpty()) { factory = new SpinnerValueFactory.ListSpinnerValueFactory(FXCollections.observableArrayList(valueList)); } else if (Float.class.isAssignableFrom(valueClass)) { Float minF = (minValue == null? Float.NaN : ObjectConverters.convert(minValue, Float.class)); Float maxF = (maxValue == null? Float.NaN : ObjectConverters.convert(maxValue, Float.class)); factory = new SpinnerValueFactory.DoubleSpinnerValueFactory(Float.isNaN(minF)? -Float.MAX_VALUE : minF, Float.isNaN(maxF)? Float.MAX_VALUE : maxF, 0); } else if (Double.class.isAssignableFrom(valueClass)) { Double minD = (minValue == null? Double.NaN : ObjectConverters.convert(minValue, Double.class)); Double maxD = (maxValue == null? Double.NaN : ObjectConverters.convert(maxValue, Double.class)); factory = new SpinnerValueFactory.DoubleSpinnerValueFactory(Double.isNaN(minD)? -Double.MAX_VALUE : minD, Double.isNaN(maxD)? Double.MAX_VALUE : maxD, 0); } else { Integer minI = (minValue == null? Integer.MIN_VALUE : ObjectConverters.convert(minValue, Integer.class)); Integer maxI = (maxValue == null? Integer.MAX_VALUE : ObjectConverters.convert(maxValue, Integer.class)); factory = new SpinnerValueFactory.IntegerSpinnerValueFactory(minI, maxI, 0); } /* We try to get a converter to allow user to type text in the spinner. * If we fail at obtaining one, the spinner will not be editable. */ try { final ObjectConverter<Object, String> converter = ObjectConverters.find(valueClass, String.class); final ObjectConverter<String, Object> inverse = converter.inverse(); factory.setConverter(new StringConverter() { @Override public String toString(Object object) { return converter.apply(object); } @Override public Object fromString(String string) { return inverse.apply(string); } }); spinner.setEditable(true); } catch (Exception e) { Loggers.JAVAFX.log(Level.FINE, null, e); spinner.setEditable(false); } spinner.setValueFactory(factory); } public static final class Spi extends FXValueEditorSpi { @Override public boolean canHandle(Class binding) { return Number.class.isAssignableFrom(binding) || byte.class.equals(binding) || short.class.equals(binding) || int.class.equals(binding) || long.class.equals(binding) || float.class.equals(binding) || double.class.equals(binding); } @Override public FXValueEditor createEditor() { return new FXNumberEditor(this); } } }