All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jidefx.scene.control.field.NumberField Maven / Gradle / Ivy

The newest version!
/*
 * @(#)NumberField.java 5/19/2013
 *
 * Copyright 2002 - 2013 JIDE Software Inc. All rights reserved.
 */

package jidefx.scene.control.field;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.util.StringConverter;
import jidefx.scene.control.field.verifier.FractionDigitsPatternVerifier;
import jidefx.scene.control.field.verifier.IntegerDigitsPatternVerifier;
import jidefx.utils.CommonUtils;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;

/**
 * A {@code FormattedTextField} for {@link Number}.
 */
public class NumberField extends FormattedTextField {
    public static enum NumberType {Normal, Integer, Percent, Currency}

    private BooleanProperty _positiveOnlyProperty;

    public NumberField() {
        setNumberType(NumberType.Normal);
    }

    public NumberField(NumberType type) {
        setNumberType(type);
    }

    private static final String STYLE_CLASS_DEFAULT = "number-field"; //NON-NLS

    @Override
    protected void initializeStyle() {
        super.initializeStyle();
        getStyleClass().addAll(STYLE_CLASS_DEFAULT);
    }

    @Override
    protected void initializeTextField() {
        super.initializeTextField();
        setSpinnersVisible(true);
    }

    private boolean isNegative(Number value) {
        // null is considered as positive as that matches our default pattern
        return value != null && value.doubleValue() < 0;
    }

    @Override
    protected void registerListeners() {
        super.registerListeners();
        valueProperty().addListener(new ChangeListener() {
            @Override
            public void changed(ObservableValue observable, Number oldValue, Number newValue) {
                if (!isNegative(oldValue) && isNegative(newValue)) {
                    initializePatternVerifiersForDecimalFormat(getDecimalFormat());
                }
                if (isNegative(oldValue) && !isNegative(newValue)) {
                    initializePatternVerifiersForDecimalFormat(getDecimalFormat());
                }
            }
        });
    }

    private ObjectProperty _numberTypeProperty;

    public ObjectProperty numberTypeProperty() {
        if (_numberTypeProperty == null) {
            _numberTypeProperty = new SimpleObjectProperty(this, "numberType") { //NON-NLS
                @Override
                protected void invalidated() {
                    super.invalidated();
                    DecimalFormat format = (DecimalFormat) DecimalFormat.getNumberInstance();
                    NumberType newValue = get();
                    switch (newValue) {
                        case Percent:
                            format = (DecimalFormat) DecimalFormat.getPercentInstance();
                            break;
                        case Currency:
                            format = (DecimalFormat) DecimalFormat.getCurrencyInstance();
                            break;
                        case Normal:
                            format = (DecimalFormat) DecimalFormat.getNumberInstance();
                            break;
                        case Integer:
                            format = (DecimalFormat) DecimalFormat.getIntegerInstance();
                            break;
                    }
                    format.setGroupingUsed(false);
                    setDecimalFormat(format);
                }
            };
        }
        return _numberTypeProperty;
    }

    public NumberType getNumberType() {
        return numberTypeProperty().get();
    }

    public void setNumberType(NumberType numberType) {
        numberTypeProperty().set(numberType);
    }

    private ObjectProperty _decimalFormatProperty;

    public ObjectProperty decimalFormatProperty() {
        if (_decimalFormatProperty == null) {
            _decimalFormatProperty = new SimpleObjectProperty(this, "decimalFormat") { //NON-NLS
                @Override
                protected void invalidated() {
                    super.invalidated();
                    initializePatternVerifiersForDecimalFormat(get());
                    setStringConverter(null);
                }
            };
        }
        return _decimalFormatProperty;
    }

    /**
     * Gets the DecimalFormat.
     *
     * @return the DecimalFormat.
     */
    public DecimalFormat getDecimalFormat() {
        return decimalFormatProperty().get();
    }

