jdk/src/share/classes/javax/swing/JSpinner.java

Print this page




   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.swing;
  27 
  28 import java.awt.*;
  29 import java.awt.event.*;
  30 
  31 import javax.swing.event.*;
  32 import javax.swing.text.*;
  33 import javax.swing.plaf.SpinnerUI;
  34 
  35 import java.util.*;
  36 import java.beans.*;



  37 import java.text.*;
  38 import java.io.*;
  39 import java.text.spi.DateFormatProvider;
  40 import java.text.spi.NumberFormatProvider;
  41 
  42 import javax.accessibility.*;

  43 import sun.util.locale.provider.LocaleProviderAdapter;
  44 import sun.util.locale.provider.LocaleResources;
  45 import sun.util.locale.provider.LocaleServiceProviderPool;
  46 
  47 
  48 /**
  49  * A single line input field that lets the user select a
  50  * number or an object value from an ordered sequence. Spinners typically
  51  * provide a pair of tiny arrow buttons for stepping through the elements
  52  * of the sequence. The keyboard up/down arrow keys also cycle through the
  53  * elements. The user may also be allowed to type a (legal) value directly
  54  * into the spinner. Although combo boxes provide similar functionality,
  55  * spinners are sometimes preferred because they don't require a drop down list
  56  * that can obscure important data.
  57  * <p>
  58  * A <code>JSpinner</code>'s sequence value is defined by its
  59  * <code>SpinnerModel</code>.
  60  * The <code>model</code> can be specified as a constructor argument and
  61  * changed with the <code>model</code> property.  <code>SpinnerModel</code>
  62  * classes for some common types are provided: <code>SpinnerListModel</code>,
  63  * <code>SpinnerNumberModel</code>, and <code>SpinnerDateModel</code>.
  64  * <p>
  65  * A <code>JSpinner</code> has a single child component that's
  66  * responsible for displaying


  93  * </pre>
  94  * <p>
  95  * For information and examples of using spinner see
  96  * <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/spinner.html">How to Use Spinners</a>,
  97  * a section in <em>The Java Tutorial.</em>
  98  * <p>
  99  * <strong>Warning:</strong> Swing is not thread safe. For more
 100  * information see <a
 101  * href="package-summary.html#threading">Swing's Threading
 102  * Policy</a>.
 103  * <p>
 104  * <strong>Warning:</strong>
 105  * Serialized objects of this class will not be compatible with
 106  * future Swing releases. The current serialization support is
 107  * appropriate for short term storage or RMI between applications running
 108  * the same version of Swing.  As of 1.4, support for long term storage
 109  * of all JavaBeans&trade;
 110  * has been added to the <code>java.beans</code> package.
 111  * Please see {@link java.beans.XMLEncoder}.
 112  *
 113  * @beaninfo
 114  *   attribute: isContainer false
 115  * description: A single line input field that lets the user select a
 116  *     number or an object value from an ordered set.
 117  *
 118  * @see SpinnerModel
 119  * @see AbstractSpinnerModel
 120  * @see SpinnerListModel
 121  * @see SpinnerNumberModel
 122  * @see SpinnerDateModel
 123  * @see JFormattedTextField
 124  *
 125  * @author Hans Muller
 126  * @author Lynn Monsanto (accessibility)
 127  * @since 1.4
 128  */


 129 @SuppressWarnings("serial") // Same-version serialization only
 130 public class JSpinner extends JComponent implements Accessible
 131 {
 132     /**
 133      * @see #getUIClassID
 134      * @see #readObject
 135      */
 136     private static final String uiClassID = "SpinnerUI";
 137 
 138     private static final Action DISABLED_ACTION = new DisabledAction();
 139 
 140     private SpinnerModel model;
 141     private JComponent editor;
 142     private ChangeListener modelListener;
 143     private transient ChangeEvent changeEvent;
 144     private boolean editorExplicitlySet = false;
 145 
 146 
 147     /**
 148      * Constructs a spinner for the given model. The spinner has


 184 
 185     /**
 186      * Sets the look and feel (L&amp;F) object that renders this component.
 187      *
 188      * @param ui  the <code>SpinnerUI</code> L&amp;F object
 189      * @see UIDefaults#getUI
 190      */
 191     public void setUI(SpinnerUI ui) {
 192         super.setUI(ui);
 193     }
 194 
 195 
 196     /**
 197      * Returns the suffix used to construct the name of the look and feel
 198      * (L&amp;F) class used to render this component.
 199      *
 200      * @return the string "SpinnerUI"
 201      * @see JComponent#getUIClassID
 202      * @see UIDefaults#getUI
 203      */

 204     public String getUIClassID() {
 205         return uiClassID;
 206     }
 207 
 208 
 209 
 210     /**
 211      * Resets the UI property with the value from the current look and feel.
 212      *
 213      * @see UIManager#getUI
 214      */
 215     public void updateUI() {
 216         setUI((SpinnerUI)UIManager.getUI(this));
 217         invalidate();
 218     }
 219 
 220 
 221     /**
 222      * This method is called by the constructors to create the
 223      * <code>JComponent</code>


 258         }
 259     }
 260 
 261 
 262     /**
 263      * Changes the model that represents the value of this spinner.
 264      * If the editor property has not been explicitly set,
 265      * the editor property is (implicitly) set after the <code>"model"</code>
 266      * <code>PropertyChangeEvent</code> has been fired.  The editor
 267      * property is set to the value returned by <code>createEditor</code>,
 268      * as in:
 269      * <pre>
 270      * setEditor(createEditor(model));
 271      * </pre>
 272      *
 273      * @param model the new <code>SpinnerModel</code>
 274      * @see #getModel
 275      * @see #getEditor
 276      * @see #setEditor
 277      * @throws IllegalArgumentException if model is <code>null</code>
 278      *
 279      * @beaninfo
 280      *        bound: true
 281      *    attribute: visualUpdate true
 282      *  description: Model that represents the value of this spinner.
 283      */


 284     public void setModel(SpinnerModel model) {
 285         if (model == null) {
 286             throw new IllegalArgumentException("null model");
 287         }
 288         if (!model.equals(this.model)) {
 289             SpinnerModel oldModel = this.model;
 290             this.model = model;
 291             if (modelListener != null) {
 292                 oldModel.removeChangeListener(modelListener);
 293                 this.model.addChangeListener(modelListener);
 294             }
 295             firePropertyChange("model", oldModel, model);
 296             if (!editorExplicitlySet) {
 297                 setEditor(createEditor(model)); // sets editorExplicitlySet true
 298                 editorExplicitlySet = false;
 299             }
 300             repaint();
 301             revalidate();
 302         }
 303     }


 361     }
 362 
 363 
 364     /**
 365      * Returns the object in the sequence that comes after the object returned
 366      * by <code>getValue()</code>. If the end of the sequence has been reached
 367      * then return <code>null</code>.
 368      * Calling this method does not effect <code>value</code>.
 369      * <p>
 370      * This method simply delegates to the <code>model</code>.
 371      * It is equivalent to:
 372      * <pre>
 373      * getModel().getNextValue()
 374      * </pre>
 375      *
 376      * @return the next legal value or <code>null</code> if one doesn't exist
 377      * @see #getValue
 378      * @see #getPreviousValue
 379      * @see SpinnerModel#getNextValue
 380      */

 381     public Object getNextValue() {
 382         return getModel().getNextValue();
 383     }
 384 
 385 
 386     /**
 387      * We pass <code>Change</code> events along to the listeners with the
 388      * the slider (instead of the model itself) as the event source.
 389      */
 390     private class ModelListener implements ChangeListener, Serializable {
 391         public void stateChanged(ChangeEvent e) {
 392             fireStateChanged();
 393         }
 394     }
 395 
 396 
 397     /**
 398      * Adds a listener to the list that is notified each time a change
 399      * to the model occurs.  The source of <code>ChangeEvents</code>
 400      * delivered to <code>ChangeListeners</code> will be this


 421     /**
 422      * Removes a <code>ChangeListener</code> from this spinner.
 423      *
 424      * @param listener the <code>ChangeListener</code> to remove
 425      * @see #fireStateChanged
 426      * @see #addChangeListener
 427      */
 428     public void removeChangeListener(ChangeListener listener) {
 429         listenerList.remove(ChangeListener.class, listener);
 430     }
 431 
 432 
 433     /**
 434      * Returns an array of all the <code>ChangeListener</code>s added
 435      * to this JSpinner with addChangeListener().
 436      *
 437      * @return all of the <code>ChangeListener</code>s added or an empty
 438      *         array if no listeners have been added
 439      * @since 1.4
 440      */

 441     public ChangeListener[] getChangeListeners() {
 442         return listenerList.getListeners(ChangeListener.class);
 443     }
 444 
 445 
 446     /**
 447      * Sends a <code>ChangeEvent</code>, whose source is this
 448      * <code>JSpinner</code>, to each <code>ChangeListener</code>.
 449      * When a <code>ChangeListener</code> has been added
 450      * to the spinner, this method method is called each time
 451      * a <code>ChangeEvent</code> is received from the model.
 452      *
 453      * @see #addChangeListener
 454      * @see #removeChangeListener
 455      * @see EventListenerList
 456      */
 457     protected void fireStateChanged() {
 458         Object[] listeners = listenerList.getListenerList();
 459         for (int i = listeners.length - 2; i >= 0; i -= 2) {
 460             if (listeners[i] == ChangeListener.class) {


 469 
 470     /**
 471      * Returns the object in the sequence that comes
 472      * before the object returned by <code>getValue()</code>.
 473      * If the end of the sequence has been reached then
 474      * return <code>null</code>. Calling this method does
 475      * not effect <code>value</code>.
 476      * <p>
 477      * This method simply delegates to the <code>model</code>.
 478      * It is equivalent to:
 479      * <pre>
 480      * getModel().getPreviousValue()
 481      * </pre>
 482      *
 483      * @return the previous legal value or <code>null</code>
 484      *   if one doesn't exist
 485      * @see #getValue
 486      * @see #getNextValue
 487      * @see SpinnerModel#getPreviousValue
 488      */

 489     public Object getPreviousValue() {
 490         return getModel().getPreviousValue();
 491     }
 492 
 493 
 494     /**
 495      * Changes the <code>JComponent</code> that displays the current value
 496      * of the <code>SpinnerModel</code>.  It is the responsibility of this
 497      * method to <i>disconnect</i> the old editor from the model and to
 498      * connect the new editor.  This may mean removing the
 499      * old editors <code>ChangeListener</code> from the model or the
 500      * spinner itself and adding one for the new editor.
 501      *
 502      * @param editor the new editor
 503      * @see #getEditor
 504      * @see #createEditor
 505      * @see #getModel
 506      * @throws IllegalArgumentException if editor is <code>null</code>
 507      *
 508      * @beaninfo
 509      *        bound: true
 510      *    attribute: visualUpdate true
 511      *  description: JComponent that displays the current value of the model
 512      */


 513     public void setEditor(JComponent editor) {
 514         if (editor == null) {
 515             throw new IllegalArgumentException("null editor");
 516         }
 517         if (!editor.equals(this.editor)) {
 518             JComponent oldEditor = this.editor;
 519             this.editor = editor;
 520             if (oldEditor instanceof DefaultEditor) {
 521                 ((DefaultEditor)oldEditor).dismiss(this);
 522             }
 523             editorExplicitlySet = true;
 524             firePropertyChange("editor", oldEditor, editor);
 525             revalidate();
 526             repaint();
 527         }
 528     }
 529 
 530 
 531     /**
 532      * Returns the component that displays and potentially


1412             return false;
1413         }
1414         public void addPropertyChangeListener(PropertyChangeListener l) {
1415         }
1416         public void removePropertyChangeListener(PropertyChangeListener l) {
1417         }
1418         public void actionPerformed(ActionEvent ae) {
1419         }
1420     }
1421 
1422     /////////////////
1423     // Accessibility support
1424     ////////////////
1425 
1426     /**
1427      * Gets the <code>AccessibleContext</code> for the <code>JSpinner</code>
1428      *
1429      * @return the <code>AccessibleContext</code> for the <code>JSpinner</code>
1430      * @since 1.5
1431      */

1432     public AccessibleContext getAccessibleContext() {
1433         if (accessibleContext == null) {
1434             accessibleContext = new AccessibleJSpinner();
1435         }
1436         return accessibleContext;
1437     }
1438 
1439     /**
1440      * <code>AccessibleJSpinner</code> implements accessibility
1441      * support for the <code>JSpinner</code> class.
1442      * @since 1.5
1443      */
1444     protected class AccessibleJSpinner extends AccessibleJComponent
1445         implements AccessibleValue, AccessibleAction, AccessibleText,
1446                    AccessibleEditableText, ChangeListener {
1447 
1448         private Object oldModelValue = null;
1449 
1450         /**
1451          * AccessibleJSpinner constructor




   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */

  25 package javax.swing;
  26 
  27 import java.awt.*;
  28 import java.awt.event.*;
  29 
  30 import javax.swing.event.*;
  31 import javax.swing.text.*;
  32 import javax.swing.plaf.SpinnerUI;
  33 
  34 import java.util.*;
  35 import java.beans.JavaBean;
  36 import java.beans.BeanProperty;
  37 import java.beans.PropertyChangeEvent;
  38 import java.beans.PropertyChangeListener;
  39 import java.text.*;
  40 import java.io.*;
  41 import java.text.spi.DateFormatProvider;
  42 import java.text.spi.NumberFormatProvider;
  43 
  44 import javax.accessibility.*;
  45 
  46 import sun.util.locale.provider.LocaleProviderAdapter;
  47 import sun.util.locale.provider.LocaleResources;


  48 
  49 /**
  50  * A single line input field that lets the user select a
  51  * number or an object value from an ordered sequence. Spinners typically
  52  * provide a pair of tiny arrow buttons for stepping through the elements
  53  * of the sequence. The keyboard up/down arrow keys also cycle through the
  54  * elements. The user may also be allowed to type a (legal) value directly
  55  * into the spinner. Although combo boxes provide similar functionality,
  56  * spinners are sometimes preferred because they don't require a drop down list
  57  * that can obscure important data.
  58  * <p>
  59  * A <code>JSpinner</code>'s sequence value is defined by its
  60  * <code>SpinnerModel</code>.
  61  * The <code>model</code> can be specified as a constructor argument and
  62  * changed with the <code>model</code> property.  <code>SpinnerModel</code>
  63  * classes for some common types are provided: <code>SpinnerListModel</code>,
  64  * <code>SpinnerNumberModel</code>, and <code>SpinnerDateModel</code>.
  65  * <p>
  66  * A <code>JSpinner</code> has a single child component that's
  67  * responsible for displaying


  94  * </pre>
  95  * <p>
  96  * For information and examples of using spinner see
  97  * <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/spinner.html">How to Use Spinners</a>,
  98  * a section in <em>The Java Tutorial.</em>
  99  * <p>
 100  * <strong>Warning:</strong> Swing is not thread safe. For more
 101  * information see <a
 102  * href="package-summary.html#threading">Swing's Threading
 103  * Policy</a>.
 104  * <p>
 105  * <strong>Warning:</strong>
 106  * Serialized objects of this class will not be compatible with
 107  * future Swing releases. The current serialization support is
 108  * appropriate for short term storage or RMI between applications running
 109  * the same version of Swing.  As of 1.4, support for long term storage
 110  * of all JavaBeans&trade;
 111  * has been added to the <code>java.beans</code> package.
 112  * Please see {@link java.beans.XMLEncoder}.
 113  *





 114  * @see SpinnerModel
 115  * @see AbstractSpinnerModel
 116  * @see SpinnerListModel
 117  * @see SpinnerNumberModel
 118  * @see SpinnerDateModel
 119  * @see JFormattedTextField
 120  *
 121  * @author Hans Muller
 122  * @author Lynn Monsanto (accessibility)
 123  * @since 1.4
 124  */
 125 @JavaBean(defaultProperty = "UI", description = "A single line input field that lets the user select a number or an object value from an ordered set.")
 126 @SwingContainer(false)
 127 @SuppressWarnings("serial") // Same-version serialization only
 128 public class JSpinner extends JComponent implements Accessible
 129 {
 130     /**
 131      * @see #getUIClassID
 132      * @see #readObject
 133      */
 134     private static final String uiClassID = "SpinnerUI";
 135 
 136     private static final Action DISABLED_ACTION = new DisabledAction();
 137 
 138     private SpinnerModel model;
 139     private JComponent editor;
 140     private ChangeListener modelListener;
 141     private transient ChangeEvent changeEvent;
 142     private boolean editorExplicitlySet = false;
 143 
 144 
 145     /**
 146      * Constructs a spinner for the given model. The spinner has


 182 
 183     /**
 184      * Sets the look and feel (L&amp;F) object that renders this component.
 185      *
 186      * @param ui  the <code>SpinnerUI</code> L&amp;F object
 187      * @see UIDefaults#getUI
 188      */
 189     public void setUI(SpinnerUI ui) {
 190         super.setUI(ui);
 191     }
 192 
 193 
 194     /**
 195      * Returns the suffix used to construct the name of the look and feel
 196      * (L&amp;F) class used to render this component.
 197      *
 198      * @return the string "SpinnerUI"
 199      * @see JComponent#getUIClassID
 200      * @see UIDefaults#getUI
 201      */
 202     @BeanProperty(bound = false)
 203     public String getUIClassID() {
 204         return uiClassID;
 205     }
 206 
 207 
 208 
 209     /**
 210      * Resets the UI property with the value from the current look and feel.
 211      *
 212      * @see UIManager#getUI
 213      */
 214     public void updateUI() {
 215         setUI((SpinnerUI)UIManager.getUI(this));
 216         invalidate();
 217     }
 218 
 219 
 220     /**
 221      * This method is called by the constructors to create the
 222      * <code>JComponent</code>


 257         }
 258     }
 259 
 260 
 261     /**
 262      * Changes the model that represents the value of this spinner.
 263      * If the editor property has not been explicitly set,
 264      * the editor property is (implicitly) set after the <code>"model"</code>
 265      * <code>PropertyChangeEvent</code> has been fired.  The editor
 266      * property is set to the value returned by <code>createEditor</code>,
 267      * as in:
 268      * <pre>
 269      * setEditor(createEditor(model));
 270      * </pre>
 271      *
 272      * @param model the new <code>SpinnerModel</code>
 273      * @see #getModel
 274      * @see #getEditor
 275      * @see #setEditor
 276      * @throws IllegalArgumentException if model is <code>null</code>





 277      */
 278     @BeanProperty(visualUpdate = true, description
 279             = "Model that represents the value of this spinner.")
 280     public void setModel(SpinnerModel model) {
 281         if (model == null) {
 282             throw new IllegalArgumentException("null model");
 283         }
 284         if (!model.equals(this.model)) {
 285             SpinnerModel oldModel = this.model;
 286             this.model = model;
 287             if (modelListener != null) {
 288                 oldModel.removeChangeListener(modelListener);
 289                 this.model.addChangeListener(modelListener);
 290             }
 291             firePropertyChange("model", oldModel, model);
 292             if (!editorExplicitlySet) {
 293                 setEditor(createEditor(model)); // sets editorExplicitlySet true
 294                 editorExplicitlySet = false;
 295             }
 296             repaint();
 297             revalidate();
 298         }
 299     }


 357     }
 358 
 359 
 360     /**
 361      * Returns the object in the sequence that comes after the object returned
 362      * by <code>getValue()</code>. If the end of the sequence has been reached
 363      * then return <code>null</code>.
 364      * Calling this method does not effect <code>value</code>.
 365      * <p>
 366      * This method simply delegates to the <code>model</code>.
 367      * It is equivalent to:
 368      * <pre>
 369      * getModel().getNextValue()
 370      * </pre>
 371      *
 372      * @return the next legal value or <code>null</code> if one doesn't exist
 373      * @see #getValue
 374      * @see #getPreviousValue
 375      * @see SpinnerModel#getNextValue
 376      */
 377     @BeanProperty(bound = false)
 378     public Object getNextValue() {
 379         return getModel().getNextValue();
 380     }
 381 
 382 
 383     /**
 384      * We pass <code>Change</code> events along to the listeners with the
 385      * the slider (instead of the model itself) as the event source.
 386      */
 387     private class ModelListener implements ChangeListener, Serializable {
 388         public void stateChanged(ChangeEvent e) {
 389             fireStateChanged();
 390         }
 391     }
 392 
 393 
 394     /**
 395      * Adds a listener to the list that is notified each time a change
 396      * to the model occurs.  The source of <code>ChangeEvents</code>
 397      * delivered to <code>ChangeListeners</code> will be this


 418     /**
 419      * Removes a <code>ChangeListener</code> from this spinner.
 420      *
 421      * @param listener the <code>ChangeListener</code> to remove
 422      * @see #fireStateChanged
 423      * @see #addChangeListener
 424      */
 425     public void removeChangeListener(ChangeListener listener) {
 426         listenerList.remove(ChangeListener.class, listener);
 427     }
 428 
 429 
 430     /**
 431      * Returns an array of all the <code>ChangeListener</code>s added
 432      * to this JSpinner with addChangeListener().
 433      *
 434      * @return all of the <code>ChangeListener</code>s added or an empty
 435      *         array if no listeners have been added
 436      * @since 1.4
 437      */
 438     @BeanProperty(bound = false)
 439     public ChangeListener[] getChangeListeners() {
 440         return listenerList.getListeners(ChangeListener.class);
 441     }
 442 
 443 
 444     /**
 445      * Sends a <code>ChangeEvent</code>, whose source is this
 446      * <code>JSpinner</code>, to each <code>ChangeListener</code>.
 447      * When a <code>ChangeListener</code> has been added
 448      * to the spinner, this method method is called each time
 449      * a <code>ChangeEvent</code> is received from the model.
 450      *
 451      * @see #addChangeListener
 452      * @see #removeChangeListener
 453      * @see EventListenerList
 454      */
 455     protected void fireStateChanged() {
 456         Object[] listeners = listenerList.getListenerList();
 457         for (int i = listeners.length - 2; i >= 0; i -= 2) {
 458             if (listeners[i] == ChangeListener.class) {


 467 
 468     /**
 469      * Returns the object in the sequence that comes
 470      * before the object returned by <code>getValue()</code>.
 471      * If the end of the sequence has been reached then
 472      * return <code>null</code>. Calling this method does
 473      * not effect <code>value</code>.
 474      * <p>
 475      * This method simply delegates to the <code>model</code>.
 476      * It is equivalent to:
 477      * <pre>
 478      * getModel().getPreviousValue()
 479      * </pre>
 480      *
 481      * @return the previous legal value or <code>null</code>
 482      *   if one doesn't exist
 483      * @see #getValue
 484      * @see #getNextValue
 485      * @see SpinnerModel#getPreviousValue
 486      */
 487     @BeanProperty(bound = false)
 488     public Object getPreviousValue() {
 489         return getModel().getPreviousValue();
 490     }
 491 
 492 
 493     /**
 494      * Changes the <code>JComponent</code> that displays the current value
 495      * of the <code>SpinnerModel</code>.  It is the responsibility of this
 496      * method to <i>disconnect</i> the old editor from the model and to
 497      * connect the new editor.  This may mean removing the
 498      * old editors <code>ChangeListener</code> from the model or the
 499      * spinner itself and adding one for the new editor.
 500      *
 501      * @param editor the new editor
 502      * @see #getEditor
 503      * @see #createEditor
 504      * @see #getModel
 505      * @throws IllegalArgumentException if editor is <code>null</code>





 506      */
 507     @BeanProperty(visualUpdate = true, description
 508             = "JComponent that displays the current value of the model")
 509     public void setEditor(JComponent editor) {
 510         if (editor == null) {
 511             throw new IllegalArgumentException("null editor");
 512         }
 513         if (!editor.equals(this.editor)) {
 514             JComponent oldEditor = this.editor;
 515             this.editor = editor;
 516             if (oldEditor instanceof DefaultEditor) {
 517                 ((DefaultEditor)oldEditor).dismiss(this);
 518             }
 519             editorExplicitlySet = true;
 520             firePropertyChange("editor", oldEditor, editor);
 521             revalidate();
 522             repaint();
 523         }
 524     }
 525 
 526 
 527     /**
 528      * Returns the component that displays and potentially


1408             return false;
1409         }
1410         public void addPropertyChangeListener(PropertyChangeListener l) {
1411         }
1412         public void removePropertyChangeListener(PropertyChangeListener l) {
1413         }
1414         public void actionPerformed(ActionEvent ae) {
1415         }
1416     }
1417 
1418     /////////////////
1419     // Accessibility support
1420     ////////////////
1421 
1422     /**
1423      * Gets the <code>AccessibleContext</code> for the <code>JSpinner</code>
1424      *
1425      * @return the <code>AccessibleContext</code> for the <code>JSpinner</code>
1426      * @since 1.5
1427      */
1428     @BeanProperty(bound = false)
1429     public AccessibleContext getAccessibleContext() {
1430         if (accessibleContext == null) {
1431             accessibleContext = new AccessibleJSpinner();
1432         }
1433         return accessibleContext;
1434     }
1435 
1436     /**
1437      * <code>AccessibleJSpinner</code> implements accessibility
1438      * support for the <code>JSpinner</code> class.
1439      * @since 1.5
1440      */
1441     protected class AccessibleJSpinner extends AccessibleJComponent
1442         implements AccessibleValue, AccessibleAction, AccessibleText,
1443                    AccessibleEditableText, ChangeListener {
1444 
1445         private Object oldModelValue = null;
1446 
1447         /**
1448          * AccessibleJSpinner constructor