~ubuntu-branches/ubuntu/precise/classpath/precise

« back to all changes in this revision

Viewing changes to javax/swing/JSpinner.java

  • Committer: Bazaar Package Importer
  • Author(s): Michael Koch
  • Date: 2006-05-27 16:11:15 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20060527161115-h6e39eposdt5snb6
Tags: 2:0.91-3
* Install header files to /usr/include/classpath.
* debian/control: classpath: Conflict with jamvm < 1.4.3 and
  cacao < 0.96 (Closes: #368172).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* JSpinner.java --
2
 
   Copyright (C) 2004, 2005  Free Software Foundation, Inc.
 
2
   Copyright (C) 2004, 2005, 2006  Free Software Foundation, Inc.
3
3
 
4
4
This file is part of GNU Classpath.
5
5
 
45
45
import java.awt.LayoutManager;
46
46
import java.beans.PropertyChangeEvent;
47
47
import java.beans.PropertyChangeListener;
 
48
import java.text.DateFormat;
48
49
import java.text.DecimalFormat;
 
50
import java.text.NumberFormat;
49
51
import java.text.ParseException;
50
52
import java.text.SimpleDateFormat;
51
53
 
53
55
import javax.swing.event.ChangeListener;
54
56
import javax.swing.plaf.SpinnerUI;
55
57
import javax.swing.text.DateFormatter;
 
58
import javax.swing.text.DefaultFormatterFactory;
 
59
import javax.swing.text.NumberFormatter;
56
60
 
57
61
/**
58
 
 * A JSpinner is a component which typically contains a numeric value and a
59
 
 * way to manipulate the value.
 
62
 * A <code>JSpinner</code> is a component that displays a single value from
 
63
 * a sequence of values, and provides a convenient means for selecting the
 
64
 * previous and next values in the sequence.  Typically the spinner displays
 
65
 * a numeric value, but it is possible to display dates or arbitrary items
 
66
 * from a list.
60
67
 *
61
68
 * @author Ka-Hing Cheung
62
69
 * 
65
72
public class JSpinner extends JComponent
66
73
{
67
74
  /**
68
 
   * DOCUMENT ME!
 
75
   * The base class for the editor used by the {@link JSpinner} component.  
 
76
   * The editor is in fact a panel containing a {@link JFormattedTextField}
 
77
   * component.
69
78
   */
70
 
  public static class DefaultEditor extends JPanel implements ChangeListener,
71
 
                                                              PropertyChangeListener,
72
 
                                                              LayoutManager
 
79
  public static class DefaultEditor 
 
80
    extends JPanel 
 
81
    implements ChangeListener, PropertyChangeListener, LayoutManager
73
82
  {
 
83
    /** The spinner that the editor is allocated to. */
74
84
    private JSpinner spinner;
75
85
 
76
86
    /** The JFormattedTextField that backs the editor. */
82
92
    private static final long serialVersionUID = -5317788736173368172L;
83
93
 
84
94
    /**
85
 
     * Creates a new <code>DefaultEditor</code> object.
 
95
     * Creates a new <code>DefaultEditor</code> object.  The editor is 
 
96
     * registered with the spinner as a {@link ChangeListener} here.
86
97
     *
87
98
     * @param spinner the <code>JSpinner</code> associated with this editor
88
99
     */
94
105
      ftf = new JFormattedTextField();
95
106
      add(ftf);
96
107
      ftf.setValue(spinner.getValue());
 
108
      ftf.addPropertyChangeListener(this);
 
109
      if(getComponentOrientation().isLeftToRight())
 
110
        ftf.setHorizontalAlignment(JTextField.RIGHT);
 
111
      else
 
112
        ftf.setHorizontalAlignment(JTextField.LEFT);
97
113
      spinner.addChangeListener(this);
98
114
    }
99
115
 
100
116
    /**
101
 
     * Returns the <code>JSpinner</code> object for this editor.
 
117
     * Returns the <code>JSpinner</code> component that the editor is assigned
 
118
     * to.
 
119
     * 
 
120
     * @return The spinner that the editor is assigned to.
102
121
     */
103
122
    public JSpinner getSpinner()
104
123
    {
114
133
    }
115
134
 
116
135
    /**
117
 
     * DOCUMENT ME!
 
136
     * Removes the editor from the {@link ChangeListener} list maintained by
 
137
     * the specified <code>spinner</code>.
118
138
     *
119
 
     * @param spinner DOCUMENT ME!
 
139
     * @param spinner  the spinner (<code>null</code> not permitted).
120
140
     */
121
141
    public void dismiss(JSpinner spinner)
122
142
    {
124
144
    }
125
145
 
126
146
    /**
127
 
     * DOCUMENT ME!
 
147
     * Returns the text field used to display and edit the current value in 
 
148
     * the spinner.
128
149
     *
129
 
     * @return DOCUMENT ME!
 
150
     * @return The text field.
130
151
     */
131
152
    public JFormattedTextField getTextField()
132
153
    {
134
155
    }
135
156
    
136
157
    /**
137
 
     * DOCUMENT ME!
 
158
     * Sets the bounds for the child components in this container.  In this
 
159
     * case, the text field is the only component to be laid out.
138
160
     *
139
 
     * @param parent DOCUMENT ME!
 
161
     * @param parent the parent container.
140
162
     */
141
163
    public void layoutContainer(Container parent)
142
164
    {
148
170
    }
149
171
    
150
172
    /**
151
 
     * DOCUMENT ME!
152
 
     *
153
 
     * @param parent DOCUMENT ME!
154
 
     *
155
 
     * @return DOCUMENT ME!
 
173
     * Calculates the minimum size for this component.  In this case, the
 
174
     * text field is the only subcomponent, so the return value is the minimum
 
175
     * size of the text field plus the insets of this component.
 
176
     *
 
177
     * @param parent  the parent container.
 
178
     *
 
179
     * @return The minimum size.
156
180
     */
157
181
    public Dimension minimumLayoutSize(Container parent)
158
182
    {
163
187
    }
164
188
    
165
189
    /**
166
 
     * DOCUMENT ME!
167
 
     *
168
 
     * @param parent DOCUMENT ME!
169
 
     *
170
 
     * @return DOCUMENT ME!
 
190
     * Calculates the preferred size for this component.  In this case, the
 
191
     * text field is the only subcomponent, so the return value is the 
 
192
     * preferred size of the text field plus the insets of this component.
 
193
     *
 
194
     * @param parent  the parent container.
 
195
     *
 
196
     * @return The preferred size.
171
197
     */
172
198
    public Dimension preferredLayoutSize(Container parent)
173
199
    {
178
204
    }
179
205
    
180
206
    /**
181
 
     * DOCUMENT ME!
 
207
     * Receives notification of property changes.  If the text field's 'value' 
 
208
     * property changes, the spinner's model is updated accordingly.
182
209
     *
183
 
     * @param event DOCUMENT ME!
 
210
     * @param event the event.
184
211
     */
185
212
    public void propertyChange(PropertyChangeEvent event)
186
213
    {
187
 
      // TODO: Implement this properly.
 
214
      if (event.getSource() == ftf) 
 
215
        {
 
216
          if (event.getPropertyName().equals("value"))
 
217
            spinner.getModel().setValue(event.getNewValue());
 
218
        }
188
219
    }
189
220
    
190
221
    /**
191
 
     * DOCUMENT ME!
 
222
     * Receives notification of changes in the state of the {@link JSpinner}
 
223
     * that the editor belongs to - the content of the text field is updated
 
224
     * accordingly.  
192
225
     *
193
 
     * @param event DOCUMENT ME!
 
226
     * @param event  the change event.
194
227
     */
195
228
    public void stateChanged(ChangeEvent event)
196
229
    {
197
 
      // TODO: Implement this properly.
 
230
      ftf.setValue(spinner.getValue());
198
231
    }
199
232
    
 
233
    /**
 
234
     * This method does nothing.  It is required by the {@link LayoutManager}
 
235
     * interface, but since this component has a single child, there is no
 
236
     * need to use this method.
 
237
     * 
 
238
     * @param child  the child component to remove.
 
239
     */
200
240
    public void removeLayoutComponent(Component child)
201
241
    {
202
242
      // Nothing to do here.
203
243
    }
204
244
 
205
245
    /**
206
 
     * DOCUMENT ME!
207
 
     *
208
 
     * @param name DOCUMENT ME!
209
 
     * @param child DOCUMENT ME!
 
246
     * This method does nothing.  It is required by the {@link LayoutManager}
 
247
     * interface, but since this component has a single child, there is no
 
248
     * need to use this method.
 
249
     * 
 
250
     * @param name  the name.
 
251
     * @param child  the child component to add.
210
252
     */
211
253
    public void addLayoutComponent(String name, Component child)
212
254
    {
215
257
  }
216
258
 
217
259
  /**
218
 
   * DOCUMENT ME!
 
260
   * A panel containing a {@link JFormattedTextField} that is configured for
 
261
   * displaying and editing numbers.  The panel is used as a subcomponent of
 
262
   * a {@link JSpinner}.
 
263
   * 
 
264
   * @see JSpinner#createEditor(SpinnerModel)
219
265
   */
220
266
  public static class NumberEditor extends DefaultEditor
221
267
  {
225
271
    private static final long serialVersionUID = 3791956183098282942L;
226
272
 
227
273
    /**
228
 
     * Creates a new NumberEditor object.
 
274
     * Creates a new <code>NumberEditor</code> object for the specified 
 
275
     * <code>spinner</code>.  The editor is registered with the spinner as a 
 
276
     * {@link ChangeListener}.
229
277
     *
230
 
     * @param spinner DOCUMENT ME!
 
278
     * @param spinner the component the editor will be used with.
231
279
     */
232
280
    public NumberEditor(JSpinner spinner)
233
281
    {
234
282
      super(spinner);
 
283
      NumberEditorFormatter nef = new NumberEditorFormatter();
 
284
      nef.setMinimum(getModel().getMinimum());
 
285
      nef.setMaximum(getModel().getMaximum());
 
286
      ftf.setFormatterFactory(new DefaultFormatterFactory(nef));
235
287
    }
236
288
 
237
289
    /**
238
 
     * Creates a new NumberEditor object.
 
290
     * Creates a new <code>NumberEditor</code> object.
239
291
     *
240
 
     * @param spinner DOCUMENT ME!
 
292
     * @param spinner  the spinner.
 
293
     * @param decimalFormatPattern  the number format pattern.
241
294
     */
242
295
    public NumberEditor(JSpinner spinner, String decimalFormatPattern)
243
296
    {
244
297
      super(spinner);
 
298
      NumberEditorFormatter nef 
 
299
          = new NumberEditorFormatter(decimalFormatPattern);
 
300
      nef.setMinimum(getModel().getMinimum());
 
301
      nef.setMaximum(getModel().getMaximum());
 
302
      ftf.setFormatterFactory(new DefaultFormatterFactory(nef));
245
303
    }
246
304
 
247
305
    /**
248
 
     * DOCUMENT ME!
 
306
     * Returns the format used by the text field.
249
307
     *
250
 
     * @return DOCUMENT ME!
 
308
     * @return The format used by the text field.
251
309
     */
252
310
    public DecimalFormat getFormat()
253
311
    {
254
 
      return null;
 
312
      NumberFormatter formatter = (NumberFormatter) ftf.getFormatter();
 
313
      return (DecimalFormat) formatter.getFormat();
255
314
    }
256
315
 
 
316
    /**
 
317
     * Returns the model used by the editor's {@link JSpinner} component,
 
318
     * cast to a {@link SpinnerNumberModel}.
 
319
     * 
 
320
     * @return The model.
 
321
     */
257
322
    public SpinnerNumberModel getModel()
258
323
    {
259
324
      return (SpinnerNumberModel) getSpinner().getModel();
260
325
    }
261
326
  }
 
327
  
 
328
  static class NumberEditorFormatter 
 
329
    extends NumberFormatter
 
330
  {
 
331
    public NumberEditorFormatter() 
 
332
    {
 
333
      super(NumberFormat.getInstance());
 
334
    }
 
335
    public NumberEditorFormatter(String decimalFormatPattern)
 
336
    {
 
337
      super(new DecimalFormat(decimalFormatPattern));
 
338
    }
 
339
  }
262
340
 
263
341
  /**
264
342
   * A <code>JSpinner</code> editor used for the {@link SpinnerListModel}.
279
357
      super(spinner);
280
358
    }
281
359
 
 
360
    /**
 
361
     * Returns the spinner's model cast as a {@link SpinnerListModel}.
 
362
     * 
 
363
     * @return The spinner's model.
 
364
     */
282
365
    public SpinnerListModel getModel()
283
366
    {
284
367
      return (SpinnerListModel) getSpinner().getModel();
299
382
    /** The serialVersionUID. */
300
383
    private static final long serialVersionUID = -4279356973770397815L;
301
384
 
302
 
    /** The DateFormat instance used to format the date. */
303
 
    SimpleDateFormat dateFormat;
304
 
 
305
385
    /**
306
386
     * Creates a new instance of DateEditor for the specified
307
387
     * <code>JSpinner</code>.
312
392
    public DateEditor(JSpinner spinner)
313
393
    {
314
394
      super(spinner);
315
 
      init(new SimpleDateFormat());
 
395
      DateEditorFormatter nef = new DateEditorFormatter();
 
396
      nef.setMinimum(getModel().getStart());
 
397
      nef.setMaximum(getModel().getEnd());
 
398
      ftf.setFormatterFactory(new DefaultFormatterFactory(nef));
316
399
    }
317
400
 
318
401
    /**
329
412
    public DateEditor(JSpinner spinner, String dateFormatPattern)
330
413
    {
331
414
      super(spinner);
332
 
      init(new SimpleDateFormat(dateFormatPattern));
333
 
    }
334
 
 
335
 
    /**
336
 
     * Initializes the JFormattedTextField for this editor.
337
 
     *
338
 
     * @param format the date format to use in the formatted text field
339
 
     */
340
 
    private void init(SimpleDateFormat format)
341
 
    {
342
 
      dateFormat = format;
343
 
      getTextField().setFormatterFactory(
344
 
        new JFormattedTextField.AbstractFormatterFactory()
345
 
        {
346
 
          public JFormattedTextField.AbstractFormatter
347
 
          getFormatter(JFormattedTextField ftf)
348
 
          {
349
 
            return new DateFormatter(dateFormat);
350
 
          }
351
 
        });
 
415
      DateEditorFormatter nef = new DateEditorFormatter(dateFormatPattern);
 
416
      nef.setMinimum(getModel().getStart());
 
417
      nef.setMaximum(getModel().getEnd());
 
418
      ftf.setFormatterFactory(new DefaultFormatterFactory(nef));
352
419
    }
353
420
 
354
421
    /**
360
427
     */
361
428
    public SimpleDateFormat getFormat()
362
429
    {
363
 
      return dateFormat;
 
430
      DateFormatter formatter = (DateFormatter) ftf.getFormatter();
 
431
      return (SimpleDateFormat) formatter.getFormat();
364
432
    }
365
433
 
366
434
    /**
374
442
    }
375
443
  }
376
444
 
377
 
  private static final long serialVersionUID = 3412663575706551720L;
378
 
 
379
 
  /** DOCUMENT ME! */
 
445
  static class DateEditorFormatter 
 
446
    extends DateFormatter
 
447
  {
 
448
    public DateEditorFormatter() 
 
449
    {
 
450
      super(DateFormat.getInstance());
 
451
    }
 
452
    public DateEditorFormatter(String dateFormatPattern)
 
453
    {
 
454
      super(new SimpleDateFormat(dateFormatPattern));
 
455
    }
 
456
  }
 
457
 
 
458
  /** 
 
459
   * A listener that forwards {@link ChangeEvent} notifications from the model
 
460
   * to the {@link JSpinner}'s listeners. 
 
461
   */
 
462
  class ModelListener implements ChangeListener
 
463
  {
 
464
    /**
 
465
     * Creates a new listener.
 
466
     */
 
467
    public ModelListener()
 
468
    {
 
469
      // nothing to do here
 
470
    }
 
471
    
 
472
    /**
 
473
     * Receives notification from the model that its state has changed.
 
474
     * 
 
475
     * @param event  the event (ignored).
 
476
     */
 
477
    public void stateChanged(ChangeEvent event)
 
478
    {
 
479
      fireStateChanged();
 
480
    }
 
481
  }
 
482
 
 
483
  /** 
 
484
   * The model that defines the current value and permitted values for the 
 
485
   * spinner. 
 
486
   */
380
487
  private SpinnerModel model;
381
488
 
382
 
  /** DOCUMENT ME! */
 
489
  /** The current editor. */
383
490
  private JComponent editor;
384
491
 
385
 
  /** DOCUMENT ME! */
386
 
  private ChangeListener listener = new ChangeListener()
387
 
    {
388
 
      public void stateChanged(ChangeEvent evt)
389
 
      {
390
 
        fireStateChanged();
391
 
      }
392
 
    };
 
492
  private static final long serialVersionUID = 3412663575706551720L;
393
493
 
394
494
  /**
395
 
   * Creates a JSpinner with <code>SpinnerNumberModel</code>
 
495
   * Creates a new <code>JSpinner</code> with default instance of 
 
496
   * {@link SpinnerNumberModel} (that is, a model with value 0, step size 1, 
 
497
   * and no upper or lower limit).
396
498
   *
397
499
   * @see javax.swing.SpinnerNumberModel
398
500
   */
402
504
  }
403
505
 
404
506
  /**
405
 
   * Creates a JSpinner with the specific model and sets the default editor
 
507
   * Creates a new <code>JSpinner with the specified model.  The 
 
508
   * {@link #createEditor(SpinnerModel)} method is used to create an editor
 
509
   * that is suitable for the model.
406
510
   *
407
 
   * @param model DOCUMENT ME!
 
511
   * @param model the model (<code>null</code> not permitted).
 
512
   * 
 
513
   * @throws NullPointerException if <code>model</code> is <code>null</code>.
408
514
   */
409
515
  public JSpinner(SpinnerModel model)
410
516
  {
411
517
    this.model = model;
412
 
    model.addChangeListener(listener);
413
 
    setEditor(createEditor(model));
 
518
    this.editor = createEditor(model);
 
519
    model.addChangeListener(new ModelListener());
414
520
    updateUI();
415
521
  }
416
522
 
439
545
  }
