1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.wotonomy.ui.swing.components;
20
21 /***
22 * NumericTextField is a "smart" text field that restricts the user's input. The
23 * input is restructed to numeric only wich can be of two types: integer and real
24 * numbers. A range can also be placed on the text field. The default type is
25 * integer, with the being (Integer.MIN_VALUE, Integer.MAX_VALUE).
26 *
27 * @author rob@straylight.princeton.com
28 * @author $Author: cgruber $
29 * @version $Revision: 893 $
30 */
31 public class NumericTextField extends SmartTextField
32 {
33
34 /********************************
35 * CONSTANTS
36 *******************************/
37
38 /***
39 * Restrict the text input to integers (whole numbers) only.
40 */
41 public final static int INTEGER = 0;
42
43 /***
44 * Restrict the text input to floating-point numbers only.
45 */
46 public final static int FLOAT = 1;
47
48 private Number maximumValue = null;
49 private Number minimumValue = null;
50
51 private boolean sign = false;
52 private int newCaretPosition = 0;
53 private int valueType = INTEGER;
54
55
56 /********************************
57 * PUBLIC METHODS
58 *******************************/
59
60 /***
61 * Default constructor.
62 */
63 public NumericTextField()
64 {
65 this("", 0);
66 }
67
68 /***
69 * Constructor.
70 * @param text The initial string the text field is set to.
71 */
72 public NumericTextField(String text)
73 {
74 this(text, 0);
75 }
76
77 /***
78 * Constructor.
79 * @param columns Width of the text field (in characters).
80 */
81 public NumericTextField(int columns)
82 {
83 this("", columns);
84 }
85
86 /***
87 * Constructor.
88 * @param text The initial string the text field is set to.
89 * @param columns Width of the text field (in characters).
90 */
91 public NumericTextField(String text, int columns)
92 {
93 super(text, columns);
94 }
95
96 /***
97 * Sets the upper limit of the range of numbers to accept.
98 * @param newMaximumValue The maximum number accepted by the text field.
99 */
100 public void setMaximumValue(double newMaximumValue)
101 {
102 if (newMaximumValue >= 0)
103 {
104 maximumValue = new Double( newMaximumValue );
105 }
106 else
107 {
108 maximumValue = null;
109 }
110 }
111
112 /***
113 * Returns the upper limit of the range of numbers to accept.
114 * @return The maximum number accepted by this text field.
115 */
116 public double getMaximumValue()
117 {
118 if ( valueType == INTEGER )
119 {
120 return (maximumValue == null) ? (double) Integer.MAX_VALUE : maximumValue.doubleValue();
121 }
122 else
123 {
124 return (maximumValue == null) ? Double.MAX_VALUE : maximumValue.doubleValue();
125 }
126 }
127
128 /***
129 * Sets the lower limit of the range of numbers to accept.
130 * @param newMinimumValue The minimum number accepted by the text field.
131 */
132 public void setMinimumValue(double newMinimumValue)
133 {
134 if (newMinimumValue <= 0)
135 {
136 minimumValue = new Double( newMinimumValue );
137 }
138 else
139 {
140 minimumValue = null;
141 }
142 }
143
144 /***
145 * Returns the lower limit of the range of numbers to accept.
146 * @return The minimum number accepted by this text field.
147 */
148 public double getMinimumValue()
149 {
150 if ( valueType == INTEGER )
151 {
152 return (minimumValue == null) ? (double) Integer.MIN_VALUE : minimumValue.doubleValue();
153 }
154 else
155 {
156 return (minimumValue == null) ? -1.0*Double.MAX_VALUE : minimumValue.doubleValue();
157
158 }
159 }
160
161 /***
162 * Sets which type of number this text field can accept.
163 * @see #INTEGER
164 * @see #FLOAT
165 * @param newValueType The type of number to accept.
166 */
167 public void setValueType(int newValueType)
168 {
169 if ((newValueType != INTEGER) && (newValueType != FLOAT))
170 {
171 valueType = INTEGER;
172 }
173 else
174 {
175 valueType = newValueType;
176 }
177 }
178
179 /***
180 * Returns which type of number this text field accepts. The default is
181 * integer.
182 * @see #INTEGER
183 * @see #FLOAT
184 * @return The type of number to accept.
185 */
186 public int getValueType()
187 {
188 return valueType;
189 }
190
191 /***
192 * Returns the integer numeric value of the string in the text field. The type
193 * can be either integer of float.
194 * @return The current value in the text field.
195 */
196 public int getIntValue()
197 {
198 int value = 0;
199
200 try
201 {
202 value = Integer.parseInt(getText());
203 }
204 catch (NumberFormatException e)
205 {
206 try
207 {
208 Double dValue = Double.valueOf(getText());
209 value = dValue.intValue();
210 }
211 catch (NumberFormatException ignored) {}
212 }
213
214 return value;
215 }
216
217 /***
218 * Sets the text field to integer value specified.
219 * @param aValue An integer value to display in the text field.
220 */
221 public void setIntValue(int aValue)
222 {
223 setText(Integer.toString(aValue));
224 }
225
226 /***
227 * Returns the real number numeric value of the string in the text field. The type
228 * can be either integer of float.
229 * @return The current value in the text field.
230 */
231 public double getDoubleValue()
232 {
233 Double value = new Double(0);
234
235 try
236 {
237 value = Double.valueOf(getText());
238 }
239 catch (NumberFormatException ignored) {}
240
241 return value.doubleValue();
242 }
243
244 /***
245 * Sets the text field to the double value specified. If the text field type is
246 * FLOAT then the the number is display as a real number. If the text field
247 * type is INTEGER then the number is converted to a whole number for displaying.
248 * @param aValue A double value to display in the text field.
249 */
250 public void setDoubleValue(double aValue)
251 {
252 Double temp = new Double(aValue);
253
254 if (valueType == FLOAT)
255 {
256 setText(temp.toString());
257 }
258 else
259 {
260 setText(Integer.toString(temp.intValue()));
261 }
262 }
263
264 /********************************
265 * PROTECTED METHODS
266 *******************************/
267
268 protected boolean isValidCharacter(char aChar)
269 {
270 if (((aChar >= ' ') && (aChar <= '/')) || ((aChar >= ':') && (aChar <= '~')))
271 {
272 if (aChar == '.')
273 {
274 if ( valueType == FLOAT )
275 {
276 return true;
277 }
278 else
279 {
280 return false;
281 }
282 }
283 else if (aChar == '-')
284 {
285 if ( getMinimumValue() < 0 )
286 {
287 return true;
288 }
289 else
290 {
291 return false;
292 }
293 }
294 else if (aChar == '+')
295 {
296 if ( getMaximumValue() >= 0 )
297 {
298 return true;
299 }
300 else
301 {
302 return false;
303 }
304 }
305 return false;
306 }
307 return true;
308 }
309
310 protected boolean isValidString(String aString)
311 {
312 int iValue = 0;
313 double dValue = 0.0;
314
315 String tempString = new String(scanForSignChar(aString));
316
317 if ( valueType == INTEGER )
318 {
319 try
320 {
321 iValue = Integer.parseInt(tempString);
322 }
323 catch (NumberFormatException e1)
324 {
325 if ((tempString.compareTo("-") == 0) && (getMinimumValue() < 0.0))
326 {
327 iValue = 0;
328 }
329 else
330 {
331 return false;
332 }
333 }
334 if ((((double)iValue) < getMinimumValue()) || (((double)iValue) > getMaximumValue()))
335 {
336 return false;
337 }
338 }
339 else
340 {
341
342 if ( tempString.startsWith( "." ) )
343 {
344 tempString = "0" + tempString;
345 }
346 try
347 {
348 dValue = Double.valueOf(tempString).doubleValue();
349 }
350 catch (NumberFormatException e2)
351 {
352 if ((tempString.compareTo("-") == 0) && (getMinimumValue() < 0.0))
353 {
354 dValue = 0.0;
355 }
356 else
357 {
358 return false;
359 }
360 }
361
362 if ((dValue < getMinimumValue()) || (dValue > getMaximumValue()))
363 {
364 return false;
365 }
366 }
367
368 return true;
369 }
370
371 protected void postProcessing()
372 {
373 if (sign)
374 {
375 setText(scanForSignChar(getText()));
376 setCaretPosition(newCaretPosition);
377 }
378 sign = false;
379 }
380
381
382 /********************************
383 * PRIVATE METHODS
384 *******************************/
385
386 private String scanForSignChar(String aString)
387 {
388 String newString = "";
389 boolean positive = false;
390 boolean negative = false;
391 int oldCaretPosition = getCaretPosition();
392 int charactersAdded = 0;
393
394 newCaretPosition = 0;
395
396 if (aString.length() <= 0)
397 {
398 return aString;
399 }
400
401 for (int i = 0; i < aString.length(); ++i)
402 {
403 switch (aString.charAt(i))
404 {
405 case '+': positive = true;
406 break;
407 case '-': negative = true;
408 break;
409 default: newString += aString.charAt(i);
410 charactersAdded++;
411 break;
412 }
413
414 if ((i + 1) == oldCaretPosition)
415 {
416 newCaretPosition = charactersAdded;
417 }
418 }
419
420 if ((!(positive)) && (negative))
421 {
422 newString = "-" + newString;
423 newCaretPosition++;
424 }
425
426 if (positive || negative)
427 {
428 sign = true;
429 }
430
431 return newString;
432 }
433 }
434