001/*
002 * Copyright 2010-2015 Institut Pasteur.
003 * 
004 * This file is part of Icy.
005 * 
006 * Icy is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 * 
011 * Icy is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 * GNU General Public License for more details.
015 * 
016 * You should have received a copy of the GNU General Public License
017 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
018 */
019package icy.gui.component;
020
021import java.awt.Color;
022import java.util.ArrayList;
023import java.util.List;
024
025/**
026 * Component to display and modify a numeric (double) value
027 * 
028 * @author Yoann Le Montagner & Stephane
029 */
030public class NumberTextField extends IcyTextField
031{
032    /**
033     * 
034     */
035    private static final long serialVersionUID = 3043750422009529874L;
036
037    /**
038     * Listener interface
039     */
040    public static interface ValueChangeListener
041    {
042        /**
043         * Method triggered when the numeric value in the component changes
044         */
045        public void valueChanged(double newValue, boolean validate);
046    }
047
048    protected double value;
049    protected boolean integer;
050    protected List<ValueChangeListener> listeners;
051
052    /**
053     * Constructor
054     */
055    public NumberTextField(boolean integer)
056    {
057        super();
058
059        value = 0;
060        this.integer = integer;
061        listeners = new ArrayList<ValueChangeListener>();
062    }
063
064    /**
065     * Constructor
066     */
067    public NumberTextField()
068    {
069        this(false);
070    }
071
072    /**
073     * Return true if the range use integer number
074     */
075    public boolean isInteger()
076    {
077        return integer;
078    }
079
080    /**
081     * Return true if the range use integer number
082     */
083    public void setInteger(boolean integer)
084    {
085        this.integer = integer;
086
087        // force value adjustment
088        setNumericValue(value);
089    }
090
091    /**
092     * Add a new listener
093     */
094    public void addValueListener(ValueChangeListener l)
095    {
096        listeners.add(l);
097    }
098
099    /**
100     * Remove a listener
101     */
102    public void removeValueListener(ValueChangeListener l)
103    {
104        listeners.remove(l);
105    }
106
107    /**
108     * Retrieve the value as a double
109     */
110    public double getNumericValue()
111    {
112        return value;
113    }
114
115    /**
116     * Set the value
117     */
118    public void setNumericValue(double value)
119    {
120        if (integer)
121            setText(Integer.toString((int) value));
122        else
123            setText(Double.toString(value));
124    }
125
126    protected void valueChanged(boolean validate)
127    {
128        fireValueChangedEvent(validate);
129    }
130
131    @Override
132    protected void textChanged(boolean validate)
133    {
134        super.textChanged(validate);
135
136        double oldValue = value;
137
138        try
139        {
140            final String text = getText();
141            value = text.isEmpty() ? 0.0 : Double.parseDouble(text);
142            // force integer
143            if (integer)
144                value = (int) value;
145            setForeground(Color.BLACK);
146        }
147        catch (NumberFormatException err)
148        {
149            setForeground(Color.RED);
150        }
151
152        if (validate)
153            valueChanged(validate);
154        else if (value != oldValue)
155            valueChanged(false);
156    }
157
158    /**
159     * Fire the value changed event
160     */
161    private void fireValueChangedEvent(boolean validate)
162    {
163        for (ValueChangeListener l : listeners)
164            l.valueChanged(value, validate);
165    }
166}