440
546
 
441
547
  /**
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).
444
 
   *
445
 
   * @param editor the new editor
446
 
   *
447
 
   * @throws IllegalArgumentException DOCUMENT ME!
 
548
   * Changes the current editor to the new editor. The old editor is
 
549
   * removed from the spinner's {@link ChangeEvent} list.
 
550
   *
 
551
   * @param editor the new editor (<code>null</code> not permitted.
 
552
   *
 
553
   * @throws IllegalArgumentException if <code>editor</code> is 
 
554
   *                                  <code>null</code>.
448
555
   *
449
556
   * @see #getEditor
450
557
   */
453
560
    if (editor == null)
454
561
      throw new IllegalArgumentException("editor may not be null");
455
562
 
456
 
    if (this.editor instanceof DefaultEditor)
457
 
      ((DefaultEditor) editor).dismiss(this);
458
 
    else if (this.editor instanceof ChangeListener)
459
 
      removeChangeListener((ChangeListener) this.editor);
460
 
 
461
 
    if (editor instanceof ChangeListener)
462
 
      addChangeListener((ChangeListener) editor);
463
 
 
 
563
    JComponent oldEditor = this.editor;
 
564
    if (oldEditor instanceof DefaultEditor)
 
565
      ((DefaultEditor) oldEditor).dismiss(this);
 
