Source for javax.swing.SpinnerNumberModel

   1: /* SpinnerNumberModel.java --
   2:    Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package javax.swing;
  39: 
  40: import java.io.Serializable;
  41: 
  42: import javax.swing.event.ChangeEvent;
  43: 
  44: /**
  45:  * A model used by the {@link JSpinner} component.
  46:  *
  47:  * @author Ka-Hing Cheung
  48:  * @since 1.4
  49:  */
  50: public class SpinnerNumberModel extends AbstractSpinnerModel
  51:   implements Serializable
  52: {
  53:   /**
  54:    * For compatability with Sun's JDK
  55:    */
  56:   private static final long serialVersionUID = 7279176385485777821L;
  57: 
  58:   /** The current value. */
  59:   private Number value;
  60: 
  61:   /** The minimum value (or <code>null</code>). */
  62:   private Comparable minimum;
  63: 
  64:   /** The maximum value (or <code>null</code>). */
  65:   private Comparable maximum;
  66: 
  67:   /** The step size. */
  68:   private Number stepSize;
  69: 
  70:   /**
  71:    * Creates a <code>SpinnerNumberModel</code> with initial value 0, step 1,
  72:    * and no maximum nor minimum.
  73:    */
  74:   public SpinnerNumberModel()
  75:   {
  76:     this(new Integer(0), null, null, new Integer(1));
  77:   }
  78: 
  79:   /**
  80:    * Creates a <code>SpinnerNumberModel</code> with double precision.
  81:    *
  82:    * @param value the initial value
  83:    * @param minimum the minimum value
  84:    * @param maximum the maximum value
  85:    * @param stepSize the step size
  86:    * @throws IllegalArgumentException if minimum &lt;= value &lt;= maximum does 
  87:    *         not hold.
  88:    */
  89:   public SpinnerNumberModel(double value, double minimum, double maximum,
  90:                             double stepSize)
  91:   {
  92:     this(new Double(value), new Double(minimum), new Double(maximum),
  93:          new Double(stepSize));
  94:   }
  95: 
  96:   /**
  97:    * Creates a <code>SpinnerNumberModel</code> with integer precision.
  98:    *
  99:    * @param value the initial value
 100:    * @param minimum the minimum value
 101:    * @param maximum the maximum value
 102:    * @param stepSize the step size
 103:    * @throws IllegalArgumentException if minimum &lt;= value &lt;= maximum does 
 104:    *         not hold.
 105:    */
 106:   public SpinnerNumberModel(int value, int minimum, int maximum, int stepSize)
 107:   {
 108:     this(new Integer(value), new Integer(minimum), new Integer(maximum),
 109:          new Integer(stepSize));
 110:   }
 111: 
 112:   /**
 113:    * Creates a <code>SpinnerNumberModel</code> with the given attributes.  The
 114:    * caller should ensure that both <code>minimum</code> and 
 115:    * <code>maximum</code> are serializable.
 116:    *
 117:    * @param value the initial value (<code>null</code> not permitted).
 118:    * @param minimum the minimum value (<code>null</code> permitted).
 119:    * @param maximum the maximum value (<code>null</code> permitted).
 120:    * @param stepSize the step size  (<code>null</code> not permitted).
 121:    *
 122:    * @throws IllegalArgumentException if minimum &lt;= value &lt;= maximum
 123:    *         does not hold
 124:    * @throws IllegalArgumentException if <code>value</code> is 
 125:    *         <code>null</code>.
 126:    * @throws IllegalArgumentException if <code>stepSize</code> is 
 127:    *         <code>null</code>.
 128:    */
 129:   public SpinnerNumberModel(Number value, Comparable minimum,
 130:                             Comparable maximum, Number stepSize)
 131:   {
 132:     if (stepSize == null)
 133:       throw new IllegalArgumentException("stepSize may not be null");
 134:     if (value == null)
 135:       throw new IllegalArgumentException("value may not be null");
 136:     if (minimum != null)
 137:       {
 138:         if (minimum.compareTo(value) > 0)
 139:           throw new IllegalArgumentException("minimum is not <= value");
 140:       }
 141:     if (maximum != null)
 142:       {
 143:         if (maximum.compareTo(value) < 0)
 144:           throw new IllegalArgumentException("maximum is not >= value");
 145:       }
 146: 
 147:     this.value = value;
 148:     this.stepSize = stepSize;
 149:     this.minimum = minimum;
 150:     this.maximum = maximum;
 151:   }
 152: 
 153:   /**
 154:    * Sets the current value and, if the new value is different to the old
 155:    * value, sends a {@link ChangeEvent} to all registered listeners.
 156:    *
 157:    * @param value the new value (<code>null</code> not permitted, must be an
 158:    *              instance of <code>Number</code>).
 159:    *
 160:    * @throws IllegalArgumentException if <code>value</code> is not an instance
 161:    *         of <code>Number</code>.
 162:    */
 163:   public void setValue(Object value)
 164:   {
 165:     if (! (value instanceof Number))
 166:       throw new IllegalArgumentException("value must be a Number");
 167: 
 168:     if (!this.value.equals(value)) 
 169:       {
 170:         this.value = (Number) value;
 171:         fireStateChanged();
 172:       }
 173:   }
 174: 
 175:   /**
 176:    * Returns the current value, which for this class is always an instance of
 177:    * {@link Number}.
 178:    *
 179:    * @return The current value.
 180:    * 
 181:    * @see #getNumber()
 182:    */
 183:   public Object getValue()
 184:   {
 185:     return value;
 186:   }
 187: 
 188:   /**
 189:    * Returns the next value, or <code>null</code> if adding the step size to
 190:    * the current value results in a value greater than the maximum value.  
 191:    * The current value is not changed.
 192:    *
 193:    * @return The next value, or <code>null</code> if the current value is the 
 194:    *         maximum value represented by this model.
 195:    */
 196:   public Object getNextValue()
 197:   {
 198:     Number num;
 199: 
 200:     if (value instanceof Double)
 201:       num = new Double(value.doubleValue() + stepSize.doubleValue());
 202:     else if (value instanceof Float)
 203:       num = new Double(value.floatValue() + stepSize.floatValue());
 204:     else if (value instanceof Long)
 205:       num = new Long(value.longValue() + stepSize.longValue());
 206:     else if (value instanceof Integer)
 207:       num = new Integer(value.intValue() + stepSize.intValue());
 208:     else if (value instanceof Short)
 209:       num = new Short((short) (value.shortValue() + stepSize.shortValue()));
 210:     else
 211:       num = new Byte((byte) (value.byteValue() + stepSize.byteValue()));
 212:     
 213:     // check upper bound if set
 214:     if ((maximum != null) && maximum.compareTo(num) < 0)
 215:       num = null;
 216:     
 217:     return num;
 218:   }
 219: 
 220:   /**
 221:    * Returns the previous value, or <code>null</code> if subtracting the
 222:    * step size from the current value results in a value less than the minimum
 223:    * value.  The current value is not changed.
 224:    *
 225:    * @return The previous value, or <code>null</code> if the current value
 226:    *         is the minimum value represented by this model.
 227:    */
 228:   public Object getPreviousValue()
 229:   {
 230:     Number num;
 231: 
 232:     if (value instanceof Double)
 233:       num = new Double(value.doubleValue() - stepSize.doubleValue());
 234:     else if (value instanceof Float)
 235:       num = new Double(value.floatValue() - stepSize.floatValue());
 236:     else if (value instanceof Long)
 237:       num = new Long(value.longValue() - stepSize.longValue());
 238:     else if (value instanceof Integer)
 239:       num = new Integer(value.intValue() - stepSize.intValue());
 240:     else if (value instanceof Short)
 241:       num = new Short((short) (value.shortValue() - stepSize.shortValue()));
 242:     else
 243:       num = new Byte((byte) (value.byteValue() - stepSize.byteValue()));
 244:     
 245:     // check lower bound if set
 246:     if ((minimum != null) && minimum.compareTo(num) > 0)
 247:       num = null;
 248: 
 249:     return num;
 250:   }
 251: 
 252:   /**
 253:    * Returns the current value.
 254:    *
 255:    * @return The current value.
 256:    */
 257:   public Number getNumber()
 258:   {
 259:     return value;
 260:   }
 261: 
 262:   /**
 263:    * Returns the minimum value, or <code>null</code> if there is no minimum.
 264:    * 
 265:    * @return The minimum value.
 266:    * 
 267:    * @see #setMinimum(Comparable)
 268:    */
 269:   public Comparable getMinimum()
 270:   {
 271:     return minimum;
 272:   }
 273: 
 274:   /**
 275:    * Sets the minimum value and, if the new value is different to the old
 276:    * value, sends a {@link ChangeEvent} to all registered listeners.  A 
 277:    * <code>null</code> value is interpreted as "no minimum value".  No check
 278:    * is made to ensure that the new minimum is less than or equal to the 
 279:    * current value, the caller is responsible for ensuring that this 
 280:    * relationship holds.  In addition, the caller should ensure that
 281:    * <code>newMinimum</code> is {@link Serializable}.
 282:    * 
 283:    * @param newMinimum  the new minimum value (<code>null</code> permitted).
 284:    * 
 285:    * @see #getMinimum()
 286:    */
 287:   public void setMinimum(Comparable newMinimum)
 288:   {
 289:     if (minimum != null ? !minimum.equals(newMinimum) : newMinimum != null)
 290:       {
 291:         minimum = newMinimum;
 292:         fireStateChanged();
 293:       }
 294:   }
 295: 
 296:   /**
 297:    * Returns the maximum value, or <code>null</code> if there is no maximum.
 298:    * 
 299:    * @return The maximum value.
 300:    * 
 301:    * @see #getMinimum()
 302:    * @see #setMaximum(Comparable)
 303:    */
 304:   public Comparable getMaximum()
 305:   {
 306:     return maximum;
 307:   }
 308: 
 309:   /**
 310:    * Sets the maximum value and, if the new value is different to the old
 311:    * value, sends a {@link ChangeEvent} to all registered listeners.  A 
 312:    * <code>null</code> value is interpreted as "no maximum value".  No check
 313:    * is made to ensure that the new maximum is greater than or equal to the 
 314:    * current value, the caller is responsible for ensuring that this 
 315:    * relationship holds. In addition, the caller should ensure that
 316:    * <code>newMaximum</code> is {@link Serializable}.
 317:    * 
 318:    * @param newMaximum  the new maximum (<code>null</code> permitted).
 319:    * 
 320:    * @see #getMaximum()
 321:    */
 322:   public void setMaximum(Comparable newMaximum)
 323:   {
 324:     if (maximum != null ? !maximum.equals(newMaximum) : newMaximum != null)
 325:       {
 326:         maximum = newMaximum;
 327:         fireStateChanged();
 328:       }
 329:   }
 330: 
 331:   /**
 332:    * Returns the step size.
 333:    * 
 334:    * @return The step size (never <code>null</code>).
 335:    */
 336:   public Number getStepSize()
 337:   {
 338:     return stepSize;
 339:   }
 340: 
 341:   /**
 342:    * Sets the step size and, if the new step size is different to the old
 343:    * step size, sends a {@link ChangeEvent} to all registered listeners.
 344:    * 
 345:    * @param newStepSize  the new step size (<code>null</code> not permitted).
 346:    * 
 347:    * @throws IllegalArgumentException if <code>newStepSize</code> is 
 348:    *         <code>null</code>.
 349:    */
 350:   public void setStepSize(Number newStepSize)
 351:   {
 352:     if (newStepSize == null)
 353:       throw new IllegalArgumentException();
 354: 
 355:     if (!stepSize.equals(newStepSize))
 356:       {
 357:         stepSize = newStepSize;
 358:         fireStateChanged();
 359:       }
 360:   }
 361: }