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
.event
.ChangeEvent
;
53 import javax
.swing
.event
.ChangeListener
;
54 import javax
.swing
.plaf
.SpinnerUI
;
55 import javax
.swing
.text
.DateFormatter
;
58 * A JSpinner is a component which typically contains a numeric value and a
59 * way to manipulate the value.
61 * @author Ka-Hing Cheung
65 public class JSpinner
extends JComponent
70 public static class DefaultEditor
extends JPanel
implements ChangeListener
,
71 PropertyChangeListener
,
74 private JSpinner spinner
;
76 /** The JFormattedTextField that backs the editor. */
77 JFormattedTextField ftf
;
80 * For compatability with Sun's JDK 1.4.2 rev. 5
82 private static final long serialVersionUID
= -5317788736173368172L;
85 * Creates a new <code>DefaultEditor</code> object.
87 * @param spinner the <code>JSpinner</code> associated with this editor
89 public DefaultEditor(JSpinner spinner
)
93 this.spinner
= spinner
;
94 ftf
= new JFormattedTextField();
96 ftf
.setValue(spinner
.getValue());
97 spinner
.addChangeListener(this);
101 * Returns the <code>JSpinner</code> object for this editor.
103 public JSpinner
getSpinner()
111 public void commitEdit() throws ParseException
113 // TODO: Implement this properly.
119 * @param spinner DOCUMENT ME!
121 public void dismiss(JSpinner spinner
)
123 spinner
.removeChangeListener(this);
129 * @return DOCUMENT ME!
131 public JFormattedTextField
getTextField()
139 * @param parent DOCUMENT ME!
141 public void layoutContainer(Container parent
)
143 Insets insets
= getInsets();
144 Dimension size
= getSize();
145 ftf
.setBounds(insets
.left
, insets
.top
,
146 size
.width
- insets
.left
- insets
.right
,
147 size
.height
- insets
.top
- insets
.bottom
);
153 * @param parent DOCUMENT ME!
155 * @return DOCUMENT ME!
157 public Dimension
minimumLayoutSize(Container parent
)
159 Insets insets
= getInsets();
160 Dimension minSize
= ftf
.getMinimumSize();
161 return new Dimension(minSize
.width
+ insets
.left
+ insets
.right
,
162 minSize
.height
+ insets
.top
+ insets
.bottom
);
168 * @param parent DOCUMENT ME!
170 * @return DOCUMENT ME!
172 public Dimension
preferredLayoutSize(Container parent
)
174 Insets insets
= getInsets();
175 Dimension prefSize
= ftf
.getPreferredSize();
176 return new Dimension(prefSize
.width
+ insets
.left
+ insets
.right
,
177 prefSize
.height
+ insets
.top
+ insets
.bottom
);
183 * @param event DOCUMENT ME!
185 public void propertyChange(PropertyChangeEvent event
)
187 // TODO: Implement this properly.
193 * @param event DOCUMENT ME!
195 public void stateChanged(ChangeEvent event
)
197 // TODO: Implement this properly.
200 public void removeLayoutComponent(Component child
)
202 // Nothing to do here.
208 * @param name DOCUMENT ME!
209 * @param child DOCUMENT ME!
211 public void addLayoutComponent(String name
, Component child
)
213 // Nothing to do here.
220 public static class NumberEditor
extends DefaultEditor
223 * For compatability with Sun's JDK
225 private static final long serialVersionUID
= 3791956183098282942L;
228 * Creates a new NumberEditor object.
230 * @param spinner DOCUMENT ME!
232 public NumberEditor(JSpinner spinner
)
238 * Creates a new NumberEditor object.
240 * @param spinner DOCUMENT ME!
242 public NumberEditor(JSpinner spinner
, String decimalFormatPattern
)
250 * @return DOCUMENT ME!
252 public DecimalFormat
getFormat()
257 public SpinnerNumberModel
getModel()
259 return (SpinnerNumberModel
) getSpinner().getModel();
264 * A <code>JSpinner</code> editor used for the {@link SpinnerListModel}.
265 * This editor uses a <code>JFormattedTextField</code> to edit the values
268 * @author Roman Kennke (kennke@aicas.com)
270 public static class ListEditor
extends DefaultEditor
273 * Creates a new instance of <code>ListEditor</code>.
275 * @param spinner the spinner for which this editor is used
277 public ListEditor(JSpinner spinner
)
282 public SpinnerListModel
getModel()
284 return (SpinnerListModel
) getSpinner().getModel();
289 * An editor class for a <code>JSpinner</code> that is used
290 * for displaying and editing dates (e.g. that uses
291 * <code>SpinnerDateModel</code> as model).
293 * The editor uses a {@link JTextField} with the value
294 * displayed by a {@link DateFormatter} instance.
296 public static class DateEditor
extends DefaultEditor
299 /** The serialVersionUID. */
300 private static final long serialVersionUID
= -4279356973770397815L;
302 /** The DateFormat instance used to format the date. */
303 SimpleDateFormat dateFormat
;
306 * Creates a new instance of DateEditor for the specified
307 * <code>JSpinner</code>.
309 * @param spinner the <code>JSpinner</code> for which to
310 * create a <code>DateEditor</code> instance
312 public DateEditor(JSpinner spinner
)
315 init(new SimpleDateFormat());
319 * Creates a new instance of DateEditor for the specified
320 * <code>JSpinner</code> using the specified date format
323 * @param spinner the <code>JSpinner</code> for which to
324 * create a <code>DateEditor</code> instance
325 * @param dateFormatPattern the date format to use
327 * @see SimpleDateFormat#SimpleDateFormat(String)
329 public DateEditor(JSpinner spinner
, String dateFormatPattern
)
332 init(new SimpleDateFormat(dateFormatPattern
));
336 * Initializes the JFormattedTextField for this editor.
338 * @param format the date format to use in the formatted text field
340 private void init(SimpleDateFormat format
)
343 getTextField().setFormatterFactory(
344 new JFormattedTextField
.AbstractFormatterFactory()
346 public JFormattedTextField
.AbstractFormatter
347 getFormatter(JFormattedTextField ftf
)
349 return new DateFormatter(dateFormat
);
355 * Returns the <code>SimpleDateFormat</code> instance that is used to
356 * format the date value.
358 * @return the <code>SimpleDateFormat</code> instance that is used to
359 * format the date value
361 public SimpleDateFormat
getFormat()
367 * Returns the {@link SpinnerDateModel} that is edited by this editor.
369 * @return the <code>SpinnerDateModel</code> that is edited by this editor
371 public SpinnerDateModel
getModel()
373 return (SpinnerDateModel
) getSpinner().getModel();
377 private static final long serialVersionUID
= 3412663575706551720L;
380 private SpinnerModel model
;
383 private JComponent editor
;
386 private ChangeListener listener
= new ChangeListener()
388 public void stateChanged(ChangeEvent evt
)
395 * Creates a JSpinner with <code>SpinnerNumberModel</code>
397 * @see javax.swing.SpinnerNumberModel
401 this(new SpinnerNumberModel());
405 * Creates a JSpinner with the specific model and sets the default editor
407 * @param model DOCUMENT ME!
409 public JSpinner(SpinnerModel model
)
412 model
.addChangeListener(listener
);
413 setEditor(createEditor(model
));
418 * If the editor is <code>JSpinner.DefaultEditor</code>, then forwards the
419 * call to it, otherwise do nothing.
421 * @throws ParseException DOCUMENT ME!
423 public void commitEdit() throws ParseException
425 if (editor
instanceof DefaultEditor
)
426 ((DefaultEditor
) editor
).commitEdit();
430 * Gets the current editor
432 * @return the current editor
436 public JComponent
getEditor()
442 * Changes the current editor to the new editor. This methods should remove
443 * the old listeners (if any) and adds the new listeners (if any).
445 * @param editor the new editor
447 * @throws IllegalArgumentException DOCUMENT ME!
451 public void setEditor(JComponent editor
)
454 throw new IllegalArgumentException("editor may not be null");
456 if (this.editor
instanceof DefaultEditor
)
457 ((DefaultEditor
) editor
).dismiss(this);
458 else if (this.editor
instanceof ChangeListener
)
459 removeChangeListener((ChangeListener
) this.editor
);
461 if (editor
instanceof ChangeListener
)
462 addChangeListener((ChangeListener
) editor
);
464 this.editor
= editor
;
468 * Gets the underly model.
470 * @return the underly model
472 public SpinnerModel
getModel()
478 * Sets a new underlying model.
480 * @param newModel the new model to set
482 * @exception IllegalArgumentException if newModel is <code>null</code>
484 public void setModel(SpinnerModel newModel
)
486 if (newModel
== null)
487 throw new IllegalArgumentException();
489 if (model
== newModel
)
492 SpinnerModel oldModel
= model
;
494 firePropertyChange("model", oldModel
, newModel
);
497 setEditor(createEditor(model
));
501 * Gets the next value without changing the current value.
503 * @return the next value
505 * @see javax.swing.SpinnerModel#getNextValue
507 public Object
getNextValue()
509 return model
.getNextValue();
513 * Gets the previous value without changing the current value.
515 * @return the previous value
517 * @see javax.swing.SpinnerModel#getPreviousValue
519 public Object
getPreviousValue()
521 return model
.getPreviousValue();
525 * Gets the <code>SpinnerUI</code> that handles this spinner
527 * @return the <code>SpinnerUI</code>
529 public SpinnerUI
getUI()
531 return (SpinnerUI
) ui
;
535 * Gets the current value of the spinner, according to the underly model,
538 * @return the current value
540 * @see javax.swing.SpinnerModel#getValue
542 public Object
getValue()
544 return model
.getValue();
550 * @param value DOCUMENT ME!
552 public void setValue(Object value
)
554 model
.setValue(value
);
558 * This method returns a name to identify which look and feel class will be
559 * the UI delegate for this spinner.
561 * @return The UIClass identifier. "SpinnerUI"
563 public String
getUIClassID()
569 * This method resets the spinner's UI delegate to the default UI for the
570 * current look and feel.
572 public void updateUI()
574 setUI((SpinnerUI
) UIManager
.getUI(this));
578 * This method sets the spinner's UI delegate.
580 * @param ui The spinner's UI delegate.
582 public void setUI(SpinnerUI ui
)
588 * Adds a <code>ChangeListener</code>
590 * @param listener the listener to add
592 public void addChangeListener(ChangeListener listener
)
594 listenerList
.add(ChangeListener
.class, listener
);
598 * Remove a particular listener
600 * @param listener the listener to remove
602 public void removeChangeListener(ChangeListener listener
)
604 listenerList
.remove(ChangeListener
.class, listener
);
608 * Gets all the <code>ChangeListener</code>s
610 * @return all the <code>ChangeListener</code>s
612 public ChangeListener
[] getChangeListeners()
614 return (ChangeListener
[]) listenerList
.getListeners(ChangeListener
.class);
618 * Fires a <code>ChangeEvent</code> to all the <code>ChangeListener</code>s
619 * added to this <code>JSpinner</code>
621 protected void fireStateChanged()
623 ChangeEvent evt
= new ChangeEvent(this);
624 ChangeListener
[] listeners
= getChangeListeners();
626 for (int i
= 0; i
< listeners
.length
; ++i
)
627 listeners
[i
].stateChanged(evt
);
631 * Creates an editor for this <code>JSpinner</code>. Really, it should be a
632 * <code>JSpinner.DefaultEditor</code>, but since that should be
633 * implemented by a JFormattedTextField, and one is not written, I am just
634 * using a dummy one backed by a JLabel.
636 * @param model DOCUMENT ME!
638 * @return the default editor
640 protected JComponent
createEditor(SpinnerModel model
)
642 if (model
instanceof SpinnerDateModel
)
643 return new DateEditor(this);
644 else if (model
instanceof SpinnerNumberModel
)
645 return new NumberEditor(this);
647 return new DefaultEditor(this);