Frames | No Frames |
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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 468: private void readObject(ObjectInputStream stream) 469: throws ClassNotFoundException, IOException 470: { 471: stream.defaultReadObject(); 472: listenerList = new EventListenerList(); 473: } 474: 475: }