1 /* DefaultBoundedRangeModel.java -- Default implementation 2 of BoundedRangeModel. 3 Copyright (C) 2002, 2004, 2005, 2006, 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., 51 Franklin Street, Fifth Floor, Boston, MA 20 02110-1301 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 40 package javax.swing; 41 42 import java.io.IOException; 43 import java.io.ObjectInputStream; 44 import java.io.ObjectOutputStream; 45 import java.io.Serializable; 46 import java.util.EventListener; 47 48 import javax.swing.event.ChangeEvent; 49 import javax.swing.event.ChangeListener; 50 import javax.swing.event.EventListenerList; 51 52 /** 53 * The default implementation of <code>BoundedRangeModel</code>. 54 * 55 * @author Andrew Selkirk (aselkirk@sympatico.ca) 56 * @author Sascha Brawer (brawer@dandelis.ch) 57 */ 58 public class DefaultBoundedRangeModel 59 implements BoundedRangeModel, Serializable 60 { 61 /** 62 * The identifier of this class in object serialization. Verified 63 * using the serialver tool of Sun J2SE 1.4.1_01. 64 */ 65 private static final long serialVersionUID = 5034068491295259790L; 66 67 /** 68 * An event that is sent to all registered {@link ChangeListener}s 69 * when the state of this range model has changed. 70 * 71 * <p>The event object is created on demand, the first time it 72 * is actually needed.</p> 73 * 74 * @see #fireStateChanged() 75 */ 76 protected transient ChangeEvent changeEvent; 77 78 /** 79 * The list of the currently registered EventListeners. 80 */ 81 protected EventListenerList listenerList = new EventListenerList(); 82 83 /** 84 * The current value of the range model, which is always between 85 * {@link #minimum} and ({@link #maximum} - {@link #extent}). In a 86 * scroll bar visualization of a {@link BoundedRangeModel}, the 87 * <code>value</code> is displayed as the position of the thumb. 88 */ 89 private int value; 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 * The current minimum value of the range model, which is always 101 * less than or equal to {@link #maximum}. 102 */ 103 private int minimum; 104 105 /** 106 * The current maximum value of the range model, which is always 107 * greater than or equal to {@link #minimum}. 108 */ 109 private int maximum; 110 111 /** 112 * A property that indicates whether the value of this {@link 113 * BoundedRangeModel} is going to change in the immediate future. 114 */ 115 private boolean isAdjusting; 116 117 /** 118 * Constructs a <code>DefaultBoundedRangeModel</code> with default 119 * values for the properties. The properties <code>value</code>, 120 * <code>extent</code> and <code>minimum</code> will be initialized 121 * to zero; <code>maximum</code> will be set to 100; the property 122 * <code>valueIsAdjusting</code> will be <code>false</code>. 123 */ DefaultBoundedRangeModel()124 public DefaultBoundedRangeModel() 125 { 126 // The fields value, extent, minimum have the default value 0, and 127 // isAdjusting is already false. These fields no not need to be 128 // set explicitly. 129 maximum = 100; 130 } 131 132 /** 133 * Constructs a <code>DefaultBoundedRangeModel</code> with the 134 * specified values for some properties. 135 * 136 * @param value the initial value of the range model, which must be 137 * a number between <code>minimum</code> and <code>(maximum - 138 * extent)</code>. In a scroll bar visualization of a {@link 139 * BoundedRangeModel}, the <code>value</code> is displayed as the 140 * position of the thumb. 141 * @param extent the initial extent of the range model, which is a 142 * number greater than or equal to zero. In a scroll bar 143 * visualization of a {@link BoundedRangeModel}, the 144 * <code>extent</code> is displayed as the size of the thumb. 145 * @param minimum the initial minimal value of the range model. 146 * @param maximum the initial maximal value of the range model. 147 * 148 * @throws IllegalArgumentException if the following condition is 149 * not satisfied: <code>minimum <= value <= value + extent <= 150 * maximum</code>. 151 */ DefaultBoundedRangeModel(int value, int extent, int minimum, int maximum)152 public DefaultBoundedRangeModel(int value, int extent, int minimum, 153 int maximum) 154 { 155 if (!(minimum <= value && extent >= 0 && (value + extent) <= maximum)) 156 throw new IllegalArgumentException(); 157 158 this.value = value; 159 this.extent = extent; 160 this.minimum = minimum; 161 this.maximum = maximum; 162 163 // The isAdjusting field already has a false value by default. 164 } 165 166 /** 167 * Returns a string with all relevant properties of this range 168 * model. 169 * 170 * @return a string representing the object 171 */ toString()172 public String toString() 173 { 174 return getClass().getName() 175 + "[value=" + value 176 + ", extent=" + extent 177 + ", min=" + minimum 178 + ", max=" + maximum 179 + ", adj=" + isAdjusting 180 + ']'; 181 } 182 183 /** 184 * Returns the current value of this bounded range model. In a 185 * scroll bar visualization of a {@link BoundedRangeModel}, the 186 * <code>value</code> is displayed as the position of the thumb. 187 * 188 * @return the value 189 */ getValue()190 public int getValue() 191 { 192 return value; 193 } 194 195 /** 196 * Changes the current value of this bounded range model. In a 197 * scroll bar visualization of a {@link BoundedRangeModel}, the 198 * <code>value</code> is displayed as the position of the thumb; 199 * changing the <code>value</code> of a scroll bar's model 200 * thus moves the thumb to a different position. 201 * 202 * @param value the value 203 */ setValue(int value)204 public void setValue(int value) 205 { 206 value = Math.max(minimum, value); 207 if (value + extent > maximum) 208 value = maximum - extent; 209 210 if (value != this.value) 211 { 212 this.value = value; 213 fireStateChanged(); 214 } 215 } 216 217 /** 218 * Returns the current extent of this bounded range model, which is 219 * a number greater than or equal to zero. In a scroll bar 220 * visualization of a {@link BoundedRangeModel}, the 221 * <code>extent</code> is displayed as the size of the thumb. 222 * 223 * @return the extent 224 */ getExtent()225 public int getExtent() 226 { 227 return extent; 228 } 229 230 /** 231 * Changes the current extent of this bounded range model. In a 232 * scroll bar visualization of a {@link BoundedRangeModel}, the 233 * <code>extent</code> is displayed as the size of the thumb. 234 * 235 * @param extent the new extent of the range model, which is a 236 * number greater than or equal to zero. 237 */ setExtent(int extent)238 public void setExtent(int extent) 239 { 240 extent = Math.max(extent, 0); 241 if (value + extent > maximum) 242 extent = maximum - value; 243 244 if (extent != this.extent) 245 { 246 this.extent = extent; 247 fireStateChanged(); 248 } 249 } 250 251 /** 252 * Returns the current minimal value of this bounded range model. 253 */ getMinimum()254 public int getMinimum() 255 { 256 return minimum; 257 } 258 259 /** 260 * Changes the current minimal value of this bounded range model. 261 * 262 * @param minimum the new minimal value. 263 */ setMinimum(int minimum)264 public void setMinimum(int minimum) 265 { 266 int value, maximum; 267 268 maximum = Math.max(minimum, this.maximum); 269 value = Math.max(minimum, this.value); 270 271 setRangeProperties(value, extent, minimum, maximum, isAdjusting); 272 } 273 274 /** 275 * Returns the current maximal value of this bounded range model. 276 * 277 * @return the maximum 278 */ getMaximum()279 public int getMaximum() 280 { 281 return maximum; 282 } 283 284 /** 285 * Changes the current maximal value of this bounded range model. 286 * 287 * @param maximum the new maximal value. 288 */ setMaximum(int maximum)289 public void setMaximum(int maximum) 290 { 291 int value, extent, minimum; 292 293 minimum = Math.min(this.minimum, maximum); 294 extent = Math.min(this.extent, maximum - minimum); 295 value = Math.min(this.value, maximum - extent); 296 297 setRangeProperties(value, extent, minimum, maximum, isAdjusting); 298 } 299 300 /** 301 * Returns whether or not the value of this bounded range model is 302 * going to change in the immediate future. Scroll bars set this 303 * property to <code>true</code> while the thumb is being dragged 304 * around; when the mouse is relased, they set the property to 305 * <code>false</code> and post a final {@link ChangeEvent}. 306 * 307 * @return <code>true</code> if the value will change soon again; 308 * <code>false</code> if the value will probably not change soon. 309 */ getValueIsAdjusting()310 public boolean getValueIsAdjusting() 311 { 312 return isAdjusting; 313 } 314 315 /** 316 * Specifies whether or not the value of this bounded range model is 317 * going to change in the immediate future. Scroll bars set this 318 * property to <code>true</code> while the thumb is being dragged 319 * around; when the mouse is relased, they set the property to 320 * <code>false</code>. 321 * 322 * @param isAdjusting <code>true</code> if the value will change 323 * soon again; <code>false</code> if the value will probably not 324 * change soon. 325 */ setValueIsAdjusting(boolean isAdjusting)326 public void setValueIsAdjusting(boolean isAdjusting) 327 { 328 if (isAdjusting == this.isAdjusting) 329 return; 330 331 this.isAdjusting = isAdjusting; 332 fireStateChanged(); 333 } 334 335 /** 336 * Sets all properties. 337 * 338 * @param value the new value of the range model. In a scroll bar 339 * visualization of a {@link BoundedRangeModel}, the 340 * <code>value</code> is displayed as the position of the thumb. 341 * @param extent the new extent of the range model, which is a 342 * number greater than or equal to zero. In a scroll bar 343 * visualization of a {@link BoundedRangeModel}, the 344 * <code>extent</code> is displayed as the size of the thumb. 345 * @param minimum the new minimal value of the range model. 346 * @param maximum the new maximal value of the range model. 347 * @param isAdjusting whether or not the value of this bounded range 348 * model is going to change in the immediate future. Scroll bars set 349 * this property to <code>true</code> while the thumb is being 350 * dragged around; when the mouse is relased, they set the property 351 * to <code>false</code>. 352 */ setRangeProperties(int value, int extent, int minimum, int maximum, boolean isAdjusting)353 public void setRangeProperties(int value, int extent, int minimum, 354 int maximum, boolean isAdjusting) 355 { 356 minimum = Math.min(Math.min(minimum, maximum), value); 357 maximum = Math.max(value, maximum); 358 if (extent + value > maximum) 359 extent = maximum - value; 360 extent = Math.max(0, extent); 361 362 if ((value == this.value) 363 && (extent == this.extent) 364 && (minimum == this.minimum) 365 && (maximum == this.maximum) 366 && (isAdjusting == this.isAdjusting)) 367 return; 368 369 this.value = value; 370 this.extent = extent; 371 this.minimum = minimum; 372 this.maximum = maximum; 373 this.isAdjusting = isAdjusting; 374 375 fireStateChanged(); 376 } 377 378 /** 379 * Subscribes a ChangeListener to state changes. 380 * 381 * @param listener the listener to be subscribed. 382 */ addChangeListener(ChangeListener listener)383 public void addChangeListener(ChangeListener listener) 384 { 385 listenerList.add(ChangeListener.class, listener); 386 } 387 388 /** 389 * Cancels the subscription of a ChangeListener. 390 * 391 * @param listener the listener to be unsubscribed. 392 */ removeChangeListener(ChangeListener listener)393 public void removeChangeListener(ChangeListener listener) 394 { 395 listenerList.remove(ChangeListener.class, listener); 396 } 397 398 /** 399 * Sends a {@link ChangeEvent} to any registered {@link 400 * ChangeListener}s. 401 * 402 * @see #addChangeListener(ChangeListener) 403 * @see #removeChangeListener(ChangeListener) 404 */ fireStateChanged()405 protected void fireStateChanged() 406 { 407 ChangeListener[] listeners = getChangeListeners(); 408 409 if (changeEvent == null) 410 changeEvent = new ChangeEvent(this); 411 412 for (int i = listeners.length - 1; i >= 0; --i) 413 listeners[i].stateChanged(changeEvent); 414 } 415 416 /** 417 * Retrieves the current listeners of the specified class. 418 * 419 * @param listenerType the class of listeners; usually {@link 420 * ChangeListener}<code>.class</code>. 421 * 422 * @return an array with the currently subscribed listeners, or 423 * an empty array if there are currently no listeners. 424 * 425 * @since 1.3 426 */ getListeners(Class<T> listenerType)427 public <T extends EventListener> T[] getListeners(Class<T> listenerType) 428 { 429 return listenerList.getListeners(listenerType); 430 } 431 432 /** 433 * Returns all <code>ChangeListeners</code> that are currently 434 * subscribed for changes to this 435 * <code>DefaultBoundedRangeModel</code>. 436 * 437 * @return an array with the currently subscribed listeners, or 438 * an empty array if there are currently no listeners. 439 * 440 * @since 1.4 441 */ getChangeListeners()442 public ChangeListener[] getChangeListeners() 443 { 444 return (ChangeListener[]) getListeners(ChangeListener.class); 445 } 446 447 /** 448 * Provides serialization support. 449 * 450 * @param stream the output stream (<code>null</code> not permitted). 451 * 452 * @throws IOException if there is an I/O error. 453 */ writeObject(ObjectOutputStream stream)454 private void writeObject(ObjectOutputStream stream) 455 throws IOException 456 { 457 stream.defaultWriteObject(); 458 } 459 460 /** 461 * Provides serialization support. 462 * 463 * @param stream the input stream (<code>null</code> not permitted). 464 * 465 * @throws IOException if there is an I/O error. 466 * @throws ClassNotFoundException if there is a classpath problem. 467 */ readObject(ObjectInputStream stream)468 private void readObject(ObjectInputStream stream) 469 throws ClassNotFoundException, IOException 470 { 471 stream.defaultReadObject(); 472 listenerList = new EventListenerList(); 473 } 474 475 } 476