1 /* DefaultBoundedRangeModel.java -- Default implementation
2    of BoundedRangeModel.
3    Copyright (C) 2002, 2004 Free Software Foundation, Inc.
4 
5 This file is part of GNU Classpath.
6 
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11 
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING.  If not, write to the
19 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA.
21 
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26 
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38 
39 package javax.swing;
40 
41 import java.io.Serializable;
42 import java.util.EventListener;
43 import javax.swing.event.ChangeEvent;
44 import javax.swing.event.ChangeListener;
45 import javax.swing.event.EventListenerList;
46 
47 
48 /**
49  * A default implementation of BoundedRangeModel.
50  *
51  * @author <a href="mailto:aselkirk@sympatico.ca">Andrew Selkirk</a>
52  * @author <a href="mailto:brawer@dandelis.ch">Sascha Brawer</a>
53  */
54 public class DefaultBoundedRangeModel
55   implements BoundedRangeModel, Serializable
56 {
57   /**
58    * The identifier of this class in object serialization. Verified
59    * using the serialver tool of Sun J2SE 1.4.1_01.
60    */
61   static final long serialVersionUID = 5034068491295259790L;
62 
63 
64   /**
65    * An event that is sent to all registered {@link ChangeListener}s
66    * when the state of this range model has changed.
67    *
68    * <p>The event object is created on demand, the first time it
69    * is actually needed.
70    *
71    * @see #fireStateChanged()
72    */
73   protected transient ChangeEvent changeEvent;
74 
75 
76   /**
77    * The list of the currently registered EventListeners.
78    */
79   protected EventListenerList listenerList = new EventListenerList();
80 
81 
82   /**
83    * The current value of the range model, which is always between
84    * {@link #minimum} and ({@link #maximum} - {@link #extent}). In a
85    * scroll bar visualization of a {@link BoundedRangeModel}, the
86    * <code>value</code> is displayed as the position of the thumb.
87    */
88   private int value;
89 
90 
91   /**
92    * The current extent of the range model, which is a number greater
93    * than or equal to zero. In a scroll bar visualization of a {@link
94    * BoundedRangeModel}, the <code>extent</code> is displayed as the
95    * size of the thumb.
96    */
97   private int extent;
98 
99 
100   /**
101    * The current minimum value of the range model, which is always
102    * less than or equal to {@link #maximum}.
103    */
104   private int minimum;
105 
106 
107   /**
108    * The current maximum value of the range model, which is always
109    * greater than or equal to {@link #minimum}.
110    */
111   private int maximum;
112 
113 
114   /**
115    * A property that indicates whether the value of this {@link
116    * BoundedRangeModel} is going to change in the immediate future.
117    */
118   private boolean isAdjusting;
119 
120 
121   /**
122    * Constructs a <code>DefaultBoundedRangeModel</code> with default
123    * values for the properties. The properties <code>value</code>,
124    * <code>extent</code> and <code>minimum</code> will be initialized
125    * to zero; <code>maximum</code> will be set to 100; the property
126    * <code>valueIsAdjusting</code> will be <code>false</code>.
127    */
DefaultBoundedRangeModel()128   public DefaultBoundedRangeModel()
129   {
130     // The fields value, extent, minimum have the default value 0, and
131     // isAdjusting is already false. These fields no not need to be
132     // set explicitly.
133     maximum = 100;
134   }
135 
136 
137   /**
138    * Constructs a <code>DefaultBoundedRangeModel</code> with the
139    * specified values for some properties.
140    *
141    * @param value the initial value of the range model, which must be
142    * a number between <code>minimum</code> and <code>(maximum -
143    * extent)</code>. In a scroll bar visualization of a {@link
144    * BoundedRangeModel}, the <code>value</code> is displayed as the
145    * position of the thumb.
146    *
147    * @param extent the initial extent of the range model, which is a
148    * number greater than or equal to zero. In a scroll bar
149    * visualization of a {@link BoundedRangeModel}, the
150    * <code>extent</code> is displayed as the size of the thumb.
151    *
152    * @param minimum the initial minimal value of the range model.
153    *
154    * @param maximum the initial maximal value of the range model.
155    *
156    * @throws IllegalArgumentException if the following condition is
157    * not satisfied: <code>minimum <= value <= value + extent <=
158    * maximum</code>.
159    */
DefaultBoundedRangeModel(int value, int extent, int minimum, int maximum)160   public DefaultBoundedRangeModel(int value, int extent, int minimum,
161                                   int maximum)
162   {
163     if (!(minimum <= value && extent >= 0 && (value + extent) <= maximum))
164       throw new IllegalArgumentException();
165 
166     this.value = value;
167     this.extent = extent;
168     this.minimum = minimum;
169     this.maximum = maximum;
170 
171     // The isAdjusting field already has a false value by default.
172   }
173 
174 
175   /**
176    * Returns a string with all relevant properties of this range
177    * model.
178    */
toString()179   public String toString()
180   {
181     return getClass().getName()
182       + "[value=" + value
183       + ", extent=" + extent
184       + ", min=" + minimum
185       + ", max=" + maximum
186       + ", adj=" + isAdjusting
187       + ']';
188   }
189 
190 
191   /**
192    * Returns the current value of this bounded range model.  In a
193    * scroll bar visualization of a {@link BoundedRangeModel}, the
194    * <code>value</code> is displayed as the position of the thumb.
195    */
getValue()196   public int getValue()
197   {
198     return value;
199   }
200 
201 
202   /**
203    * Changes the current value of this bounded range model. In a
204    * scroll bar visualization of a {@link BoundedRangeModel}, the
205    * <code>value</code> is displayed as the position of the thumb;
206    * changing the <code>value</code> of a scroll bar&#x2019;s model
207    * thus moves the thumb to a different position.
208    */
setValue(int value)209   public void setValue(int value)
210   {
211     value = Math.max(minimum, value);
212     if (value + extent > maximum)
213       value = maximum - extent;
214 
215     if (value != this.value)
216       {
217         this.value = value;
218         fireStateChanged();
219       }
220   }
221 
222 
223   /**
224    * Returns the current extent of this bounded range model, which is
225    * a number greater than or equal to zero. In a scroll bar
226    * visualization of a {@link BoundedRangeModel}, the
227    * <code>extent</code> is displayed as the size of the thumb.
228    */
getExtent()229   public int getExtent()
230   {
231     return extent;
232   }
233 
234 
235   /**
236    * Changes the current extent of this bounded range model. In a
237    * scroll bar visualization of a {@link BoundedRangeModel}, the
238    * <code>extent</code> is displayed as the size of the thumb.
239    *
240    * @param extent the new extent of the range model, which is a
241    * number greater than or equal to zero.
242    */
setExtent(int extent)243   public void setExtent(int extent)
244   {
245     extent = Math.max(extent, 0);
246     if (value + extent > maximum)
247       extent = maximum - value;
248 
249     if (extent != this.extent)
250       {
251         this.extent = extent;
252         fireStateChanged();
253       }
254   }
255 
256 
257   /**
258    * Returns the current minimal value of this bounded range model.
259    */
getMinimum()260   public int getMinimum()
261   {
262     return minimum;
263   }
264 
265 
266   /**
267    * Changes the current minimal value of this bounded range model.
268    *
269    * @param minimum the new minimal value.
270    */
setMinimum(int minimum)271   public void setMinimum(int minimum)
272   {
273     int value, maximum;
274 
275     maximum = Math.max(minimum, this.maximum);
276     value = Math.max(minimum, this.value);
277 
278     setRangeProperties(value, extent, minimum, maximum, isAdjusting);
279   }
280 
281 
282   /**
283    * Returns the current maximal value of this bounded range model.
284    */
getMaximum()285   public int getMaximum()
286   {
287     return maximum;
288   }
289 
290 
291   /**
292    * Changes the current maximal value of this bounded range model.
293    *
294    * @param maximum the new maximal value.
295    */
setMaximum(int maximum)296   public void setMaximum(int maximum)
297   {
298     int value, extent, minimum;
299 
300     minimum = Math.min(this.minimum, maximum);
301     extent = Math.min(this.extent, maximum - minimum);
302     value = Math.min(this.value, maximum - extent);
303 
304     setRangeProperties(value, extent, minimum, maximum, isAdjusting);
305   }
306 
307 
308   /**
309    * Returns whether or not the value of this bounded range model is
310    * going to change in the immediate future. Scroll bars set this
311    * property to <code>true</code> while the thumb is being dragged
312    * around; when the mouse is relased, they set the property to
313    * <code>false</code> and post a final {@link ChangeEvent}.
314    *
315    * @returns <code>true</code> if the value will change soon again;
316    * <code>false</code> if the value will probably not change soon.
317    */
getValueIsAdjusting()318   public boolean getValueIsAdjusting()
319   {
320     return isAdjusting;
321   }
322 
323 
324   /**
325    * Specifies whether or not the value of this bounded range model is
326    * going to change in the immediate future. Scroll bars set this
327    * property to <code>true</code> while the thumb is being dragged
328    * around; when the mouse is relased, they set the property to
329    * <code>false</code>.
330    *
331    * @param isAdjusting <code>true</code> if the value will change
332    * soon again; <code>false</code> if the value will probably not
333    * change soon.
334    */
setValueIsAdjusting(boolean isAdjusting)335   public void setValueIsAdjusting(boolean isAdjusting)
336   {
337     if (isAdjusting == this.isAdjusting)
338       return;
339 
340     this.isAdjusting = isAdjusting;
341     fireStateChanged();
342   }
343 
344 
345   /**
346    * setRangeProperties
347    *
348    * @param value the new value of the range model.  In a scroll bar
349    * visualization of a {@link BoundedRangeModel}, the
350    * <code>value</code> is displayed as the position of the thumb.
351    *
352    * @param extent the new extent of the range model, which is a
353    * number greater than or equal to zero. In a scroll bar
354    * visualization of a {@link BoundedRangeModel}, the
355    * <code>extent</code> is displayed as the size of the thumb.
356    *
357    * @param minimum the new minimal value of the range model.
358    *
359    * @param maximum the new maximal value of the range model.
360 
361    * @param isAdjusting whether or not the value of this bounded range
362    * model is going to change in the immediate future. Scroll bars set
363    * this property to <code>true</code> while the thumb is being
364    * dragged around; when the mouse is relased, they set the property
365    * to <code>false</code>.
366    */
setRangeProperties(int value, int extent, int minimum, int maximum, boolean isAdjusting)367   public void setRangeProperties(int value, int extent, int minimum,
368                                  int maximum, boolean isAdjusting)
369   {
370     minimum = Math.min(Math.min(minimum, maximum), value);
371     maximum = Math.max(value, maximum);
372     if (extent + value > maximum)
373       extent = maximum - value;
374     extent = Math.max(0, extent);
375 
376     if ((value == this.value)
377         && (extent == this.extent)
378         && (minimum == this.minimum)
379         && (maximum == this.maximum)
380         && (isAdjusting == this.isAdjusting))
381       return;
382 
383     this.value = value;
384     this.extent = extent;
385     this.minimum = minimum;
386     this.maximum = maximum;
387     this.isAdjusting = isAdjusting;
388 
389     fireStateChanged();
390   }
391 
392 
393   /**
394    * Subscribes a ChangeListener to state changes.
395    *
396    * @param listener the listener to be subscribed.
397    */
addChangeListener(ChangeListener listener)398   public void addChangeListener(ChangeListener listener)
399   {
400     listenerList.add(ChangeListener.class, listener);
401   }
402 
403 
404   /**
405    * Cancels the subscription of a ChangeListener.
406    *
407    * @param listener the listener to be unsubscribed.
408    */
removeChangeListener(ChangeListener listener)409   public void removeChangeListener(ChangeListener listener)
410   {
411     listenerList.remove(ChangeListener.class, listener);
412   }
413 
414 
415   /**
416    * Sends a {@link ChangeEvent} to any registered {@link
417    * ChangeListener}s.
418    *
419    * @see #addChangeListener(ChangeListener)
420    * @see #removeChangeListener(ChangeListener)
421    */
fireStateChanged()422   protected void fireStateChanged()
423   {
424     Object[] listeners;
425 
426     listeners = listenerList.getListenerList();
427     for (int i = listeners.length - 2; i >= 0; i -= 2)
428       if (listeners[i] == ChangeListener.class)
429         {
430           if (changeEvent == null)
431             changeEvent = new ChangeEvent(this);
432           ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent);
433         }
434   }
435 
436 
437   /**
438    * Retrieves the current listeners of the specified class.
439    *
440    * @param c the class of listeners; usually {@link
441    * ChangeListener}<code>.class</code>.
442    *
443    * @return an array with the currently subscribed listeners, or
444    * an empty array if there are currently no listeners.
445    *
446    * @since 1.3
447    */
getListeners(Class listenerType)448   public EventListener[] getListeners(Class listenerType)
449   {
450     return listenerList.getListeners(listenerType);
451   }
452 
453 
454   /**
455    * Returns all <code>ChangeListeners</code> that are currently
456    * subscribed for changes to this
457    * <code>DefaultBoundedRangeModel</code>.
458    *
459    * @return an array with the currently subscribed listeners, or
460    * an empty array if there are currently no listeners.
461    *
462    * @since 1.4
463    */
getChangeListeners()464   public ChangeListener[] getChangeListeners()
465   {
466     return (ChangeListener[]) getListeners(ChangeListener.class);
467   }
468 }
469