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