2 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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)
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.
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
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
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. */
41 import java.awt.Component;
42 import java.awt.Container;
43 import java.awt.Dimension;
44 import java.awt.Insets;
45 import java.awt.LayoutManager;
46 import java.beans.PropertyChangeEvent;
47 import java.beans.PropertyChangeListener;
48 import java.text.DecimalFormat;
49 import java.text.ParseException;
50 import java.text.SimpleDateFormat;
52 import javax.swing.border.EtchedBorder;
53 import javax.swing.event.ChangeEvent;
54 import javax.swing.event.ChangeListener;
55 import javax.swing.plaf.SpinnerUI;
56 import javax.swing.text.DateFormatter;
59 * A JSpinner is a component which typically contains a numeric value and a
60 * way to manipulate the value.
62 * @author Ka-Hing Cheung
66 public class JSpinner extends JComponent
71 public static class DefaultEditor extends JPanel implements ChangeListener,
72 PropertyChangeListener,
75 private JSpinner spinner;
77 /** The JFormattedTextField that backs the editor. */
78 JFormattedTextField ftf;
81 * For compatability with Sun's JDK 1.4.2 rev. 5
83 private static final long serialVersionUID = -5317788736173368172L;
86 * Creates a new <code>DefaultEditor</code> object.
88 * @param spinner the <code>JSpinner</code> associated with this editor
90 public DefaultEditor(JSpinner spinner)
94 this.spinner = spinner;
95 ftf = new JFormattedTextField();
97 ftf.setValue(spinner.getValue());
98 spinner.addChangeListener(this);
102 * Returns the <code>JSpinner</code> object for this editor.
104 public JSpinner getSpinner()
112 public void commitEdit()
113 throws ParseException
120 * @param spinner DOCUMENT ME!
122 public void dismiss(JSpinner spinner)
124 spinner.removeChangeListener(this);
130 * @return DOCUMENT ME!
132 public JFormattedTextField getTextField()
140 * @param parent DOCUMENT ME!
142 public void layoutContainer(Container parent)
144 Insets insets = getInsets();
145 Dimension size = getSize();
146 ftf.setBounds(insets.left, insets.top,
147 size.width - insets.left - insets.right,
148 size.height - insets.top - insets.bottom);
154 * @param parent DOCUMENT ME!
156 * @return DOCUMENT ME!
158 public Dimension minimumLayoutSize(Container parent)
160 Insets insets = getInsets();
161 Dimension minSize = ftf.getMinimumSize();
162 return new Dimension(minSize.width + insets.left + insets.right,
163 minSize.height + insets.top + insets.bottom);
169 * @param parent DOCUMENT ME!
171 * @return DOCUMENT ME!
173 public Dimension preferredLayoutSize(Container parent)
175 Insets insets = getInsets();
176 Dimension prefSize = ftf.getPreferredSize();
177 return new Dimension(prefSize.width + insets.left + insets.right,
178 prefSize.height + insets.top + insets.bottom);
184 * @param event DOCUMENT ME!
186 public void propertyChange(PropertyChangeEvent event)
193 * @param event DOCUMENT ME!
195 public void stateChanged(ChangeEvent event)
200 public void removeLayoutComponent(Component child)
207 * @param name DOCUMENT ME!
208 * @param child DOCUMENT ME!
210 public void addLayoutComponent(String name, Component child)
218 public static class NumberEditor extends DefaultEditor
221 * For compatability with Sun's JDK
223 private static final long serialVersionUID = 3791956183098282942L;
226 * Creates a new NumberEditor object.
228 * @param spinner DOCUMENT ME!
230 public NumberEditor(JSpinner spinner)
236 * Creates a new NumberEditor object.
238 * @param spinner DOCUMENT ME!
240 public NumberEditor(JSpinner spinner, String decimalFormatPattern)
248 * @return DOCUMENT ME!
250 public DecimalFormat getFormat()
255 public SpinnerNumberModel getModel()
257 return (SpinnerNumberModel) getSpinner().getModel();
262 * An editor class for a <code>JSpinner</code> that is used
263 * for displaying and editing dates (e.g. that uses
264 * <code>SpinnerDateModel</code> as model).
266 * The editor uses a {@link JTextField} with the value
267 * displayed by a {@link DateFormatter} instance.
269 public static class DateEditor extends DefaultEditor
272 /** The serialVersionUID. */
273 private static final long serialVersionUID = -4279356973770397815L;
275 /** The DateFormat instance used to format the date. */
276 SimpleDateFormat dateFormat;
279 * Creates a new instance of DateEditor for the specified
280 * <code>JSpinner</code>.
282 * @param spinner the <code>JSpinner</code> for which to
283 * create a <code>DateEditor</code> instance
285 public DateEditor(JSpinner spinner)
288 init(new SimpleDateFormat());
292 * Creates a new instance of DateEditor for the specified
293 * <code>JSpinner</code> using the specified date format
296 * @param spinner the <code>JSpinner</code> for which to
297 * create a <code>DateEditor</code> instance
298 * @param dateFormatPattern the date format to use
300 * @see SimpleDateFormat(String)
302 public DateEditor(JSpinner spinner, String dateFormatPattern)
305 init(new SimpleDateFormat(dateFormatPattern));
309 * Initializes the JFormattedTextField for this editor.
311 * @param the date format to use in the formatted text field
313 private void init(SimpleDateFormat format)
316 getTextField().setFormatterFactory(
317 new JFormattedTextField.AbstractFormatterFactory()
319 public JFormattedTextField.AbstractFormatter
320 getFormatter(JFormattedTextField ftf)
322 return new DateFormatter(dateFormat);
328 * Returns the <code>SimpleDateFormat</code> instance that is used to
329 * format the date value.
331 * @return the <code>SimpleDateFormat</code> instance that is used to
332 * format the date value
334 public SimpleDateFormat getFormat()
340 * Returns the {@link SpinnerDateModel} that is edited by this editor.
342 * @return the <code>SpinnerDateModel</code> that is edited by this editor
344 public SpinnerDateModel getModel()
346 return (SpinnerDateModel) getSpinner().getModel();
350 private static final long serialVersionUID = 3412663575706551720L;
353 private SpinnerModel model;
356 private JComponent editor;
359 private ChangeListener listener = new ChangeListener()
361 public void stateChanged(ChangeEvent evt)
368 * Creates a JSpinner with <code>SpinnerNumberModel</code>
370 * @see javax.swing.SpinnerNumberModel
374 this(new SpinnerNumberModel());
378 * Creates a JSpinner with the specific model and sets the default editor
380 * @param model DOCUMENT ME!
382 public JSpinner(SpinnerModel model)
385 model.addChangeListener(listener);
386 setEditor(createEditor(model));
391 * If the editor is <code>JSpinner.DefaultEditor</code>, then forwards the
392 * call to it, otherwise do nothing.
394 * @throws ParseException DOCUMENT ME!
396 public void commitEdit() throws ParseException
398 if (editor instanceof DefaultEditor)
399 ((DefaultEditor) editor).commitEdit();
403 * Gets the current editor
405 * @return the current editor
409 public JComponent getEditor()
415 * Changes the current editor to the new editor. This methods should remove
416 * the old listeners (if any) and adds the new listeners (if any).
418 * @param editor the new editor
420 * @throws IllegalArgumentException DOCUMENT ME!
424 public void setEditor(JComponent editor)
427 throw new IllegalArgumentException("editor may not be null");
429 if (this.editor instanceof DefaultEditor)
430 ((DefaultEditor) editor).dismiss(this);
431 else if (this.editor instanceof ChangeListener)
432 removeChangeListener((ChangeListener) this.editor);
434 if (editor instanceof ChangeListener)
435 addChangeListener((ChangeListener) editor);
437 this.editor = editor;
441 * Gets the underly model.
443 * @return the underly model
445 public SpinnerModel getModel()
451 * Sets a new underlying model.
453 * @param newModel the new model to set
455 * @exception IllegalArgumentException if newModel is <code>null</code>
457 public void setModel(SpinnerModel newModel)
459 if (newModel == null)
460 throw new IllegalArgumentException();
462 if (model == newModel)
465 SpinnerModel oldModel = model;
467 firePropertyChange("model", oldModel, newModel);
470 setEditor(createEditor(model));
474 * Gets the next value without changing the current value.
476 * @return the next value
478 * @see javax.swing.SpinnerModel#getNextValue
480 public Object getNextValue()
482 return model.getNextValue();
486 * Gets the previous value without changing the current value.
488 * @return the previous value
490 * @see javax.swing.SpinnerModel#getPreviousValue
492 public Object getPreviousValue()
494 return model.getPreviousValue();
498 * Gets the <code>SpinnerUI</code> that handles this spinner
500 * @return the <code>SpinnerUI</code>
502 public SpinnerUI getUI()
504 return (SpinnerUI) ui;
508 * Gets the current value of the spinner, according to the underly model,
511 * @return the current value
513 * @see javax.swing.SpinnerModel#getValue
515 public Object getValue()
517 return model.getValue();
523 * @param value DOCUMENT ME!
525 public void setValue(Object value)
527 model.setValue(value);
531 * This method returns a name to identify which look and feel class will be
532 * the UI delegate for this spinner.
534 * @return The UIClass identifier. "SpinnerUI"
536 public String getUIClassID()
542 * This method resets the spinner's UI delegate to the default UI for the
543 * current look and feel.
545 public void updateUI()
547 setUI((SpinnerUI) UIManager.getUI(this));
551 * This method sets the spinner's UI delegate.
553 * @param ui The spinner's UI delegate.
555 public void setUI(SpinnerUI ui)
561 * Adds a <code>ChangeListener</code>
563 * @param listener the listener to add
565 public void addChangeListener(ChangeListener listener)
567 listenerList.add(ChangeListener.class, listener);
571 * Remove a particular listener
573 * @param listener the listener to remove
575 public void removeChangeListener(ChangeListener listener)
577 listenerList.remove(ChangeListener.class, listener);
581 * Gets all the <code>ChangeListener</code>s
583 * @return all the <code>ChangeListener</code>s
585 public ChangeListener[] getChangeListeners()
587 return (ChangeListener[]) listenerList.getListeners(ChangeListener.class);
591 * Fires a <code>ChangeEvent</code> to all the <code>ChangeListener</code>s
592 * added to this <code>JSpinner</code>
594 protected void fireStateChanged()
596 ChangeEvent evt = new ChangeEvent(this);
597 ChangeListener[] listeners = getChangeListeners();
599 for (int i = 0; i < listeners.length; ++i)
600 listeners[i].stateChanged(evt);
604 * Creates an editor for this <code>JSpinner</code>. Really, it should be a
605 * <code>JSpinner.DefaultEditor</code>, but since that should be
606 * implemented by a JFormattedTextField, and one is not written, I am just
607 * using a dummy one backed by a JLabel.
609 * @param model DOCUMENT ME!
611 * @return the default editor
613 protected JComponent createEditor(SpinnerModel model)
615 if (model instanceof SpinnerDateModel)
616 return new DateEditor(this);
617 else if (model instanceof SpinnerNumberModel)
618 return new NumberEditor(this);
620 return new DefaultEditor(this);