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’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