View Javadoc

1   /*
2    * @(#) NumberEditor.java Apr 11, 2005
3    * 
4    * Copyright (c) 2003-2005 Delft University of Technology, Jaffalaan 5, 2628 BX
5    * Delft, the Netherlands. All rights reserved.
6    * 
7    * See for project information <a href="http://www.simulation.tudelft.nl/">
8    * www.simulation.tudelft.nl </a>.
9    * 
10   * The source code and binary code of this software are proprietary information
11   * of Delft University of Technology.
12   */
13  package org.gscg.common.gui.components.interactivespinner;
14  
15  import java.text.DecimalFormat;
16  import java.text.NumberFormat;
17  import java.text.ParseException;
18  
19  import javax.swing.JFormattedTextField;
20  import javax.swing.SwingConstants;
21  import javax.swing.text.DefaultFormatterFactory;
22  import javax.swing.text.NumberFormatter;
23  
24  
25  /***
26   * <p>
27   * (c) copyright 2005 <a href="http://www.simulation.tudelft.nl">Delft
28   * University of Technology </a>, the Netherlands. <br>
29   * See for project information <a
30   * href="http://www.simulation.tudelft.nl">www.simulation.tudelft.nl </a> <br>
31   * 
32   * Copyright (c) 2003-2005 Delft University of Technology, Jaffalaan 5, 2628 BX
33   * Delft, the Netherlands. All rights reserved.
34   * 
35   * See for project information <a href="http://www.simulation.tudelft.nl/">
36   * www.simulation.tudelft.nl </a>.
37   * 
38   * The source code and binary code of this software are proprietary information
39   * of Delft University of Technology.
40   * 
41   * @author <a
42   *         href="http://www.tbm.tudelft.nl/webstaf/stijnh/index.htm">Stijn-Pieter
43   *         van Houten </a>
44   * @version $Revision: 1.1 $ $Date: 2005/06/16 12:33:56 $
45   * @since 1.1.3
46   */
47  /***
48   * An editor for a <code>JSpinner</code> whose model is a
49   * <code>SpinnerNumberModel</code>. The value of the editor is displayed with
50   * a <code>JFormattedTextField</code> whose format is defined by a
51   * <code>NumberFormatter</code> instance whose <code>minimum</code> and
52   * <code>maximum</code> properties are mapped to the
53   * <code>SpinnerNumberModel</code>.
54   */
55  public class NumberEditor extends DefaultEditor
56  {
57  	/***
58  	 * Construct a <code>JSpinner</code> editor that supports displaying and
59  	 * editing the value of a <code>SpinnerNumberModel</code> with a
60  	 * <code>JFormattedTextField</code>.<code>This</code>
61  	 * <code>NumberEditor</code>
62  	 * becomes both a <code>ChangeListener</code> on the spinner and a
63  	 * <code>PropertyChangeListener</code> on the new
64  	 * <code>JFormattedTextField</code>.
65  	 * 
66  	 * @param spinner the spinner whose model <code>this</code> editor will
67  	 *        monitor
68  	 * 
69  	 * @see #getModel
70  	 * @see #getFormat
71  	 * @see SpinnerNumberModel
72  	 */
73  	public NumberEditor(final JInteractiveSpinner spinner)
74  	{
75  		this(spinner, new DecimalFormat());
76  	}
77  
78  	/***
79  	 * Construct a <code>JSpinner</code> editor that supports displaying and
80  	 * editing the value of a <code>SpinnerNumberModel</code> with a
81  	 * <code>JFormattedTextField</code>.<code>This</code>
82  	 * <code>NumberEditor</code>
83  	 * becomes both a <code>ChangeListener</code> on the spinner and a
84  	 * <code>PropertyChangeListener</code> on the new
85  	 * <code>JFormattedTextField</code>.
86  	 * 
87  	 * @param spinner the spinner whose model <code>this</code> editor will
88  	 *        monitor
89  	 * @param decimalFormatPattern the initial pattern for the
90  	 *        <code>DecimalFormat</code> object that's used to display and
91  	 *        parse the value of the text field.
92  	 * @see SpinnerNumberModel
93  	 * @see java.text.DecimalFormat
94  	 */
95  	public NumberEditor(final JInteractiveSpinner spinner,
96  			final String decimalFormatPattern)
97  	{
98  		this(spinner, new DecimalFormat(decimalFormatPattern));
99  	}
100 
101 
102 	/***
103 	 * Construct a <code>JSpinner</code> editor that supports displaying and
104 	 * editing the value of a <code>SpinnerNumberModel</code> with a
105 	 * <code>JFormattedTextField</code>.<code>This</code>
106 	 * <code>NumberEditor</code>
107 	 * becomes both a <code>ChangeListener</code> on the spinner and a
108 	 * <code>PropertyChangeListener</code> on the new
109 	 * <code>JFormattedTextField</code>.
110 	 * 
111 	 * @param spinner the spinner whose model <code>this</code> editor will
112 	 *        monitor
113 	 * @param format the initial pattern for the <code>DecimalFormat</code>
114 	 *        object that's used to display and parse the value of the text
115 	 *        field.
116 	 * @see java.text.DecimalFormat
117 	 */
118 	private NumberEditor(final JInteractiveSpinner spinner,
119 			final DecimalFormat format)
120 	{
121 		super(spinner);
122 		if (!(spinner.getModel() instanceof SpinnerNumberModel))
123 		{
124 			throw new IllegalArgumentException("model not a SpinnerNumberModel");
125 		}
126 
127 		SpinnerNumberModel model = (SpinnerNumberModel) spinner.getModel();
128 		NumberFormatter formatter = new NumberEditorFormatter(model, format);
129 		DefaultFormatterFactory factory = new DefaultFormatterFactory(formatter);
130 		JFormattedTextField ftf = getTextField();
131 		// ftf.setEditable(true);
132 		ftf.setFormatterFactory(factory);
133 		ftf.setHorizontalAlignment(SwingConstants.RIGHT);
134 
135 		/*
136 		 * TBD - initializing the column width of the text field is imprecise
137 		 * and doing it here is tricky because the developer may configure the
138 		 * formatter later.
139 		 */
140 		try
141 		{
142 			String maxString = formatter.valueToString(model.getMinimum());
143 			String minString = formatter.valueToString(model.getMaximum());
144 			ftf.setColumns(Math.max(maxString.length(), minString.length()));
145 		} catch (ParseException e)
146 		{
147 			// TBD should throw a chained error here
148 			e = null;
149 		}
150 
151 	}
152 
153 	/***
154 	 * Returns the <code>java.text.NumberFormat</code> object the
155 	 * <code>JFormattedTextField</code> uses to parse and format numbers.
156 	 * 
157 	 * @return the value of
158 	 *         <code>getTextField().getFormatter().getFormat()</code>.
159 	 * @see java.text.DecimalFormat
160 	 */
161 	public DecimalFormat getFormat()
162 	{
163 		return (DecimalFormat) ((NumberFormatter) (getTextField()
164 				.getFormatter())).getFormat();
165 	}
166 
167 
168 	/***
169 	 * Return our spinner ancestor's <code>SpinnerNumberModel</code>.
170 	 * 
171 	 * @return <code>getSpinner().getModel()</code>
172 	 */
173 	public SpinnerNumberModel getModel()
174 	{
175 		return (SpinnerNumberModel) (getSpinner().getModel());
176 	}
177 
178 	/***
179 	 * This subclass of javax.swing.NumberFormatter maps the minimum/maximum
180 	 * properties to a SpinnerNumberModel and initializes the valueClass of the
181 	 * NumberFormatter to match the type of the initial models value.
182 	 */
183 	private static class NumberEditorFormatter extends NumberFormatter
184 	{
185 		/*** the model */
186 		private final SpinnerNumberModel model;
187 
188 		/***
189 
190 		 * constructs a new NumberEditorFormatter
191 		 * 
192 		 * @param model the model
193 		 * @param format the format
194 		 */
195 		public NumberEditorFormatter(final SpinnerNumberModel model,
196 				final NumberFormat format)
197 		{
198 			super(format);
199 			this.model = model;
200 			setValueClass(model.getValue().getClass());
201 		}
202 
203 		/***
204 		 * @see javax.swing.text.InternationalFormatter#setMinimum(java.lang.Comparable)
205 		 */
206 		public void setMinimum(final Comparable min)
207 		{
208 			this.model.setMinimum(min);
209 		}
210 
211 		/***
212 		 * @see javax.swing.text.InternationalFormatter#getMinimum()
213 		 */
214 		public Comparable getMinimum()
215 		{
216 			return this.model.getMinimum();
217 		}
218 
219 		/***
220 		 * @see javax.swing.text.InternationalFormatter#setMaximum(java.lang.Comparable)
221 		 */
222 		public void setMaximum(final Comparable max)
223 		{
224 			this.model.setMaximum(max);
225 		}
226 
227 		/***
228 		 * @see javax.swing.text.InternationalFormatter#getMaximum()
229 		 */
230 		public Comparable getMaximum()
231 		{
232 			return this.model.getMaximum();
233 		}
234 	}
235 }