KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > SpinnerNumberModel


1 /*
2  * @(#)SpinnerNumberModel.java 1.12 04/05/12
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing;
9
10 import java.util.*;
11 import java.io.Serializable JavaDoc;
12
13
14 /**
15  * A <code>SpinnerModel</code> for sequences of numbers.
16  * The upper and lower bounds of the sequence are defined
17  * by properties called <code>minimum</code> and
18  * <code>maximum</code>. The size of the increase or decrease
19  * computed by the <code>nextValue</code> and
20  * <code>previousValue</code> methods is defined by a property called
21  * <code>stepSize</code>. The <code>minimum</code> and
22  * <code>maximum</code> properties can be <code>null</code>
23  * to indicate that the sequence has no lower or upper limit.
24  * All of the properties in this class are defined in terms of two
25  * generic types: <code>Number</code> and
26  * <code>Comparable</code>, so that all Java numeric types
27  * may be accommodated. Internally, there's only support for
28  * values whose type is one of the primitive <code>Number</code> types:
29  * <code>Double</code>, <code>Float</code>, <code>Long</code>,
30  * <code>Integer</code>, <code>Short</code>, or <code>Byte</code>.
31  * <p>
32  * To create a <code>SpinnerNumberModel</code> for the integer
33  * range zero to one hundred, with
34  * fifty as the initial value, one could write:
35  * <pre>
36  * Integer value = new Integer(50);
37  * Integer min = new Integer(0);
38  * Integer max = new Integer(100);
39  * Integer step = new Integer(1);
40  * SpinnerNumberModel model = new SpinnerNumberModel(value, min, max, step);
41  * int fifty = model.getNumber().intValue();
42  * </pre>
43  * <p>
44  * Spinners for integers and doubles are common, so special constructors
45  * for these cases are provided. For example to create the model in
46  * the previous example, one could also write:
47  * <pre>
48  * SpinnerNumberModel model = new SpinnerNumberModel(50, 0, 100, 1);
49  * </pre>
50  * <p>
51  * This model inherits a <code>ChangeListener</code>.
52  * The <code>ChangeListeners</code> are notified
53  * whenever the model's <code>value</code>, <code>stepSize</code>,
54  * <code>minimum</code>, or <code>maximum</code> properties changes.
55  *
56  * @see JSpinner
57  * @see SpinnerModel
58  * @see AbstractSpinnerModel
59  * @see SpinnerListModel
60  * @see SpinnerDateModel
61  *
62  * @version 1.12 05/12/04
63  * @author Hans Muller
64  * @since 1.4
65 */

