Source for javax.swing.DefaultBoundedRangeModel

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