001/**
002 * 
003 */
004package icy.gui.component.editor;
005
006import icy.gui.component.SpecialValueSpinner;
007import icy.gui.component.model.SpecialValueSpinnerModel;
008
009import java.text.DecimalFormat;
010import java.text.NumberFormat;
011import java.text.ParseException;
012
013import javax.swing.JFormattedTextField;
014import javax.swing.JSpinner.DefaultEditor;
015import javax.swing.SwingConstants;
016import javax.swing.text.DefaultFormatterFactory;
017import javax.swing.text.NumberFormatter;
018
019/**
020 * @author Stephane
021 */
022public class SpecialValueSpinnerEditor extends DefaultEditor
023{
024    /**
025     * 
026     */
027    private static final long serialVersionUID = -2378027484728815432L;
028
029    private static class NumberEditorFormatter extends NumberFormatter
030    {
031        /**
032         * 
033         */
034        private static final long serialVersionUID = 723313251195326099L;
035
036        private final SpecialValueSpinnerModel model;
037
038        NumberEditorFormatter(SpecialValueSpinnerModel model, NumberFormat format)
039        {
040            super(format);
041            this.model = model;
042            setValueClass(model.getValue().getClass());
043        }
044
045        @Override
046        public void setMinimum(Comparable min)
047        {
048            model.setMinimum(min);
049        }
050
051        @Override
052        public Comparable getMinimum()
053        {
054            return model.getMinimum();
055        }
056
057        @Override
058        public void setMaximum(Comparable max)
059        {
060            model.setMaximum(max);
061        }
062
063        @Override
064        public Comparable getMaximum()
065        {
066            return model.getMaximum();
067        }
068
069        @Override
070        public Object stringToValue(String text) throws ParseException
071        {
072            if ((text != null) && text.equalsIgnoreCase(model.getSpecialText()))
073                return model.getSpecialValue();
074
075            return super.stringToValue(text);
076        }
077
078        @Override
079        public String valueToString(Object value) throws ParseException
080        {
081            if ((value != null) && value.equals(model.getSpecialValue()))
082                return model.getSpecialText();
083
084            return super.valueToString(value);
085        }
086    }
087
088    public SpecialValueSpinnerEditor(SpecialValueSpinner spinner)
089    {
090        this(spinner, (DecimalFormat) NumberFormat.getInstance(spinner.getLocale()));
091    }
092
093    public SpecialValueSpinnerEditor(SpecialValueSpinner spinner, String decimalFormatPattern)
094    {
095        this(spinner, new DecimalFormat(decimalFormatPattern));
096    }
097
098    private SpecialValueSpinnerEditor(SpecialValueSpinner spinner, DecimalFormat format)
099    {
100        super(spinner);
101
102        if (!(spinner.getModel() instanceof SpecialValueSpinnerModel))
103            throw new IllegalArgumentException("model not a SpecialValueSpinnerModel");
104
105        SpecialValueSpinnerModel model = (SpecialValueSpinnerModel) spinner.getModel();
106        NumberFormatter formatter = new NumberEditorFormatter(model, format);
107        DefaultFormatterFactory factory = new DefaultFormatterFactory(formatter);
108        JFormattedTextField ftf = getTextField();
109        ftf.setEditable(true);
110        ftf.setFormatterFactory(factory);
111        ftf.setHorizontalAlignment(SwingConstants.RIGHT);
112
113        /*
114         * TBD - initializing the column width of the text field
115         * is imprecise and doing it here is tricky because
116         * the developer may configure the formatter later.
117         */
118        try
119        {
120            String maxString = formatter.valueToString(model.getMinimum());
121            String minString = formatter.valueToString(model.getMaximum());
122            ftf.setColumns(Math.max(maxString.length(), minString.length()));
123        }
124        catch (ParseException e)
125        {
126            // TBD should throw a chained error here
127        }
128
129    }
130
131    public DecimalFormat getFormat()
132    {
133        return (DecimalFormat) ((NumberFormatter) (getTextField().getFormatter())).getFormat();
134    }
135
136    public SpecialValueSpinnerModel getModel()
137    {
138        return (SpecialValueSpinnerModel) (getSpinner().getModel());
139    }
140}