66 public class SpinnerNumberModel extends AbstractSpinnerModel JavaDoc implements Serializable JavaDoc
67 {
68     private Number JavaDoc stepSize, value;
69     private Comparable JavaDoc minimum, maximum;
70
71
72     /**
73      * Constructs a <code>SpinnerModel</code> that represents
74      * a closed sequence of
75      * numbers from <code>minimum</code> to <code>maximum</code>. The
76      * <code>nextValue</code> and <code>previousValue</code> methods
77      * compute elements of the sequence by adding or subtracting
78      * <code>stepSize</code> respectively. All of the parameters
79      * must be mutually <code>Comparable</code>, <code>value</code>
80      * and <code>stepSize</code> must be instances of <code>Integer</code>
81      * <code>Long</code>, <code>Float</code>, or <code>Double</code>.
82      * <p>
83      * The <code>minimum</code> and <code>maximum</code> parameters
84      * can be <code>null</code> to indicate that the range doesn't
85      * have an upper or lower bound.
86      * If <code>value</code> or <code>stepSize</code> is <code>null</code>,
87      * or if both <code>minimum</code> and <code>maximum</code>
88      * are specified and <code>mininum &gt; maximum</code> then an
89      * <code>IllegalArgumentException</code> is thrown.
90      * Similarly if <code>(minimum &lt;= value &lt;= maximum</code>) is false,
91      * an <code>IllegalArgumentException</code> is thrown.
92      *
93      * @param value the current (non <code>null</code>) value of the model
94      * @param minimum the first number in the sequence or <code>null</code>
95      * @param maximum the last number in the sequence or <code>null</code>
96      * @param stepSize the difference between elements of the sequence
97      *
98      * @throws IllegalArgumentException if stepSize or value is
99      * <code>null</code> or if the following expression is false:
100      * <code>minimum &lt;= value &lt;= maximum</code>
101      */

102     public SpinnerNumberModel(Number JavaDoc value, Comparable JavaDoc minimum, Comparable JavaDoc maximum, Number JavaDoc stepSize) {
103     if ((value == null) || (stepSize == null)) {
104         throw new IllegalArgumentException JavaDoc("value and stepSize must be non-null");
105     }
106     if (!(((minimum == null) || (minimum.compareTo(value) <= 0)) &&
107           ((maximum == null) || (maximum.compareTo(value) >= 0)))) {
108         throw new IllegalArgumentException JavaDoc("(minimum <= value <= maximum) is false");
109     }
110     this.value = value;
111     this.minimum = minimum;
112     this.maximum = maximum;
113     this.stepSize = stepSize;
114     }
115
116
117     /**
118      * Constructs a <code>SpinnerNumberModel</code> with the specified
119      * <code>value</code>, <code>minimum</code>/<code>maximum</code> bounds,
120      * and <code>stepSize</code>.
121      *
122      * @param value the current value of the model
123      * @param minimum the first number in the sequence
124      * @param maximum the last number in the sequence
125      * @param stepSize the difference between elements of the sequence
126      * @throws IllegalArgumentException if the following expression is false:
127      * <code>minimum &lt;= value &lt;= maximum</code>
128      */

129     public SpinnerNumberModel(int value, int minimum, int maximum, int stepSize) {
130     this(new Integer JavaDoc(value), new Integer JavaDoc(minimum), new Integer JavaDoc(maximum), new Integer JavaDoc(stepSize));
131     }
132
133
134     /**
135      * Constructs a <code>SpinnerNumberModel</code> with the specified
136      * <code>value</code>, <code>minimum</code>/<code>maximum</code> bounds,
137      * and <code>stepSize</code>.
138      *
139      * @param value the current value of the model
140      * @param minimum the first number in the sequence
141      * @param maximum the last number in the sequence
142      * @param stepSize the difference between elements of the sequence
143      * @throws IllegalArgumentException if the following expression is false:
144      * <code>minimum &lt;= value &lt;= maximum</code>
145      */

146     public SpinnerNumberModel(double value, double minimum, double maximum, double stepSize) {
147     this(new Double JavaDoc(value), new Double JavaDoc(minimum), new Double JavaDoc(maximum), new Double JavaDoc(stepSize));
148     }
149
150
151     /**
152      * Constructs a <code>SpinnerNumberModel</code> with no
153      * <code>minimum</code> or <code>maximum</code> value,
154      * <code>stepSize</code> equal to one, and an initial value of zero.
155      */

156     public SpinnerNumberModel() {
157     this(new Integer JavaDoc(0), null, null, new Integer JavaDoc(1));
158     }
159
160
161     /**
162      * Changes the lower bound for numbers in this sequence.
163      * If <code>minimum</code> is <code>null</code>,
164      * then there is no lower bound. No bounds checking is done here;
165      * the new <code>minimum</code> value may invalidate the
166      * <code>(minimum &lt;= value &lt= maximum)</code>
167      * invariant enforced by the constructors. This is to simplify updating
168      * the model, naturally one should ensure that the invariant is true
169      * before calling the <code>getNextValue</code>,
170      * <code>getPreviousValue</code>, or <code>setValue</code> methods.
171      * <p>
172      * Typically this property is a <code>Number</code> of the same type
173      * as the <code>value</code> however it's possible to use any
174      * <code>Comparable</code> with a <code>compareTo</code>
175      * method for a <code>Number</code> with the same type as the value.
176      * For example if value was a <code>Long</code>,
177      * <code>minimum</code> might be a Date subclass defined like this:
178      * <pre>
179      * MyDate extends Date { // Date already implements Comparable
180      * public int compareTo(Long o) {
181      * long t = getTime();
182      * return (t < o.longValue() ? -1 : (t == o.longValue() ? 0 : 1));
183      * }
184      * }
185      * </pre>
186      * <p>
187      * This method fires a <code>ChangeEvent</code>
188      * if the <code>minimum</code> has changed.
189      *
190      * @param minimum a <code>Comparable</code> that has a
191      * <code>compareTo</code> method for <code>Number</code>s with
192      * the same type as <code>value</code>
193      * @see #getMinimum
194      * @see #setMaximum
195      * @see SpinnerModel#addChangeListener
196      */

197     public void setMinimum(Comparable JavaDoc minimum) {
198     if ((minimum == null) ? (this.minimum != null) : !minimum.equals(this.minimum)) {
199         this.minimum = minimum;
200         fireStateChanged();
201     }
202     }
203
204
205     /**
206      * Returns the first number in this sequence.
207      *
208      * @return the value of the <code>minimum</code> property
209      * @see #setMinimum
210      */

211     public Comparable JavaDoc getMinimum() {
212     return minimum;
213     }
214
215
216     /**
217      * Changes the upper bound for numbers in this sequence.
218      * If <code>maximum</code> is <code>null</code>, then there
219      * is no upper bound. No bounds checking is done here; the new
220      * <code>maximum</code> value may invalidate the
221      * <code>(minimum <= value < maximum)</code>
222      * invariant enforced by the constructors. This is to simplify updating
223      * the model, naturally one should ensure that the invariant is true
224      * before calling the <code>next</code>, <code>previous</code>,
225      * or <code>setValue</code> methods.
226      * <p>
227      * Typically this property is a <code>Number</code> of the same type
228      * as the <code>value</code> however it's possible to use any
229      * <code>Comparable</code> with a <code>compareTo</code>
230      * method for a <code>Number</code> with the same type as the value.
231      * See <a HREF="#setMinimum(java.lang.Comparable)">
232      * <code>setMinimum</code></a> for an example.
233      * <p>
234      * This method fires a <code>ChangeEvent</code> if the
235      * <code>maximum</code> has changed.
236      *
237      * @param maximum a <code>Comparable</code> that has a
238      * <code>compareTo</code> method for <code>Number</code>s with
239      * the same type as <code>value</code>
240      * @see #getMaximum
241      * @see #setMinimum
242      * @see SpinnerModel#addChangeListener
243      */

244     public void setMaximum(Comparable JavaDoc maximum) {
245     if ((maximum == null) ? (this.maximum != null) : !maximum.equals(this.maximum)) {
246         this.maximum = maximum;
247         fireStateChanged();
248     }
249     }
250
251
252     /**
253      * Returns the last number in the sequence.
254      *
255      * @return the value of the <code>maximum</code> property
256      * @see #setMaximum
257      */

258     public Comparable JavaDoc getMaximum() {
259     return maximum;
260     }
261
262
263     /**
264      * Changes the size of the value change computed by the
265      * <code>getNextValue</code> and <code>getPreviousValue</code>
266      * methods. An <code>IllegalArgumentException</code>
267      * is thrown if <code>stepSize</code> is <code>null</code>.
268      * <p>
269      * This method fires a <code>ChangeEvent</code> if the
270      * <code>stepSize</code> has changed.
271      *
272      * @param stepSize the size of the value change computed by the
273      * <code>getNextValue</code> and <code>getPreviousValue</code> methods
274      * @see #getNextValue
275      * @see #getPreviousValue
276      * @see #getStepSize
277      * @see SpinnerModel#addChangeListener
278      */

279     public void setStepSize(Number JavaDoc stepSize) {
280     if (stepSize == null) {
281         throw new IllegalArgumentException JavaDoc("null stepSize");
282     }
283     if (!stepSize.equals(this.stepSize)) {
284         this.stepSize = stepSize;
285         fireStateChanged();
286     }
287     }
288
289
290     /**
291      * Returns the size of the value change computed by the
292      * <code>getNextValue</code>
293      * and <code>getPreviousValue</code> methods.
294      *
295      * @return the value of the <code>stepSize</code> property
296      * @see #setStepSize
297      */

298     public Number JavaDoc getStepSize() {
299     return stepSize;
300     }
301
302
303     private Number JavaDoc incrValue(int dir)
304     {
305     Number JavaDoc newValue;
306     if ((value instanceof Float JavaDoc) || (value instanceof Double JavaDoc)) {
307         double v = value.doubleValue() + (stepSize.doubleValue() * (double)dir);
308         if (value instanceof Double JavaDoc) {
309         newValue = new Double JavaDoc(v);
310         }
311         else {
312         newValue = new Float JavaDoc(v);
313         }
314     }
315     else {
316         long v = value.longValue() + (stepSize.longValue() * (long)dir);
317
318         if (value instanceof Long JavaDoc) {
319         newValue = new Long JavaDoc(v);
320         }
321         else if (value instanceof Integer JavaDoc) {
322         newValue = new Integer JavaDoc((int)v);
323         }
324         else if (value instanceof Short JavaDoc) {
325         newValue = new Short JavaDoc((short)v);
326         }
327         else {
328         newValue = new Byte JavaDoc((byte)v);
329         }
330     }
331
332     if ((maximum != null) && (maximum.compareTo(newValue) < 0)) {
333         return null;
334     }
335     if ((minimum != null) && (minimum.compareTo(newValue) > 0)) {
336         return null;
337     }
338     else {
339         return newValue;
340     }
341     }
342
343
344     /**
345      * Returns the next number in the sequence.
346      *
347      * @return <code>value + stepSize</code> or <code>null</code> if the sum
348      * exceeds <code>maximum</code>.
349      *
350      * @see SpinnerModel#getNextValue
351      * @see #getPreviousValue
352      * @see #setStepSize
353      */

354     public Object JavaDoc getNextValue() {
355     return incrValue(+1);
356     }
357
358
359     /**
360      * Returns the previous number in the sequence.
361      *
362      * @return <code>value - stepSize</code>, or
363      * <code>null</code> if the sum is less
364      * than <code>minimum</code>.
365      *
366      * @see SpinnerModel#getPreviousValue
367      * @see #getNextValue
368      * @see #setStepSize
369      */

370     public Object JavaDoc getPreviousValue() {
371     return incrValue(-1);
372     }
373
374
375     /**
376      * Returns the value of the current element of the sequence.
377      *
378      * @return the value property
379      * @see #setValue
380      */

381     public Number JavaDoc getNumber() {
382     return value;
383     }
384
385
386     /**
387      * Returns the value of the current element of the sequence.
388      *
389      * @return the value property
390      * @see #setValue
391      * @see #getNumber
392      */

393     public Object JavaDoc getValue() {
394     return value;
395     }
396
397
398     /**
399      * Sets the current value for this sequence. If <code>value</code> is
400      * <code>null</code>, or not a <code>Number</code>, an
401      * <code>IllegalArgumentException</code> is thrown. No
402      * bounds checking is done here; the new value may invalidate the
403      * <code>(minimum &lt;= value &lt;= maximum)</code>
404      * invariant enforced by the constructors. It's also possible to set
405      * the value to be something that wouldn't naturally occur in the sequence,
406      * i.e. a value that's not modulo the <code>stepSize</code>.
407      * This is to simplify updating the model, and to accommodate
408      * spinners that don't want to restrict values that have been
409      * directly entered by the user. Naturally, one should ensure that the
410      * <code>(minimum &lt;= value &lt;= maximum)</code> invariant is true
411      * before calling the <code>next</code>, <code>previous</code>, or
412      * <code>setValue</code> methods.
413      * <p>
414      * This method fires a <code>ChangeEvent</code> if the value has changed.
415      *
416      * @param value the current (non <code>null</code>) <code>Number</code>
417      * for this sequence
418      * @throws IllegalArgumentException if <code>value</code> is
419      * <code>null</code> or not a <code>Number</code>
420      * @see #getNumber
421      * @see #getValue
422      * @see SpinnerModel#addChangeListener
423      */

424     public void setValue(Object JavaDoc value) {
425     if ((value == null) || !(value instanceof Number JavaDoc)) {
426         throw new IllegalArgumentException JavaDoc("illegal value");
427     }
428     if (!value.equals(this.value)) {
429         this.value = (Number JavaDoc)value;
430         fireStateChanged();
431     }
432     }
433 }
434
435
Popular Tags