    /**
     * Sets the DecimalFormat that will format the value. We currently only support DateFormat and DecimalFormat.
     * Because the way the FormattedTextField works, we will automatically call the following line for any
     * DecimalFormats.
     * 
{@code
     * DecimalFormat format = ...
     * ..
     * format.setMinimumFractionDigits(format.getMaximumFractionDigits());
     * }
* * @param format the new DecimalFormat. */ public void setDecimalFormat(DecimalFormat format) { decimalFormatProperty().set(format); } public BooleanProperty positiveOnlyProperty() { if (_positiveOnlyProperty == null) { _positiveOnlyProperty = new SimpleBooleanProperty(this, "positiveOnly") { //NON-NLS @Override protected void invalidated() { super.invalidated(); initializePatternVerifiersForDecimalFormat(getDecimalFormat()); } }; } return _positiveOnlyProperty; } /** * Gets the flag to allow only positive values in the field. * * @return true or false. */ public boolean isPositiveOnly() { return positiveOnlyProperty().get(); } /** * Sets the flag to allow only positive values in the field. * * @param positiveOnly true to allow only possible values. False to allow both negative and positive values. */ public void setPositiveOnly(boolean positiveOnly) { positiveOnlyProperty().set(positiveOnly); } @Override protected String toString(Number value) { DecimalFormat format = getDecimalFormat(); if (format != null) { try { return format.format(value); } catch (Exception e) { CommonUtils.ignoreException(e); } } return super.toString(value); } @Override protected Number fromString(String text) { DecimalFormat format = getDecimalFormat(); if (format != null) { try { return format.parse(text); } catch (ParseException e) { CommonUtils.ignoreException(e); } } return super.fromString(text); } @Override protected boolean supportFromString() { return getDecimalFormat() != null || super.supportFromString(); } protected void initializePatternVerifiersForDecimalFormat(DecimalFormat decimalFormat) { int multiplier = decimalFormat.getMultiplier(); String text = decimalFormat.format((getValue() != null && getValue().doubleValue() < 0 ? -1.2 : 1.2) / (double) multiplier); text = text.replace("0", "").replace('2', 'f').replace('1', 'n'); final int integerDigits = decimalFormat.getMaximumIntegerDigits(); if (integerDigits >= 1) { IntegerDigitsPatternVerifier patternVerifier = new IntegerDigitsPatternVerifier( isPositiveOnly() ? 0 : -(int) Math.pow(10, integerDigits) + 1, (int) Math.pow(10, integerDigits) - 1, 1, multiplier) { @Override public Number toTargetValue(Number fieldValue) { return fieldValue; } @Override public Number fromTargetValue(Number previousFieldValue, Number targetValue) { return targetValue; } }; patternVerifier.setStringConverter(new StringConverter() { private NumberFormat getIntegerFormat(NumberFormat format) { NumberFormat instance = NumberFormat.getInstance(); instance.setMaximumIntegerDigits(format.getMaximumIntegerDigits()); instance.setMinimumIntegerDigits(format.getMinimumIntegerDigits()); instance.setMaximumFractionDigits(0); instance.setGroupingUsed(format.isGroupingUsed()); instance.setParseIntegerOnly(true); return instance; } @Override public String toString(Number object) { return getIntegerFormat(decimalFormat).format(object); } @Override public Number fromString(String string) { try { return getIntegerFormat(decimalFormat).parse(string); } catch (ParseException e) { CommonUtils.ignoreException(e); } return Integer.parseInt(string); } }); getPatternVerifiers().put("n", patternVerifier); //NON-NLS } if (decimalFormat.getMaximumFractionDigits() >= 1) { getPatternVerifiers().put("f", new FractionDigitsPatternVerifier(decimalFormat.getMaximumFractionDigits(), multiplier) { @Override public Number toTargetValue(Number fieldValue) { return fieldValue; } @Override public Number fromTargetValue(Number previousFieldValue, Number targetValue) { return targetValue; } }); // we have to enforce the MinimumFractionDigits because the way group works decimalFormat.setMinimumFractionDigits(decimalFormat.getMaximumFractionDigits()); } setPattern(text); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy