Am Mittwoch, den 15.02.2006, 16:32 +0000 schrieb David Gilbert: > Hi, > > This patch makes our JSpinner usable (it was broken) and more compatible with > the > reference implementation (I added a lot of Mauve tests to ensure this). I > also > added a small demo app that I used for basic testing:
Wow! Good work you do. :-) The demo is quite impressive. Is it linked
into the activity board (replace that old Spinner demo)?
Thank you very much for this, this has long been broken.
Cheers, Roman
> 2006-02-15 David Gilbert <[EMAIL PROTECTED]>
>
> * javax/swing/JSpinner.java
> (DefaultEditor.DefaultEditor(JSpinner)): Add self to text field as a
> PropertyChangeListener,
> (DefaultEditor.getSpinner): Updated API docs,
> (DefaultEditor.dismiss): Likewise,
> (DefaultEditor.getTextField): Likewise,
> (DefaultEditor.layoutContainer): Likewise,
> (DefaultEditor.minimumLayoutSize): Likewise,
> (DefaultEditor.preferredLayoutSize): Likewise,
> (DefaultEditor.propertyChange): Implemented,
> (DefaultEditor.stateChanged): Implemented,
> (DefaultEditor.removeLayoutComponent): Updated API docs,
> (DefaultEditor.addLayoutComponent): Likewise,
> (NumberEditor.NumberEditor(JSpinner)): Set formatter for text field,
> (NumberEditor.NumberEditor(JSpinner, String)): Likewise,
> (NumberEditor.getFormat): Implemented,
> (NumberEditor.getModel): Updated API docs,
> (NumberEditorFormatter): New static inner class,
> (ListEditor.getModel): Updated API docs,
> (DateEditor.dateFormat): Removed,
> (DateEditor.DateEditor(JSpinner)): Set formatter for text field,
> (DateEditor.DateEditor(JSpinner, String)): Likewise,
> (DateEditor.init): Removed,
> (DateEditor.getFormat): Reimplemented,
> (DateEditorFormatter): New static inner class,
> (ModelListener): New inner class,
> (model): Updated API docs,
> (editor): Likewise,
> (listener): Removed,
> (JSpinner()): Updated API docs,
> (JSpinner(SpinnerModel)): Set up ModelListener,
> (setEditor): Fire property change,
> (getModel): Updated API docs,
> (setModel): Removed check for null editor,
> (setValue): Updated API docs,
> (getUIClassID): Updated API docs,
> (createEditor): Handle SpinnerListModel case,
> * javax/swing/plaf/basic/BasicSpinnerUI.java
> (createUI): Updated API docs,
> (createPropertyChangeListener): Added FIXME,
> (installDefaults): Set text field border to null,
> (DefaultLayoutManager): Updated API docs,
> (DefaultLayoutManager.layoutContainer): Modified layout,
> (DefaultLayoutManager.minimumLayoutSize): Ignore button heights,
> (DefaultLayoutManager.preferredLayoutSize): Likewise,
> (DefaultLayoutManager.removeLayoutComponent): Removed tabs,
> (DefaultLayoutManager.addLayoutComponent): Likewise,
> (DefaultLayoutManager.minSize): Renamed prefSize,
> (DefaultLayoutManager.setBounds): Reformatted,
> (DefaultLayoutManager.editor): Added API docs,
> (DefaultLayoutManager.next): Likewise,
> (DefaultLayoutManager.previous): Likewise,
> * javax/swing/plaf/metal/MetalLookAndFeel.java
> (initComponentDefaults): Added entry for 'Spinner.border',
> * examples/gnu/classpath/examples/swing/SpinnerDemo.java: New file.
>
> There is still some work to do on this (e.g. font settings aren't reflected
> in the
> UI yet, setting the component to disabled doesn't work, etc.)...
>
> Regards,
>
> Dave
> einfaches Textdokument-Anlage (diff.txt)
> Index: examples/gnu/classpath/examples/swing/SpinnerDemo.java
> ===================================================================
> RCS file: examples/gnu/classpath/examples/swing/SpinnerDemo.java
> diff -N examples/gnu/classpath/examples/swing/SpinnerDemo.java
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ examples/gnu/classpath/examples/swing/SpinnerDemo.java 15 Feb 2006
> 15:57:19 -0000
> @@ -0,0 +1,230 @@
> +/* SpinnerDemo.java -- An example showing various spinners in Swing.
> + Copyright (C) 2006, Free Software Foundation, Inc.
> +
> +This file is part of GNU Classpath examples.
> +
> +GNU Classpath is free software; you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation; either version 2, or (at your option)
> +any later version.
> +
> +GNU Classpath 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 for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GNU Classpath; see the file COPYING. If not, write to the
> +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> +02110-1301 USA.
> +*/
> +
> +
> +package gnu.classpath.examples.swing;
> +
> +import java.awt.BorderLayout;
> +import java.awt.Font;
> +import java.awt.GridLayout;
> +import java.awt.event.ActionEvent;
> +import java.awt.event.ActionListener;
> +import java.util.Calendar;
> +import java.util.Date;
> +
> +import javax.swing.BorderFactory;
> +import javax.swing.JButton;
> +import javax.swing.JCheckBox;
> +import javax.swing.JFrame;
> +import javax.swing.JPanel;
> +import javax.swing.JSpinner;
> +import javax.swing.SpinnerDateModel;
> +import javax.swing.SpinnerListModel;
> +import javax.swing.SpinnerNumberModel;
> +import javax.swing.UIManager;
> +import javax.swing.plaf.metal.DefaultMetalTheme;
> +import javax.swing.plaf.metal.MetalLookAndFeel;
> +
> +/**
> + * A simple demo showing various spinners in different states.
> + */
> +public class SpinnerDemo
> + extends JFrame
> + implements ActionListener
> +{
> + private JPanel content;
> + private JCheckBox spinnerState1;
> + private JSpinner spinner1;
> + private JSpinner spinner2;
> +
> + private JCheckBox spinnerState2;
> + private JSpinner spinner3;
> + private JSpinner spinner4;
> +
> + private JCheckBox spinnerState3;
> + private JSpinner spinner5;
> + private JSpinner spinner6;
> +
> + /**
> + * Creates a new demo instance.
> + *
> + * @param title the frame title.
> + */
> + public SpinnerDemo(String title)
> + {
> + super(title);
> + JPanel content = createContent();
> + // initFrameContent() is only called (from main) when running this app
> + // standalone
> + }
> +
> + /**
> + * When the demo is run independently, the frame is displayed, so we should
> + * initialise the content panel (including the demo content and a close
> + * button). But when the demo is run as part of the Swing activity board,
> + * only the demo content panel is used, the frame itself is never
> displayed,
> + * so we can avoid this step.
> + */
> + public void initFrameContent()
> + {
> + JPanel closePanel = new JPanel();
> + JButton closeButton = new JButton("Close");
> + closeButton.setActionCommand("CLOSE");
> + closeButton.addActionListener(this);
> + closePanel.add(closeButton);
> + content.add(closePanel, BorderLayout.SOUTH);
> + getContentPane().add(content);
> + }
> +
> + /**
> + * Returns a panel with the demo content. The panel
> + * uses a BorderLayout(), and the BorderLayout.SOUTH area
> + * is empty, to allow callers to add controls to the
> + * bottom of the panel if they want to (a close button is
> + * added if this demo is being run as a standalone demo).
> + */
> + JPanel createContent()
> + {
> + if (content == null)
> + {
> + content = new JPanel(new BorderLayout());
> + JPanel panel = new JPanel(new GridLayout(3, 1));
> + panel.add(createPanel1());
> + panel.add(createPanel2());
> + panel.add(createPanel3());
> + content.add(panel);
> + }
> + return content;
> + }
> +
> + private JPanel createPanel1()
> + {
> + JPanel panel = new JPanel(new BorderLayout());
> + this.spinnerState1 = new JCheckBox("Enabled", true);
> + this.spinnerState1.setActionCommand("COMBO_STATE1");
> + this.spinnerState1.addActionListener(this);
> + panel.add(this.spinnerState1, BorderLayout.EAST);
> +
> + JPanel controlPanel = new JPanel();
> + controlPanel.setBorder(BorderFactory.createTitledBorder(
> + "Number Spinner: "));
> + this.spinner1 = new JSpinner(new SpinnerNumberModel(5.0, 0.0, 10.0,
> 0.5));
> + this.spinner2 = new JSpinner(new SpinnerNumberModel(50, 0, 100, 5));
> + this.spinner2.setFont(new Font("Dialog", Font.PLAIN, 20));
> + controlPanel.add(this.spinner1);
> + controlPanel.add(this.spinner2);
> +
> + panel.add(controlPanel);
> +
> + return panel;
> + }
> +
> + private JPanel createPanel2()
> + {
> + JPanel panel = new JPanel(new BorderLayout());
> + this.spinnerState2 = new JCheckBox("Enabled", true);
> + this.spinnerState2.setActionCommand("COMBO_STATE2");
> + this.spinnerState2.addActionListener(this);
> + panel.add(this.spinnerState2, BorderLayout.EAST);
> +
> + JPanel controlPanel = new JPanel();
> + controlPanel.setBorder(BorderFactory.createTitledBorder("Date Spinner:
> "));
> + this.spinner3 = new JSpinner(new SpinnerDateModel(new Date(), null,
> null,
> + Calendar.DATE));
> +
> + this.spinner4 = new JSpinner(new SpinnerDateModel(new Date(), null,
> null,
> + Calendar.YEAR));
> + this.spinner4.setFont(new Font("Dialog", Font.PLAIN, 20));
> +
> + controlPanel.add(this.spinner3);
> + controlPanel.add(this.spinner4);
> +
> + panel.add(controlPanel);
> +
> + return panel;
> + }
> +
> + private JPanel createPanel3()
> + {
> + JPanel panel = new JPanel(new BorderLayout());
> + this.spinnerState3 = new JCheckBox("Enabled", true);
> + this.spinnerState3.setActionCommand("COMBO_STATE3");
> + this.spinnerState3.addActionListener(this);
> + panel.add(this.spinnerState3, BorderLayout.EAST);
> +
> + JPanel controlPanel = new JPanel();
> + controlPanel.setBorder(BorderFactory.createTitledBorder("List Spinner:
> "));
> + this.spinner5 = new JSpinner(new SpinnerListModel(new Object[] {"Red",
> + "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet"}));
> +
> + this.spinner6 = new JSpinner(new SpinnerListModel(new Object[] {"Red",
> + "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet"}));
> + this.spinner6.setValue("Yellow");
> + this.spinner6.setFont(new Font("Dialog", Font.PLAIN, 20));
> +
> + controlPanel.add(this.spinner5);
> + controlPanel.add(this.spinner6);
> +
> + panel.add(controlPanel);
> +
> + return panel;
> + }
> +
> + public void actionPerformed(ActionEvent e)
> + {
> + if (e.getActionCommand().equals("COMBO_STATE1"))
> + {
> + spinner1.setEnabled(spinnerState1.isSelected());
> + spinner2.setEnabled(spinnerState1.isSelected());
> + }
> + else if (e.getActionCommand().equals("COMBO_STATE2"))
> + {
> + spinner3.setEnabled(spinnerState2.isSelected());
> + spinner4.setEnabled(spinnerState2.isSelected());
> + }
> + else if (e.getActionCommand().equals("COMBO_STATE3"))
> + {
> + spinner5.setEnabled(spinnerState3.isSelected());
> + spinner6.setEnabled(spinnerState3.isSelected());
> + }
> + else if (e.getActionCommand().equals("CLOSE"))
> + {
> + System.exit(0);
> + }
> + }
> +
> + public static void main(String[] args)
> + {
> + try
> + {
> + MetalLookAndFeel.setCurrentTheme(new DefaultMetalTheme());
> + UIManager.setLookAndFeel(new
> javax.swing.plaf.metal.MetalLookAndFeel());
> + }
> + catch (Exception e) {
> + e.printStackTrace();
> + }
> + SpinnerDemo app = new SpinnerDemo("Spinner Demo");
> + app.initFrameContent();
> + app.pack();
> + app.setVisible(true);
> + }
> +
> +}
> Index: javax/swing/JSpinner.java
> ===================================================================
> RCS file: /sources/classpath/classpath/javax/swing/JSpinner.java,v
> retrieving revision 1.14
> diff -u -r1.14 JSpinner.java
> --- javax/swing/JSpinner.java 19 Oct 2005 15:45:04 -0000 1.14
> +++ javax/swing/JSpinner.java 15 Feb 2006 15:57:29 -0000
> @@ -1,5 +1,5 @@
> /* JSpinner.java --
> - Copyright (C) 2004, 2005 Free Software Foundation, Inc.
> + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
>
> This file is part of GNU Classpath.
>
> @@ -45,7 +45,9 @@
> import java.awt.LayoutManager;
> import java.beans.PropertyChangeEvent;
> import java.beans.PropertyChangeListener;
> +import java.text.DateFormat;
> import java.text.DecimalFormat;
> +import java.text.NumberFormat;
> import java.text.ParseException;
> import java.text.SimpleDateFormat;
>
> @@ -53,10 +55,15 @@
> import javax.swing.event.ChangeListener;
> import javax.swing.plaf.SpinnerUI;
> import javax.swing.text.DateFormatter;
> +import javax.swing.text.DefaultFormatterFactory;
> +import javax.swing.text.NumberFormatter;
>
> /**
> - * A JSpinner is a component which typically contains a numeric value and a
> - * way to manipulate the value.
> + * A <code>JSpinner</code> is a component that displays a single value from
> + * a sequence of values, and provides a convenient means for selecting the
> + * previous and next values in the sequence. Typically the spinner displays
> + * a numeric value, but it is possible to display dates or arbitrary items
> + * from a list.
> *
> * @author Ka-Hing Cheung
> *
> @@ -65,12 +72,15 @@
> public class JSpinner extends JComponent
> {
> /**
> - * DOCUMENT ME!
> - */
> - public static class DefaultEditor extends JPanel implements ChangeListener,
> -
> PropertyChangeListener,
> - LayoutManager
> + * The base class for the editor used by the [EMAIL PROTECTED] JSpinner}
> component.
> + * The editor is in fact a panel containing a [EMAIL PROTECTED]
> JFormattedTextField}
> + * component.
> + */
> + public static class DefaultEditor
> + extends JPanel
> + implements ChangeListener, PropertyChangeListener, LayoutManager
> {
> + /** The spinner that the editor is allocated to. */
> private JSpinner spinner;
>
> /** The JFormattedTextField that backs the editor. */
> @@ -82,7 +92,8 @@
> private static final long serialVersionUID = -5317788736173368172L;
>
> /**
> - * Creates a new <code>DefaultEditor</code> object.
> + * Creates a new <code>DefaultEditor</code> object. The editor is
> + * registered with the spinner as a [EMAIL PROTECTED] ChangeListener}
> here.
> *
> * @param spinner the <code>JSpinner</code> associated with this editor
> */
> @@ -94,11 +105,15 @@
> ftf = new JFormattedTextField();
> add(ftf);
> ftf.setValue(spinner.getValue());
> + ftf.addPropertyChangeListener(this);
> spinner.addChangeListener(this);
> }
>
> /**
> - * Returns the <code>JSpinner</code> object for this editor.
> + * Returns the <code>JSpinner</code> component that the editor is
> assigned
> + * to.
> + *
> + * @return The spinner that the editor is assigned to.
> */
> public JSpinner getSpinner()
> {
> @@ -114,9 +129,10 @@
> }
>
> /**
> - * DOCUMENT ME!
> + * Removes the editor from the [EMAIL PROTECTED] ChangeListener} list
> maintained by
> + * the specified <code>spinner</code>.
> *
> - * @param spinner DOCUMENT ME!
> + * @param spinner the spinner (<code>null</code> not permitted).
> */
> public void dismiss(JSpinner spinner)
> {
> @@ -124,9 +140,10 @@
> }
>
> /**
> - * DOCUMENT ME!
> + * Returns the text field used to display and edit the current value in
> + * the spinner.
> *
> - * @return DOCUMENT ME!
> + * @return The text field.
> */
> public JFormattedTextField getTextField()
> {
> @@ -134,9 +151,10 @@
> }
>
> /**
> - * DOCUMENT ME!
> + * Sets the bounds for the child components in this container. In this
> + * case, the text field is the only component to be laid out.
> *
> - * @param parent DOCUMENT ME!
> + * @param parent the parent container.
> */
> public void layoutContainer(Container parent)
> {
> @@ -148,11 +166,13 @@
> }
>
> /**
> - * DOCUMENT ME!
> + * Calculates the minimum size for this component. In this case, the
> + * text field is the only subcomponent, so the return value is the
> minimum
> + * size of the text field plus the insets of this component.
> *
> - * @param parent DOCUMENT ME!
> + * @param parent the parent container.
> *
> - * @return DOCUMENT ME!
> + * @return The minimum size.
> */
> public Dimension minimumLayoutSize(Container parent)
> {
> @@ -163,11 +183,13 @@
> }
>
> /**
> - * DOCUMENT ME!
> + * Calculates the preferred size for this component. In this case, the
> + * text field is the only subcomponent, so the return value is the
> + * preferred size of the text field plus the insets of this component.
> *
> - * @param parent DOCUMENT ME!
> + * @param parent the parent container.
> *
> - * @return DOCUMENT ME!
> + * @return The preferred size.
> */
> public Dimension preferredLayoutSize(Container parent)
> {
> @@ -178,35 +200,51 @@
> }
>
> /**
> - * DOCUMENT ME!
> + * Receives notification of property changes. If the text field's
> 'value'
> + * property changes, the spinner's model is updated accordingly.
> *
> - * @param event DOCUMENT ME!
> + * @param event the event.
> */
> public void propertyChange(PropertyChangeEvent event)
> {
> - // TODO: Implement this properly.
> + if (event.getSource() == ftf)
> + {
> + if (event.getPropertyName().equals("value"))
> + spinner.getModel().setValue(event.getNewValue());
> + }
> }
>
> /**
> - * DOCUMENT ME!
> + * Receives notification of changes in the state of the [EMAIL
> PROTECTED] JSpinner}
> + * that the editor belongs to - the content of the text field is updated
> + * accordingly.
> *
> - * @param event DOCUMENT ME!
> + * @param event the change event.
> */
> public void stateChanged(ChangeEvent event)
> {
> - // TODO: Implement this properly.
> + ftf.setValue(spinner.getValue());
> }
>
> + /**
> + * This method does nothing. It is required by the [EMAIL PROTECTED]
> LayoutManager}
> + * interface, but since this component has a single child, there is no
> + * need to use this method.
> + *
> + * @param child the child component to remove.
> + */
> public void removeLayoutComponent(Component child)
> {
> // Nothing to do here.
> }
>
> /**
> - * DOCUMENT ME!
> - *
> - * @param name DOCUMENT ME!
> - * @param child DOCUMENT ME!
> + * This method does nothing. It is required by the [EMAIL PROTECTED]
> LayoutManager}
> + * interface, but since this component has a single child, there is no
> + * need to use this method.
> + *
> + * @param name the name.
> + * @param child the child component to add.
> */
> public void addLayoutComponent(String name, Component child)
> {
> @@ -215,7 +253,11 @@
> }
>
> /**
> - * DOCUMENT ME!
> + * A panel containing a [EMAIL PROTECTED] JFormattedTextField} that is
> configured for
> + * displaying and editing numbers. The panel is used as a subcomponent of
> + * a [EMAIL PROTECTED] JSpinner}.
> + *
> + * @see JSpinner#createEditor(SpinnerModel)
> */
> public static class NumberEditor extends DefaultEditor
> {
> @@ -225,40 +267,72 @@
> private static final long serialVersionUID = 3791956183098282942L;
>
> /**
> - * Creates a new NumberEditor object.
> + * Creates a new <code>NumberEditor</code> object for the specified
> + * <code>spinner</code>. The editor is registered with the spinner as a
> + * [EMAIL PROTECTED] ChangeListener}.
> *
> - * @param spinner DOCUMENT ME!
> + * @param spinner the component the editor will be used with.
> */
> public NumberEditor(JSpinner spinner)
> {
> super(spinner);
> + NumberEditorFormatter nef = new NumberEditorFormatter();
> + nef.setMinimum(getModel().getMinimum());
> + nef.setMaximum(getModel().getMaximum());
> + ftf.setFormatterFactory(new DefaultFormatterFactory(nef));
> }
>
> /**
> - * Creates a new NumberEditor object.
> + * Creates a new <code>NumberEditor</code> object.
> *
> - * @param spinner DOCUMENT ME!
> + * @param spinner the spinner.
> + * @param decimalFormatPattern the number format pattern.
> */
> public NumberEditor(JSpinner spinner, String decimalFormatPattern)
> {
> super(spinner);
> + NumberEditorFormatter nef
> + = new NumberEditorFormatter(decimalFormatPattern);
> + nef.setMinimum(getModel().getMinimum());
> + nef.setMaximum(getModel().getMaximum());
> + ftf.setFormatterFactory(new DefaultFormatterFactory(nef));
> }
>
> /**
> - * DOCUMENT ME!
> + * Returns the format used by the text field.
> *
> - * @return DOCUMENT ME!
> + * @return The format used by the text field.
> */
> public DecimalFormat getFormat()
> {
> - return null;
> + NumberFormatter formatter = (NumberFormatter) ftf.getFormatter();
> + return (DecimalFormat) formatter.getFormat();
> }
>
> + /**
> + * Returns the model used by the editor's [EMAIL PROTECTED] JSpinner}
> component,
> + * cast to a [EMAIL PROTECTED] SpinnerNumberModel}.
> + *
> + * @return The model.
> + */
> public SpinnerNumberModel getModel()
> {
> return (SpinnerNumberModel) getSpinner().getModel();
> }
> }
> +
> + static class NumberEditorFormatter
> + extends NumberFormatter
> + {
> + public NumberEditorFormatter()
> + {
> + super(NumberFormat.getInstance());
> + }
> + public NumberEditorFormatter(String decimalFormatPattern)
> + {
> + super(new DecimalFormat(decimalFormatPattern));
> + }
> + }
>
> /**
> * A <code>JSpinner</code> editor used for the [EMAIL PROTECTED]
> SpinnerListModel}.
> @@ -279,6 +353,11 @@
> super(spinner);
> }
>
> + /**
> + * Returns the spinner's model cast as a [EMAIL PROTECTED]
> SpinnerListModel}.
> + *
> + * @return The spinner's model.
> + */
> public SpinnerListModel getModel()
> {
> return (SpinnerListModel) getSpinner().getModel();
> @@ -299,9 +378,6 @@
> /** The serialVersionUID. */
> private static final long serialVersionUID = -4279356973770397815L;
>
> - /** The DateFormat instance used to format the date. */
> - SimpleDateFormat dateFormat;
> -
> /**
> * Creates a new instance of DateEditor for the specified
> * <code>JSpinner</code>.
> @@ -312,7 +388,10 @@
> public DateEditor(JSpinner spinner)
> {
> super(spinner);
> - init(new SimpleDateFormat());
> + DateEditorFormatter nef = new DateEditorFormatter();
> + nef.setMinimum(getModel().getStart());
> + nef.setMaximum(getModel().getEnd());
> + ftf.setFormatterFactory(new DefaultFormatterFactory(nef));
> }
>
> /**
> @@ -329,26 +408,10 @@
> public DateEditor(JSpinner spinner, String dateFormatPattern)
> {
> super(spinner);
> - init(new SimpleDateFormat(dateFormatPattern));
> - }
> -
> - /**
> - * Initializes the JFormattedTextField for this editor.
> - *
> - * @param format the date format to use in the formatted text field
> - */
> - private void init(SimpleDateFormat format)
> - {
> - dateFormat = format;
> - getTextField().setFormatterFactory(
> - new JFormattedTextField.AbstractFormatterFactory()
> - {
> - public JFormattedTextField.AbstractFormatter
> - getFormatter(JFormattedTextField ftf)
> - {
> - return new DateFormatter(dateFormat);
> - }
> - });
> + DateEditorFormatter nef = new DateEditorFormatter(dateFormatPattern);
> + nef.setMinimum(getModel().getStart());
> + nef.setMaximum(getModel().getEnd());
> + ftf.setFormatterFactory(new DefaultFormatterFactory(nef));
> }
>
> /**
> @@ -360,7 +423,8 @@
> */
> public SimpleDateFormat getFormat()
> {
> - return dateFormat;
> + DateFormatter formatter = (DateFormatter) ftf.getFormatter();
> + return (SimpleDateFormat) formatter.getFormat();
> }
>
> /**
> @@ -374,25 +438,59 @@
> }
> }
>
> - private static final long serialVersionUID = 3412663575706551720L;
> + static class DateEditorFormatter
> + extends DateFormatter
> + {
> + public DateEditorFormatter()
> + {
> + super(DateFormat.getInstance());
> + }
> + public DateEditorFormatter(String dateFormatPattern)
> + {
> + super(new SimpleDateFormat(dateFormatPattern));
> + }
> + }
>
> - /** DOCUMENT ME! */
> + /**
> + * A listener that forwards [EMAIL PROTECTED] ChangeEvent} notifications
> from the model
> + * to the [EMAIL PROTECTED] JSpinner}'s listeners.
> + */
> + class ModelListener implements ChangeListener
> + {
> + /**
> + * Creates a new listener.
> + */
> + public ModelListener()
> + {
> + // nothing to do here
> + }
> +
> + /**
> + * Receives notification from the model that its state has changed.
> + *
> + * @param event the event (ignored).
> + */
> + public void stateChanged(ChangeEvent event)
> + {
> + fireStateChanged();
> + }
> + }
> +
> + /**
> + * The model that defines the current value and permitted values for the
> + * spinner.
> + */
> private SpinnerModel model;
>
> - /** DOCUMENT ME! */
> + /** The current editor. */
> private JComponent editor;
>
> - /** DOCUMENT ME! */
> - private ChangeListener listener = new ChangeListener()
> - {
> - public void stateChanged(ChangeEvent evt)
> - {
> - fireStateChanged();
> - }
> - };
> + private static final long serialVersionUID = 3412663575706551720L;
>
> /**
> - * Creates a JSpinner with <code>SpinnerNumberModel</code>
> + * Creates a new <code>JSpinner</code> with default instance of
> + * [EMAIL PROTECTED] SpinnerNumberModel} (that is, a model with value 0,
> step size 1,
> + * and no upper or lower limit).
> *
> * @see javax.swing.SpinnerNumberModel
> */
> @@ -402,15 +500,19 @@
> }
>
> /**
> - * Creates a JSpinner with the specific model and sets the default editor
> - *
> - * @param model DOCUMENT ME!
> + * Creates a new <code>JSpinner with the specified model. The
> + * [EMAIL PROTECTED] #createEditor(SpinnerModel)} method is used to create
> an editor
> + * that is suitable for the model.
> + *
> + * @param model the model (<code>null</code> not permitted).
> + *
> + * @throws NullPointerException if <code>model</code> is <code>null</code>.
> */
> public JSpinner(SpinnerModel model)
> {
> this.model = model;
> - model.addChangeListener(listener);
> - setEditor(createEditor(model));
> + this.editor = createEditor(model);
> + model.addChangeListener(new ModelListener());
> updateUI();
> }
>
> @@ -439,12 +541,13 @@
> }
>
> /**
> - * Changes the current editor to the new editor. This methods should remove
> - * the old listeners (if any) and adds the new listeners (if any).
> + * Changes the current editor to the new editor. The old editor is
> + * removed from the spinner's [EMAIL PROTECTED] ChangeEvent} list.
> *
> - * @param editor the new editor
> + * @param editor the new editor (<code>null</code> not permitted.
> *
> - * @throws IllegalArgumentException DOCUMENT ME!
> + * @throws IllegalArgumentException if <code>editor</code> is
> + * <code>null</code>.
> *
> * @see #getEditor
> */
> @@ -453,21 +556,22 @@
> if (editor == null)
> throw new IllegalArgumentException("editor may not be null");
>
> - if (this.editor instanceof DefaultEditor)
> - ((DefaultEditor) editor).dismiss(this);
> - else if (this.editor instanceof ChangeListener)
> - removeChangeListener((ChangeListener) this.editor);
> -
> - if (editor instanceof ChangeListener)
> - addChangeListener((ChangeListener) editor);
> -
> + JComponent oldEditor = this.editor;
> + if (oldEditor instanceof DefaultEditor)
> + ((DefaultEditor) oldEditor).dismiss(this);
> + else if (oldEditor instanceof ChangeListener)
> + removeChangeListener((ChangeListener) oldEditor);
> +
> this.editor = editor;
> + firePropertyChange("editor", oldEditor, editor);
> }
>
> /**
> - * Gets the underly model.
> + * Returns the model used by the [EMAIL PROTECTED] JSpinner} component.
> *
> - * @return the underly model
> + * @return The model.
> + *
> + * @see #setModel(SpinnerModel)
> */
> public SpinnerModel getModel()
> {
> @@ -492,9 +596,7 @@
> SpinnerModel oldModel = model;
> model = newModel;
> firePropertyChange("model", oldModel, newModel);
> -
> - if (editor == null)
> - setEditor(createEditor(model));
> + setEditor(createEditor(model));
> }
>
> /**
> @@ -545,9 +647,9 @@
> }
>
> /**
> - * DOCUMENT ME!
> + * Sets the value in the model.
> *
> - * @param value DOCUMENT ME!
> + * @param value the new value.
> */
> public void setValue(Object value)
> {
> @@ -555,10 +657,10 @@
> }
>
> /**
> - * This method returns a name to identify which look and feel class will be
> + * Returns the ID that identifies which look and feel class will be
> * the UI delegate for this spinner.
> *
> - * @return The UIClass identifier. "SpinnerUI"
> + * @return <code>"SpinnerUI"</code>.
> */
> public String getUIClassID()
> {
> @@ -575,7 +677,7 @@
> }
>
> /**
> - * This method sets the spinner's UI delegate.
> + * Sets the UI delegate for the component.
> *
> * @param ui The spinner's UI delegate.
> */
> @@ -628,14 +730,11 @@
> }
>
> /**
> - * Creates an editor for this <code>JSpinner</code>. Really, it should be a
> - * <code>JSpinner.DefaultEditor</code>, but since that should be
> - * implemented by a JFormattedTextField, and one is not written, I am just
> - * using a dummy one backed by a JLabel.
> + * Creates an editor that is appropriate for the specified
> <code>model</code>.
> *
> - * @param model DOCUMENT ME!
> + * @param model the model.
> *
> - * @return the default editor
> + * @return The editor.
> */
> protected JComponent createEditor(SpinnerModel model)
> {
> @@ -643,6 +742,8 @@
> return new DateEditor(this);
> else if (model instanceof SpinnerNumberModel)
> return new NumberEditor(this);
> + else if (model instanceof SpinnerListModel)
> + return new ListEditor(this);
> else
> return new DefaultEditor(this);
> }
> Index: javax/swing/plaf/basic/BasicSpinnerUI.java
> ===================================================================
> RCS file:
> /sources/classpath/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java,v
> retrieving revision 1.7
> diff -u -r1.7 BasicSpinnerUI.java
> --- javax/swing/plaf/basic/BasicSpinnerUI.java 12 Oct 2005 12:10:00
> -0000 1.7
> +++ javax/swing/plaf/basic/BasicSpinnerUI.java 15 Feb 2006 15:57:30
> -0000
> @@ -1,5 +1,5 @@
> -/* SpinnerUI.java --
> - Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
> +/* BasicSpinnerUI.java --
> + Copyright (C) 2003, 2004, 2005, 2006, Free Software Foundation, Inc.
>
> This file is part of GNU Classpath.
>
> @@ -41,6 +41,7 @@
> import java.awt.Component;
> import java.awt.Container;
> import java.awt.Dimension;
> +import java.awt.Font;
> import java.awt.Insets;
> import java.awt.LayoutManager;
> import java.awt.event.ActionEvent;
> @@ -59,22 +60,21 @@
> import javax.swing.plaf.SpinnerUI;
>
> /**
> - * DOCUMENT ME!
> + * A UI delegate for the [EMAIL PROTECTED] JSpinner} component.
> *
> * @author Ka-Hing Cheung
> *
> - * @see javax.swing.JSpinner
> * @since 1.4
> */
> public class BasicSpinnerUI extends SpinnerUI
> {
> /**
> - * Creates a new <code>ComponentUI</code> for the specified
> + * Creates a new <code>BasicSpinnerUI</code> for the specified
> * <code>JComponent</code>
> *
> - * @param c DOCUMENT ME!
> + * @param c the component (ignored).
> *
> - * @return a ComponentUI
> + * @return A new instance of [EMAIL PROTECTED] BasicSpinnerUI}.
> */
> public static ComponentUI createUI(JComponent c)
> {
> @@ -144,14 +144,15 @@
> {
> return new PropertyChangeListener()
> {
> - public void propertyChange(PropertyChangeEvent evt)
> - {
> - // FIXME: Add check for enabled property change. Need to
> - // disable the buttons.
> - if ("editor".equals(evt.getPropertyName()))
> - BasicSpinnerUI.this.replaceEditor((JComponent) evt.getOldValue(),
> - (JComponent) evt.getNewValue());
> - }
> + public void propertyChange(PropertyChangeEvent event)
> + {
> + // FIXME: Add check for enabled property change. Need to
> + // disable the buttons.
> + if ("editor".equals(event.getPropertyName()))
> + BasicSpinnerUI.this.replaceEditor((JComponent)
> event.getOldValue(),
> + (JComponent) event.getNewValue());
> + // FIXME: Handle 'font' property change
> + }
> };
> }
>
> @@ -169,6 +170,12 @@
> LookAndFeel.installColorsAndFont(spinner, "Spinner.background",
> "Spinner.foreground", "Spinner.font");
> LookAndFeel.installBorder(spinner, "Spinner.border");
> + JComponent e = spinner.getEditor();
> + if (e instanceof JSpinner.DefaultEditor)
> + {
> + JSpinner.DefaultEditor de = (JSpinner.DefaultEditor) e;
> + de.getTextField().setBorder(null);
> + }
> spinner.setLayout(createLayout());
> spinner.setOpaque(true);
> }
> @@ -352,7 +359,8 @@
> private PropertyChangeListener listener = createPropertyChangeListener();
>
> /**
> - * DOCUMENT ME!
> + * A layout manager for the [EMAIL PROTECTED] JSpinner} component. The
> spinner has
> + * three subcomponents: an editor, a 'next' button and a 'previous' button.
> */
> private class DefaultLayoutManager implements LayoutManager
> {
> @@ -365,58 +373,52 @@
> {
> synchronized (parent.getTreeLock())
> {
> - Insets i = parent.getInsets();
> - boolean l2r = parent.getComponentOrientation().isLeftToRight();
> - /*
> - -------------- --------------
> - | | n | | n | |
> - | e | - | or | - | e |
> - | | p | | p | |
> - -------------- --------------
> - */
> - Dimension e = minSize(editor);
> - Dimension n = minSize(next);
> - Dimension p = minSize(previous);
> - Dimension s = spinner.getPreferredSize();
> -
> - int x = l2r ? i.left : i.right;
> - int y = i.top;
> - int w = Math.max(p.width, n.width);
> - int h = Math.max(p.height, n.height);
> - h = Math.max(h, e.height / 2);
> - int e_width = s.width - w;
> -
> - if (l2r)
> - {
> - setBounds(editor, x, y + (s.height - e.height) / 2, e_width,
> - e.height);
> - x += e_width;
> -
> - setBounds(next, x, y, w, h);
> - y += h;
> -
> - setBounds(previous, x, y, w, h);
> - }
> - else
> - {
> - setBounds(next, x, y + (s.height - e.height) / 2, w, h);
> - y += h;
> -
> - setBounds(previous, x, y, w, h);
> - x += w;
> - y -= h;
> -
> - setBounds(editor, x, y, e_width, e.height);
> - }
> + Insets i = parent.getInsets();
> + boolean l2r = parent.getComponentOrientation().isLeftToRight();
> + /*
> + -------------- --------------
> + | | n | | n | |
> + | e | - | or | - | e |
> + | | p | | p | |
> + -------------- --------------
> + */
> + Dimension e = prefSize(editor);
> + Dimension n = prefSize(next);
> + Dimension p = prefSize(previous);
> + Dimension s = spinner.getPreferredSize();
> +
> + int x = l2r ? i.left : i.right;
> + int y = i.top;
> + int w = Math.max(p.width, n.width);
> + int h = e.height / 2;
> + int e_width = s.width - w - i.left - i.right;
> +
> + if (l2r)
> + {
> + setBounds(editor, x, y, e_width, 2 * h);
> + x += e_width;
> + setBounds(next, x, y, w, h);
> + y += h;
> + setBounds(previous, x, y, w, h);
> + }
> + else
> + {
> + setBounds(next, x, y + (s.height - e.height) / 2, w, h);
> + y += h;
> + setBounds(previous, x, y + (s.height - e.height) / 2, w, h);
> + x += w;
> + y -= h;
> + setBounds(editor, x, y, e_width, e.height);
> + }
> }
> }
>
> /**
> - * DOCUMENT ME!
> + * Calculates the minimum layout size.
> *
> - * @param parent DOCUMENT ME!
> + * @param parent the parent.
> *
> - * @return DOCUMENT ME!
> + * @return The minimum layout size.
> */
> public Dimension minimumLayoutSize(Container parent)
> {
> @@ -424,36 +426,32 @@
>
> if (editor != null)
> {
> - Dimension tmp = editor.getMinimumSize();
> - d.width += tmp.width;
> - d.height = tmp.height;
> + Dimension tmp = editor.getMinimumSize();
> + d.width += tmp.width;
> + d.height = tmp.height;
> }
>
> int nextWidth = 0;
> int previousWidth = 0;
> - int otherHeight = 0;
>
> if (next != null)
> {
> - Dimension tmp = next.getMinimumSize();
> - nextWidth = tmp.width;
> - otherHeight += tmp.height;
> + Dimension tmp = next.getMinimumSize();
> + nextWidth = tmp.width;
> }
> if (previous != null)
> {
> - Dimension tmp = previous.getMinimumSize();
> - previousWidth = tmp.width;
> - otherHeight += tmp.height;
> + Dimension tmp = previous.getMinimumSize();
> + previousWidth = tmp.width;
> }
>
> - d.height = Math.max(d.height, otherHeight);
> d.width += Math.max(nextWidth, previousWidth);
>
> return d;
> }
>
> /**
> - * DOCUMENT ME!
> + * Returns the preferred layout size of the container.
> *
> * @param parent DOCUMENT ME!
> *
> @@ -465,31 +463,29 @@
>
> if (editor != null)
> {
> - Dimension tmp = editor.getPreferredSize();
> - d.width += Math.max(tmp.width, 40);
> - d.height = tmp.height;
> + Dimension tmp = editor.getPreferredSize();
> + d.width += Math.max(tmp.width, 40);
> + d.height = tmp.height;
> }
>
> int nextWidth = 0;
> int previousWidth = 0;
> - int otherHeight = 0;
>
> if (next != null)
> {
> - Dimension tmp = next.getPreferredSize();
> - nextWidth = tmp.width;
> - otherHeight += tmp.height;
> + Dimension tmp = next.getPreferredSize();
> + nextWidth = tmp.width;
> }
> if (previous != null)
> {
> - Dimension tmp = previous.getPreferredSize();
> - previousWidth = tmp.width;
> - otherHeight += tmp.height;
> + Dimension tmp = previous.getPreferredSize();
> + previousWidth = tmp.width;
> }
>
> - d.height = Math.max(d.height, otherHeight);
> d.width += Math.max(nextWidth, previousWidth);
> -
> + Insets insets = parent.getInsets();
> + d.width = d.width + insets.left + insets.right;
> + d.height = d.height + insets.top + insets.bottom;
> return d;
> }
>
> @@ -501,11 +497,11 @@
> public void removeLayoutComponent(Component child)
> {
> if (child == editor)
> - editor = null;
> + editor = null;
> else if (child == next)
> - next = null;
> + next = null;
> else if (previous == child)
> - previous = null;
> + previous = null;
> }
>
> /**
> @@ -517,11 +513,11 @@
> public void addLayoutComponent(String name, Component child)
> {
> if ("Editor".equals(name))
> - editor = child;
> + editor = child;
> else if ("Next".equals(name))
> - next = child;
> + next = child;
> else if ("Previous".equals(name))
> - previous = child;
> + previous = child;
> }
>
> /**
> @@ -531,36 +527,36 @@
> *
> * @return DOCUMENT ME!
> */
> - private Dimension minSize(Component c)
> + private Dimension prefSize(Component c)
> {
> if (c == null)
> - return new Dimension();
> + return new Dimension();
> else
> - return c.getMinimumSize();
> + return c.getPreferredSize();
> }
>
> /**
> - * DOCUMENT ME!
> + * Sets the bounds for the specified component.
> *
> - * @param c DOCUMENT ME!
> - * @param x DOCUMENT ME!
> - * @param y DOCUMENT ME!
> - * @param w DOCUMENT ME!
> - * @param h DOCUMENT ME!
> + * @param c the component.
> + * @param x the x-coordinate for the top-left of the component bounds.
> + * @param y the y-coordinate for the top-left of the component bounds.
> + * @param w the width of the bounds.
> + * @param h the height of the bounds.
> */
> private void setBounds(Component c, int x, int y, int w, int h)
> {
> if (c != null)
> - c.setBounds(x, y, w, h);
> + c.setBounds(x, y, w, h);
> }
>
> - /** DOCUMENT ME! */
> + /** The editor component. */
> private Component editor;
>
> - /** DOCUMENT ME! */
> + /** The next button. */
> private Component next;
>
> - /** DOCUMENT ME! */
> + /** The previous button. */
> private Component previous;
> }
> }
> Index: javax/swing/plaf/metal/MetalLookAndFeel.java
> ===================================================================
> RCS file:
> /sources/classpath/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java,v
> retrieving revision 1.77
> diff -u -r1.77 MetalLookAndFeel.java
> --- javax/swing/plaf/metal/MetalLookAndFeel.java 30 Jan 2006 15:32:21
> -0000 1.77
> +++ javax/swing/plaf/metal/MetalLookAndFeel.java 15 Feb 2006 15:57:32
> -0000
> @@ -1171,6 +1171,7 @@
>
> "Spinner.arrowButtonInsets", new InsetsUIResource(0, 0, 0, 0),
> "Spinner.background", getControl(),
> + "Spinner.border", MetalBorders.getTextFieldBorder(),
> "Spinner.font", new FontUIResource("Dialog", Font.BOLD, 12),
> "Spinner.foreground", getControl(),
>
signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil
