/* * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.swing; import java.awt.*;import java.awt.event.*; import javax.swing.event.*;import javax.swing.text.*;import javax.swing.plaf.SpinnerUI; import java.util.*;import java.beans.*;import java.text.*;import java.io.*;import java.util.HashMap;import sun.util.resources.LocaleData; import javax.accessibility.*; /** * A single line input field that lets the user select a * number or an object value from an ordered sequence. Spinners typically * provide a pair of tiny arrow buttons for stepping through the elements * of the sequence. The keyboard up/down arrow keys also cycle through the * elements. The user may also be allowed to type a (legal) value directly * into the spinner. Although combo boxes provide similar functionality, * spinners are sometimes preferred because they don't require a drop down list * that can obscure important data. * <p> * A <code>JSpinner</code>'s sequence value is defined by its * <code>SpinnerModel</code>. * The <code>model</code> can be specified as a constructor argument and * changed with the <code>model</code> property. <code>SpinnerModel</code> * classes for some common types are provided: <code>SpinnerListModel</code>, * <code>SpinnerNumberModel</code>, and <code>SpinnerDateModel</code>. * <p> * A <code>JSpinner</code> has a single child component that's * responsible for displaying * and potentially changing the current element or <i>value</i> of * the model, which is called the <code>editor</code>. The editor is created * by the <code>JSpinner</code>'s constructor and can be changed with the * <code>editor</code> property. The <code>JSpinner</code>'s editor stays * in sync with the model by listening for <code>ChangeEvent</code>s. If the * user has changed the value displayed by the <code>editor</code> it is * possible for the <code>model</code>'s value to differ from that of * the <code>editor</code>. To make sure the <code>model</code> has the same * value as the editor use the <code>commitEdit</code> method, eg: * <pre> * try { * spinner.commitEdit(); * } * catch (ParseException pe) {{ * // Edited value is invalid, spinner.getValue() will return * // the last valid value, you could revert the spinner to show that: * JComponent editor = spinner.getEditor() * if (editor instanceof DefaultEditor) { * ((DefaultEditor)editor).getTextField().setValue(spinner.getValue(); * } * // reset the value to some known value: * spinner.setValue(fallbackValue); * // or treat the last valid value as the current, in which * // case you don't need to do anything. * } * return spinner.getValue(); * </pre> * <p> * For information and examples of using spinner see * <a href="http://java.sun.com/doc/books/tutorial/uiswing/components/spinner.html">How to Use Spinners</a>, * a section in <em>The Java Tutorial.</em> * <p> * <strong>Warning:</strong> Swing is not thread safe. For more * information see <a * href="package-summary.html#threading">Swing's Threading * Policy</a>. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans<sup><font size="-2">TM</font></sup> * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @beaninfo * attribute: isContainer false * description: A single line input field that lets the user select a * number or an object value from an ordered set. * * @see SpinnerModel * @see AbstractSpinnerModel * @see SpinnerListModel * @see SpinnerNumberModel * @see SpinnerDateModel * @see JFormattedTextField * * @author Hans Muller * @author Lynn Monsanto (accessibility) * @since 1.4 */public class JSpinner extends JComponent implements Accessible{ /** * @see #getUIClassID * @see #readObject */ private static final String uiClassID = "SpinnerUI"; private static final Action DISABLED_ACTION = new DisabledAction(); private SpinnerModel model; private JComponent editor; private ChangeListener modelListener; private transient ChangeEvent changeEvent; private boolean editorExplicitlySet = false; /** * Constructs a spinner for the given model. The spinner has * a set of previous/next buttons, and an editor appropriate * for the model. * * @throws NullPointerException if the model is {@code null} */ public JSpinner(SpinnerModel model) { if (model == null) { throw new NullPointerException("model cannot be null"); } this.model = model; this.editor = createEditor(model); setUIProperty("opaque",true); updateUI(); } /** * Constructs a spinner with an <code>Integer SpinnerNumberModel</code> * with initial value 0 and no minimum or maximum limits. */ public JSpinner() { this(new SpinnerNumberModel()); } /** * Returns the look and feel (L&F) object that renders this component. * * @return the <code>SpinnerUI</code> object that renders this component */ public SpinnerUI getUI() { return (SpinnerUI)ui; } /** * Sets the look and feel (L&F) object that renders this component. * * @param ui the <code>SpinnerUI</code> L&F object * @see UIDefaults#getUI */ public void setUI(SpinnerUI ui) { super.setUI(ui); } /** * Returns the suffix used to construct the name of the look and feel * (L&F) class used to render this component. * * @return the string "SpinnerUI" * @see JComponent#getUIClassID * @see UIDefaults#getUI */ public String getUIClassID() { return uiClassID; } /** * Resets the UI property with the value from the current look and feel. * * @see UIManager#getUI */ public void updateUI() { setUI((SpinnerUI)UIManager.getUI(this)); invalidate(); } /** * This method is called by the constructors to create the * <code>JComponent</code> * that displays the current value of the sequence. The editor may * also allow the user to enter an element of the sequence directly. * An editor must listen for <code>ChangeEvents</code> on the * <code>model</code> and keep the value it displays * in sync with the value of the model. * <p> * Subclasses may override this method to add support for new * <code>SpinnerModel</code> classes. Alternatively one can just * replace the editor created here with the <code>setEditor</code> * method. The default mapping from model type to editor is: * <ul> * <li> <code>SpinnerNumberModel => JSpinner.NumberEditor</code> * <li> <code>SpinnerDateModel => JSpinner.DateEditor</code> * <li> <code>SpinnerListModel => JSpinner.ListEditor</code> * <li> <i>all others</i> => <code>JSpinner.DefaultEditor</code> * </ul> * * @return a component that displays the current value of the sequence * @param model the value of getModel * @see #getModel * @see #setEditor */ protected JComponent createEditor(SpinnerModel model) { if (model instanceof SpinnerDateModel) { return new DateEditor(this); } else if (model instanceof SpinnerListModel) { return new ListEditor(this); } else if (model instanceof SpinnerNumberModel) { return new NumberEditor(this); } else { return new DefaultEditor(this); } } /** * Changes the model that represents the value of this spinner. * If the editor property has not been explicitly set, * the editor property is (implicitly) set after the <code>"model"</code> * <code>PropertyChangeEvent</code> has been fired. The editor * property is set to the value returned by <code>createEditor</code>, * as in: * <pre> * setEditor(createEditor(model)); * </pre> * * @param model the new <code>SpinnerModel</code> * @see #getModel * @see #getEditor * @see #setEditor * @throws IllegalArgumentException if model is <code>null</code> * * @beaninfo * bound: true * attribute: visualUpdate true * description: Model that represents the value of this spinner. */ public void setModel(SpinnerModel model) { if (model == null) { throw new IllegalArgumentException("null model"); } if (!model.equals(this.model)) { SpinnerModel oldModel = this.model; this.model = model; if (modelListener != null) { oldModel.removeChangeListener(modelListener); this.model.addChangeListener(modelListener); } firePropertyChange("model", oldModel, model); if (!editorExplicitlySet) { setEditor(createEditor(model)); // sets editorExplicitlySet true editorExplicitlySet = false; } repaint(); revalidate(); } } /** * Returns the <code>SpinnerModel</code> that defines * this spinners sequence of values. * * @return the value of the model property * @see #setModel */ public SpinnerModel getModel() { return model; } /** * Returns the current value of the model, typically * this value is displayed by the <code>editor</code>. If the * user has changed the value displayed by the <code>editor</code> it is * possible for the <code>model</code>'s value to differ from that of * the <code>editor</code>, refer to the class level javadoc for examples * of how to deal with this. * <p> * This method simply delegates to the <code>model</code>. * It is equivalent to: * <pre> * getModel().getValue() * </pre> * * @see #setValue * @see SpinnerModel#getValue */ public Object getValue() { return getModel().getValue(); } /** * Changes current value of the model, typically * this value is displayed by the <code>editor</code>. * If the <code>SpinnerModel</code> implementation * doesn't support the specified value then an * <code>IllegalArgumentException</code> is thrown. * <p> * This method simply delegates to the <code>model</code>. * It is equivalent to: * <pre> * getModel().setValue(value) * </pre> * * @throws IllegalArgumentException if <code>value</code> isn't allowed * @see #getValue * @see SpinnerModel#setValue */ public void setValue(Object value) { getModel().setValue(value); } /** * Returns the object in the sequence that comes after the object returned * by <code>getValue()</code>. If the end of the sequence has been reached * then return <code>null</code>. * Calling this method does not effect <code>value</code>. * <p> * This method simply delegates to the <code>model</code>. * It is equivalent to: * <pre> * getModel().getNextValue() * </pre> * * @return the next legal value or <code>null</code> if one doesn't exist * @see #getValue * @see #getPreviousValue * @see SpinnerModel#getNextValue */ public Object getNextValue() { return getModel().getNextValue(); } /** * We pass <code>Change</code> events along to the listeners with the * the slider (instead of the model itself) as the event source. */ private class ModelListener implements ChangeListener, Serializable { public void stateChanged(ChangeEvent e) { fireStateChanged(); } } /** * Adds a listener to the list that is notified each time a change * to the model occurs. The source of <code>ChangeEvents</code> * delivered to <code>ChangeListeners</code> will be this * <code>JSpinner</code>. Note also that replacing the model * will not affect listeners added directly to JSpinner. * Applications can add listeners to the model directly. In that * case is that the source of the event would be the * <code>SpinnerModel</code>. * * @param listener the <code>ChangeListener</code> to add * @see #removeChangeListener * @see #getModel */ public void addChangeListener(ChangeListener listener) { if (modelListener == null) { modelListener = new ModelListener(); getModel().addChangeListener(modelListener); } listenerList.add(ChangeListener.class, listener); } /** * Removes a <code>ChangeListener</code> from this spinner. * * @param listener the <code>ChangeListener</code> to remove * @see #fireStateChanged * @see #addChangeListener */ public void removeChangeListener(ChangeListener listener) { listenerList.remove(ChangeListener.class, listener); } /** * Returns an array of all the <code>ChangeListener</code>s added * to this JSpinner with addChangeListener(). * * @return all of the <code>ChangeListener</code>s added or an empty * array if no listeners have been added * @since 1.4 */ public ChangeListener[] getChangeListeners() { return listenerList.getListeners(ChangeListener.class); } /** * Sends a <code>ChangeEvent</code>, whose source is this * <code>JSpinner</code>, to each <code>ChangeListener</code>. * When a <code>ChangeListener</code> has been added * to the spinner, this method method is called each time * a <code>ChangeEvent</code> is received from the model. * * @see #addChangeListener * @see #removeChangeListener * @see EventListenerList */ protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ChangeListener.class) { if (changeEvent == null) { changeEvent = new ChangeEvent(this); } ((ChangeListener)listeners[i+1]).stateChanged(changeEvent); } } } /** * Returns the object in the sequence that comes * before the object returned by <code>getValue()</code>. * If the end of the sequence has been reached then * return <code>null</code>. Calling this method does * not effect <code>value</code>. * <p> * This method simply delegates to the <code>model</code>. * It is equivalent to: * <pre> * getModel().getPreviousValue() * </pre> * * @return the previous legal value or <code>null</code> * if one doesn't exist * @see #getValue * @see #getNextValue * @see SpinnerModel#getPreviousValue */ public Object getPreviousValue() { return getModel().getPreviousValue(); } /** * Changes the <code>JComponent</code> that displays the current value * of the <code>SpinnerModel</code>. It is the responsibility of this * method to <i>disconnect</i> the old editor from the model and to * connect the new editor. This may mean removing the * old editors <code>ChangeListener</code> from the model or the * spinner itself and adding one for the new editor. * * @param editor the new editor * @see #getEditor * @see #createEditor * @see #getModel * @throws IllegalArgumentException if editor is <code>null</code> *Lines 1–500 of 2033. Load more
/* * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.swing; import java.awt.*; import java.awt.event.*; import javax.swing.event.*; import javax.swing.text.*; import javax.swing.plaf.SpinnerUI; import java.util.*; import java.beans.*; import java.text.*; import java.io.*; import java.util.HashMap; import sun.util.resources.LocaleData; import javax.accessibility.*; /** * A single line input field that lets the user select a * number or an object value from an ordered sequence. Spinners typically * provide a pair of tiny arrow buttons for stepping through the elements * of the sequence. The keyboard up/down arrow keys also cycle through the * elements. The user may also be allowed to type a (legal) value directly * into the spinner. Although combo boxes provide similar functionality, * spinners are sometimes preferred because they don't require a drop down list * that can obscure important data. * <p> * A <code>JSpinner</code>'s sequence value is defined by its * <code>SpinnerModel</code>. * The <code>model</code> can be specified as a constructor argument and * changed with the <code>model</code> property. <code>SpinnerModel</code> * classes for some common types are provided: <code>SpinnerListModel</code>, * <code>SpinnerNumberModel</code>, and <code>SpinnerDateModel</code>. * <p> * A <code>JSpinner</code> has a single child component that's * responsible for displaying * and potentially changing the current element or <i>value</i> of * the model, which is called the <code>editor</code>. The editor is created * by the <code>JSpinner</code>'s constructor and can be changed with the * <code>editor</code> property. The <code>JSpinner</code>'s editor stays * in sync with the model by listening for <code>ChangeEvent</code>s. If the * user has changed the value displayed by the <code>editor</code> it is * possible for the <code>model</code>'s value to differ from that of * the <code>editor</code>. To make sure the <code>model</code> has the same * value as the editor use the <code>commitEdit</code> method, eg: * <pre> * try { * spinner.commitEdit(); * } * catch (ParseException pe) {{ * // Edited value is invalid, spinner.getValue() will return * // the last valid value, you could revert the spinner to show that: * JComponent editor = spinner.getEditor() * if (editor instanceof DefaultEditor) { * ((DefaultEditor)editor).getTextField().setValue(spinner.getValue(); * } * // reset the value to some known value: * spinner.setValue(fallbackValue); * // or treat the last valid value as the current, in which * // case you don't need to do anything. * } * return spinner.getValue(); * </pre> * <p> * For information and examples of using spinner see * <a href="http://java.sun.com/doc/books/tutorial/uiswing/components/spinner.html">How to Use Spinners</a>, * a section in <em>The Java Tutorial.</em> * <p> * <strong>Warning:</strong> Swing is not thread safe. For more * information see <a * href="package-summary.html#threading">Swing's Threading * Policy</a>. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans<sup><font size="-2">TM</font></sup> * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @beaninfo * attribute: isContainer false * description: A single line input field that lets the user select a * number or an object value from an ordered set. * * @see SpinnerModel * @see AbstractSpinnerModel * @see SpinnerListModel * @see SpinnerNumberModel * @see SpinnerDateModel * @see JFormattedTextField * * @author Hans Muller * @author Lynn Monsanto (accessibility) * @since 1.4 */ public class JSpinner extends JComponent implements Accessible { /** * @see #getUIClassID * @see #readObject */ private static final String uiClassID = "SpinnerUI"; private static final Action DISABLED_ACTION = new DisabledAction(); private SpinnerModel model; private JComponent editor; private ChangeListener modelListener; private transient ChangeEvent changeEvent; private boolean editorExplicitlySet = false; /** * Constructs a spinner for the given model. The spinner has * a set of previous/next buttons, and an editor appropriate * for the model. * * @throws NullPointerException if the model is {@code null} */ public JSpinner(SpinnerModel model) { if (model == null) { throw new NullPointerException("model cannot be null"); } this.model = model; this.editor = createEditor(model); setUIProperty("opaque",true); updateUI(); } /** * Constructs a spinner with an <code>Integer SpinnerNumberModel</code> * with initial value 0 and no minimum or maximum limits. */ public JSpinner() { this(new SpinnerNumberModel()); } /** * Returns the look and feel (L&F) object that renders this component. * * @return the <code>SpinnerUI</code> object that renders this component */ public SpinnerUI getUI() { return (SpinnerUI)ui; } /** * Sets the look and feel (L&F) object that renders this component. * * @param ui the <code>SpinnerUI</code> L&F object * @see UIDefaults#getUI */ public void setUI(SpinnerUI ui) { super.setUI(ui); } /** * Returns the suffix used to construct the name of the look and feel * (L&F) class used to render this component. * * @return the string "SpinnerUI" * @see JComponent#getUIClassID * @see UIDefaults#getUI */ public String getUIClassID() { return uiClassID; } /** * Resets the UI property with the value from the current look and feel. * * @see UIManager#getUI */ public void updateUI() { setUI((SpinnerUI)UIManager.getUI(this)); invalidate(); } /** * This method is called by the constructors to create the * <code>JComponent</code> * that displays the current value of the sequence. The editor may * also allow the user to enter an element of the sequence directly. * An editor must listen for <code>ChangeEvents</code> on the * <code>model</code> and keep the value it displays * in sync with the value of the model. * <p> * Subclasses may override this method to add support for new * <code>SpinnerModel</code> classes. Alternatively one can just * replace the editor created here with the <code>setEditor</code> * method. The default mapping from model type to editor is: * <ul> * <li> <code>SpinnerNumberModel => JSpinner.NumberEditor</code> * <li> <code>SpinnerDateModel => JSpinner.DateEditor</code> * <li> <code>SpinnerListModel => JSpinner.ListEditor</code> * <li> <i>all others</i> => <code>JSpinner.DefaultEditor</code> * </ul> * * @return a component that displays the current value of the sequence * @param model the value of getModel * @see #getModel * @see #setEditor */ protected JComponent createEditor(SpinnerModel model) { if (model instanceof SpinnerDateModel) { return new DateEditor(this); } else if (model instanceof SpinnerListModel) { return new ListEditor(this); } else if (model instanceof SpinnerNumberModel) { return new NumberEditor(this); } else { return new DefaultEditor(this); } } /** * Changes the model that represents the value of this spinner. * If the editor property has not been explicitly set, * the editor property is (implicitly) set after the <code>"model"</code> * <code>PropertyChangeEvent</code> has been fired. The editor * property is set to the value returned by <code>createEditor</code>, * as in: * <pre> * setEditor(createEditor(model)); * </pre> * * @param model the new <code>SpinnerModel</code> * @see #getModel * @see #getEditor * @see #setEditor * @throws IllegalArgumentException if model is <code>null</code> * * @beaninfo * bound: true * attribute: visualUpdate true * description: Model that represents the value of this spinner. */ public void setModel(SpinnerModel model) { if (model == null) { throw new IllegalArgumentException("null model"); } if (!model.equals(this.model)) { SpinnerModel oldModel = this.model; this.model = model; if (modelListener != null) { oldModel.removeChangeListener(modelListener); this.model.addChangeListener(modelListener); } firePropertyChange("model", oldModel, model); if (!editorExplicitlySet) { setEditor(createEditor(model)); // sets editorExplicitlySet true editorExplicitlySet = false; } repaint(); revalidate(); } } /** * Returns the <code>SpinnerModel</code> that defines * this spinners sequence of values. * * @return the value of the model property * @see #setModel */ public SpinnerModel getModel() { return model; } /** * Returns the current value of the model, typically * this value is displayed by the <code>editor</code>. If the * user has changed the value displayed by the <code>editor</code> it is * possible for the <code>model</code>'s value to differ from that of * the <code>editor</code>, refer to the class level javadoc for examples * of how to deal with this. * <p> * This method simply delegates to the <code>model</code>. * It is equivalent to: * <pre> * getModel().getValue() * </pre> * * @see #setValue * @see SpinnerModel#getValue */ public Object getValue() { return getModel().getValue(); } /** * Changes current value of the model, typically * this value is displayed by the <code>editor</code>. * If the <code>SpinnerModel</code> implementation * doesn't support the specified value then an * <code>IllegalArgumentException</code> is thrown. * <p> * This method simply delegates to the <code>model</code>. * It is equivalent to: * <pre> * getModel().setValue(value) * </pre> * * @throws IllegalArgumentException if <code>value</code> isn't allowed * @see #getValue * @see SpinnerModel#setValue */ public void setValue(Object value) { getModel().setValue(value); } /** * Returns the object in the sequence that comes after the object returned * by <code>getValue()</code>. If the end of the sequence has been reached * then return <code>null</code>. * Calling this method does not effect <code>value</code>. * <p> * This method simply delegates to the <code>model</code>. * It is equivalent to: * <pre> * getModel().getNextValue() * </pre> * * @return the next legal value or <code>null</code> if one doesn't exist * @see #getValue * @see #getPreviousValue * @see SpinnerModel#getNextValue */ public Object getNextValue() { return getModel().getNextValue(); } /** * We pass <code>Change</code> events along to the listeners with the * the slider (instead of the model itself) as the event source. */ private class ModelListener implements ChangeListener, Serializable { public void stateChanged(ChangeEvent e) { fireStateChanged(); } } /** * Adds a listener to the list that is notified each time a change * to the model occurs. The source of <code>ChangeEvents</code> * delivered to <code>ChangeListeners</code> will be this * <code>JSpinner</code>. Note also that replacing the model * will not affect listeners added directly to JSpinner. * Applications can add listeners to the model directly. In that * case is that the source of the event would be the * <code>SpinnerModel</code>. * * @param listener the <code>ChangeListener</code> to add * @see #removeChangeListener * @see #getModel */ public void addChangeListener(ChangeListener listener) { if (modelListener == null) { modelListener = new ModelListener(); getModel().addChangeListener(modelListener); } listenerList.add(ChangeListener.class, listener); } /** * Removes a <code>ChangeListener</code> from this spinner. * * @param listener the <code>ChangeListener</code> to remove * @see #fireStateChanged * @see #addChangeListener */ public void removeChangeListener(ChangeListener listener) { listenerList.remove(ChangeListener.class, listener); } /** * Returns an array of all the <code>ChangeListener</code>s added * to this JSpinner with addChangeListener(). * * @return all of the <code>ChangeListener</code>s added or an empty * array if no listeners have been added * @since 1.4 */ public ChangeListener[] getChangeListeners() { return listenerList.getListeners(ChangeListener.class); } /** * Sends a <code>ChangeEvent</code>, whose source is this * <code>JSpinner</code>, to each <code>ChangeListener</code>. * When a <code>ChangeListener</code> has been added * to the spinner, this method method is called each time * a <code>ChangeEvent</code> is received from the model. * * @see #addChangeListener * @see #removeChangeListener * @see EventListenerList */ protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ChangeListener.class) { if (changeEvent == null) { changeEvent = new ChangeEvent(this); } ((ChangeListener)listeners[i+1]).stateChanged(changeEvent); } } } /** * Returns the object in the sequence that comes * before the object returned by <code>getValue()</code>. * If the end of the sequence has been reached then * return <code>null</code>. Calling this method does * not effect <code>value</code>. * <p> * This method simply delegates to the <code>model</code>. * It is equivalent to: * <pre> * getModel().getPreviousValue() * </pre> * * @return the previous legal value or <code>null</code> * if one doesn't exist * @see #getValue * @see #getNextValue * @see SpinnerModel#getPreviousValue */ public Object getPreviousValue() { return getModel().getPreviousValue(); } /** * Changes the <code>JComponent</code> that displays the current value * of the <code>SpinnerModel</code>. It is the responsibility of this * method to <i>disconnect</i> the old editor from the model and to * connect the new editor. This may mean removing the * old editors <code>ChangeListener</code> from the model or the * spinner itself and adding one for the new editor. * * @param editor the new editor * @see #getEditor * @see #createEditor * @see #getModel * @throws IllegalArgumentException if editor is <code>null</code> *