566
    else if (oldEditor instanceof ChangeListener)
 
567
      removeChangeListener((ChangeListener) oldEditor);
 
568
    
464
569
    this.editor = editor;
 
570
    firePropertyChange("editor", oldEditor, editor);
465
571
  }
466
572
 
467
573
  /**
468
 
   * Gets the underly model.
 
574
   * Returns the model used by the {@link JSpinner} component.
469
575
   *
470
 
   * @return the underly model
 
576
   * @return The model.
 
577
   * 
 
578
   * @see #setModel(SpinnerModel)
471
579
   */
472
580
  public SpinnerModel getModel()
473
581
  {
492
600
    SpinnerModel oldModel = model;
493
601
    model = newModel;
494
602
    firePropertyChange("model", oldModel, newModel);
495
 
 
496
 
    if (editor == null)
497
 
      setEditor(createEditor(model));
 
603
    setEditor(createEditor(model));
498
604
  }
499
605
 
500
606
  /**
545
651
  }
546
652
 
547
653
  /**
548
 
   * DOCUMENT ME!
 
654
   * Sets the value in the model.
549
655
   *
550
 
   * @param value DOCUMENT ME!
 
656
   * @param value the new value.
551
657
   */
552
658
  public void setValue(Object value)
553
659
  {
555
661
  }
556
662
 
557
663
  /**
558
 
   * This method returns a name to identify which look and feel class will be
 
664
   * Returns the ID that identifies which look and feel class will be
559
665
   * the UI delegate for this spinner.
560
666
   *
561
 
   * @return The UIClass identifier. "SpinnerUI"
 
667
   * @return <code>"SpinnerUI"</code>.
562
668
   */
563
669
  public String getUIClassID()
564
670
  {
575
681
  }
576
682
 
577
683
  /**
578
 
   * This method sets the spinner's UI delegate.
 
684
   * Sets the UI delegate for the component.
579
685
   *
580
686
   * @param ui The spinner's UI delegate.
581
687
   */
628
734
  }
629
735
 
630
736
  /**
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.
635
 
   *
636
 
   * @param model DOCUMENT ME!
637
 
   *
638
 
   * @return the default editor
 
737
   * Creates an editor that is appropriate for the specified <code>model</code>.
 
738
   *
 
739
   * @param model the model.
 
740
   *
 
741
   * @return The editor.
639
742
   */
640
743
  protected JComponent createEditor(SpinnerModel model)
641
744
  {
643
746
      return new DateEditor(this);
644
747
    else if (model instanceof SpinnerNumberModel)
645
748
      return new NumberEditor(this);
 
749
    else if (model instanceof SpinnerListModel)
 
750
      return new ListEditor(this);
646
751
    else
647
752
      return new DefaultEditor(this);
648
753
  }