OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [swing/] [JFormattedTextField.java] - Blame information for rev 772

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 772 jeremybenn
/* JFormattedTextField.java --
2
   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package javax.swing;
40
 
41
import java.awt.event.FocusEvent;
42
import java.io.Serializable;
43
import java.text.DateFormat;
44
import java.text.Format;
45
import java.text.NumberFormat;
46
import java.text.ParseException;
47
import java.util.Date;
48
 
49
import javax.swing.text.AbstractDocument;
50
import javax.swing.text.DateFormatter;
51
import javax.swing.text.DefaultFormatter;
52
import javax.swing.text.DefaultFormatterFactory;
53
import javax.swing.text.Document;
54
import javax.swing.text.DocumentFilter;
55
import javax.swing.text.InternationalFormatter;
56
import javax.swing.text.NavigationFilter;
57
import javax.swing.text.NumberFormatter;
58
 
59
/**
60
 * A text field that makes use of a formatter to display and edit a specific
61
 * type of data. The value that is displayed can be an arbitrary object. The
62
 * formatter is responsible for displaying the value in a textual form and
63
 * it may allow editing of the value.
64
 *
65
 * Formatters are usually obtained using an instance of
66
 * {@link AbstractFormatterFactory}. This factory is responsible for providing
67
 * an instance of {@link AbstractFormatter} that is able to handle the
68
 * formatting of the value of the JFormattedTextField.
69
 *
70
 * @author Michael Koch
71
 * @author Anthony Balkissoon abalkiss at redhat dot com
72
 *
73
 * @since 1.4
74
 */
75
public class JFormattedTextField extends JTextField
76
{
77
  private static final long serialVersionUID = 5464657870110180632L;
78
 
79
  /**
80
   * An abstract base implementation for a formatter that can be used by
81
   * a JTextField. A formatter can display a specific type of object and
82
   * may provide a way to edit this value.
83
   */
84
  public abstract static class AbstractFormatter implements Serializable
85
  {
86
    private static final long serialVersionUID = -5193212041738979680L;
87
 
88
    private JFormattedTextField textField;
89
 
90
    public AbstractFormatter ()
91
    {
92
      //Do nothing here.
93
    }
94
 
95
    /**
96
     * Clones the AbstractFormatter and removes the association to any
97
     * particular JFormattedTextField.
98
     *
99
     * @return a clone of this formatter with no association to any particular
100
     * JFormattedTextField
101
     * @throws CloneNotSupportedException if the Object's class doesn't support
102
     * the {@link Cloneable} interface
103
     */
104
    protected Object clone()
105
      throws CloneNotSupportedException
106
    {
107
      // Clone this formatter.
108
      AbstractFormatter newFormatter = (AbstractFormatter) super.clone();
109
 
110
      // And remove the association to the JFormattedTextField.
111
      newFormatter.textField = null;
112
      return newFormatter;
113
    }
114
 
115
    /**
116
     * Returns a custom set of Actions that this formatter supports.  Should
117
     * be subclassed by formatters that have a custom set of Actions.
118
     *
119
     * @return <code>null</code>.  Should be subclassed by formatters that want
120
     * to install custom Actions on the JFormattedTextField.
121
     */
122
    protected Action[] getActions()
123
    {
124
      return null;
125
    }
126
 
127
    /**
128
     * Gets the DocumentFilter for this formatter.  Should be subclassed
129
     * by formatters wishing to install a filter that oversees Document
130
     * mutations.
131
     *
132
     * @return <code>null</code>.  Should be subclassed by formatters
133
     * that want to restrict Document mutations.
134
     */
135
    protected DocumentFilter getDocumentFilter()
136
    {
137
      // Subclasses should override this if they want to install a
138
      // DocumentFilter.
139
      return null;
140
    }
141
 
142
    /**
143
     * Returns the JFormattedTextField on which this formatter is
144
     * currently installed.
145
     *
146
     * @return the JFormattedTextField on which this formatter is currently
147
     * installed
148
     */
149
    protected JFormattedTextField getFormattedTextField()
150
    {
151
      return textField;
152
    }
153
 
154
    /**
155
     * Gets the NavigationFilter for this formatter.  Should be subclassed
156
     * by formatters (such as {@link DefaultFormatter}) that wish to
157
     * restrict where the cursor can be placed within the text field.
158
     *
159
     * @return <code>null</code>.  Subclassed by formatters that want to restrict
160
     * cursor location within the JFormattedTextField.
161
     */
162
    protected NavigationFilter getNavigationFilter()
163
    {
164
      // This should be subclassed if the formatter wants to install
165
      // a NavigationFilter on the JFormattedTextField.
166
      return null;
167
    }
168
 
169
    /**
170
     * Installs this formatter on the specified JFormattedTextField.  This
171
     * converts the current value to a displayable String and displays it,
172
     * and installs formatter specific Actions from <code>getActions</code>.
173
     * It also installs a DocumentFilter and NavigationFilter on the
174
     * JFormattedTextField.
175
     * <p>
176
     * If there is a <code>ParseException</code> this sets the text to an
177
     * empty String and marks the text field in an invalid state.
178
     *
179
     * @param textField the JFormattedTextField on which to install this
180
     * formatter
181
     */
182
    public void install(JFormattedTextField textField)
183
    {
184
      // Uninstall the current textfield.
185
      if (this.textField != null)
186
        uninstall();
187
 
188
      this.textField = textField;
189
 
190
      // Install some state on the text field, including display text,
191
      // DocumentFilter, NavigationFilter, and formatter specific Actions.
192
      if (textField != null)
193
        {
194
          try
195
          {
196
            // Set the text of the field.
197
            textField.setText(valueToString(textField.getValue()));
198
            Document doc = textField.getDocument();
199
 
200
            // Set the DocumentFilter for the field's Document.
201
            if (doc instanceof AbstractDocument)
202
              ((AbstractDocument) doc).setDocumentFilter(getDocumentFilter());
203
 
204
            // Set the NavigationFilter.
205
            textField.setNavigationFilter(getNavigationFilter());
206
 
207
            // Set the Formatter Actions
208
            // FIXME: Have to add the actions from getActions()
209
          }
210
          catch (ParseException pe)
211
          {
212
            // Set the text to an empty String and mark the field as invalid.
213
            textField.setText("");
214
            setEditValid(false);
215
          }
216
        }
217
    }
218
 
219
    /**
220
     * Clears the state installed on the JFormattedTextField by the formatter.
221
     * This resets the DocumentFilter, NavigationFilter, and any additional
222
     * Actions (returned by <code>getActions()</code>).
223
     */
224
    public void uninstall()
225
    {
226
      // Set the DocumentFilter for the field's Document.
227
      Document doc = textField.getDocument();
228
      if (doc instanceof AbstractDocument)
229
        ((AbstractDocument) doc).setDocumentFilter(null);
230
      textField.setNavigationFilter(null);
231
      // FIXME: Have to remove the Actions from getActions()
232
      this.textField = null;
233
    }
234
 
235
    /**
236
     * Invoke this method when invalid values are entered.  This forwards the
237
     * call to the JFormattedTextField.
238
     */
239
    protected void invalidEdit()
240
    {
241
      textField.invalidEdit();
242
    }
243
 
244
    /**
245
     * This method updates the <code>editValid</code> property of
246
     * JFormattedTextField.
247
     *
248
     * @param valid the new state for the <code>editValid</code> property
249
     */
250
    protected void setEditValid(boolean valid)
251
    {
252
      textField.editValid = valid;
253
    }
254
 
255
    /**
256
     * Parses <code>text</code> to return a corresponding Object.
257
     *
258
     * @param text the String to parse
259
     * @return an Object that <code>text</code> represented
260
     * @throws ParseException if there is an error in the conversion
261
     */
262
    public abstract Object stringToValue(String text)
263
      throws ParseException;
264
 
265
    /**
266
     * Returns a String to be displayed, based on the Object
267
     * <code>value</code>.
268
     *
269
     * @param value the Object from which to generate a String
270
     * @return a String to be displayed
271
     * @throws ParseException if there is an error in the conversion
272
     */
273
    public abstract String valueToString(Object value)
274
      throws ParseException;
275
  }
276
 
277
  /**
278
   * Delivers instances of an {@link AbstractFormatter} for
279
   * a specific value type for a JFormattedTextField.
280
   */
281
  public abstract static class AbstractFormatterFactory
282
  {
283
    public AbstractFormatterFactory()
284
    {
285
      // Do nothing here.
286
    }
287
 
288
    public abstract AbstractFormatter getFormatter(JFormattedTextField tf);
289
  }
290
 
291
  /** The possible focusLostBehavior options **/
292
  public static final int COMMIT = 0;
293
  public static final int COMMIT_OR_REVERT = 1;
294
  public static final int REVERT = 2;
295
  public static final int PERSIST = 3;
296
 
297
  /** The most recent valid and committed value **/
298
  private Object value;
299
 
300
  /** The behaviour for when this text field loses focus **/
301
  private int focusLostBehavior = COMMIT_OR_REVERT;
302
 
303
  /** The formatter factory currently being used **/
304
  private AbstractFormatterFactory formatterFactory;
305
 
306
  /** The formatter currently being used **/
307
  private AbstractFormatter formatter;
308
 
309
  // Package-private to avoid an accessor method.
310
  boolean editValid = true;
311
 
312
  /**
313
   * Creates a JFormattedTextField with no formatter factory.
314
   * <code>setValue</code> or <code>setFormatterFactory</code> will
315
   * properly configure this text field to edit a particular type
316
   * of value.
317
   */
318
  public JFormattedTextField()
319
  {
320
    this((AbstractFormatterFactory) null, null);
321
  }
322
 
323
  /**
324
   * Creates a JFormattedTextField that can handle the specified Format.
325
   * An appopriate AbstractFormatter and AbstractFormatterFactory will
326
   * be created for the specified Format.
327
   *
328
   * @param format the Format that this JFormattedTextField should be able
329
   * to handle
330
   */
331
  public JFormattedTextField(Format format)
332
  {
333
    this ();
334
    setFormatterFactory(getAppropriateFormatterFactory(format));
335
  }
336
 
337
  /**
338
   * Creates a JFormattedTextField with the specified formatter.  This will
339
   * create a {@link DefaultFormatterFactory} with this formatter as the default
340
   * formatter.
341
   *
342
   * @param formatter the formatter to use for this JFormattedTextField
343
   */
344
  public JFormattedTextField(AbstractFormatter formatter)
345
  {
346
    this(new DefaultFormatterFactory(formatter));
347
  }
348
 
349
  /**
350
   * Creates a JFormattedTextField with the specified formatter factory.
351
   *
352
   * @param factory the formatter factory to use for this JFormattedTextField
353
   */
354
  public JFormattedTextField(AbstractFormatterFactory factory)
355
  {
356
    setFormatterFactory(factory);
357
  }
358
 
359
  /**
360
   * Creates a JFormattedTextField with the specified formatter factory and
361
   * initial value.
362
   *
363
   * @param factory the initial formatter factory for this JFormattedTextField
364
   * @param value the initial value for the text field
365
   */
366
  public JFormattedTextField(AbstractFormatterFactory factory, Object value)
367
  {
368
    setFormatterFactory(factory);
369
    setValue(value);
370
  }
371
 
372
  /**
373
   * Creates a JFormattedTextField with the specified value.  This creates a
374
   * formatter and formatterFactory that are appropriate for the value.
375
   *
376
   * @param value the initial value for this JFormattedTextField
377
   */
378
  public JFormattedTextField(Object value)
379
  {
380
    setValue(value);
381
  }
382
 
383
  /**
384
   * Returns an AbstractFormatterFactory that will give an appropriate
385
   * AbstractFormatter for the given Format.
386
   * @param format the Format to match with an AbstractFormatter.
387
   * @return a DefaultFormatterFactory whose defaultFormatter is appropriate
388
   * for the given Format.
389
   */
390
  private AbstractFormatterFactory getAppropriateFormatterFactory(Format format)
391
  {
392
    AbstractFormatter newFormatter;
393
    if (format instanceof DateFormat)
394
      newFormatter = new DateFormatter((DateFormat) format);
395
    else if (format instanceof NumberFormat)
396
      newFormatter = new NumberFormatter ((NumberFormat) format);
397
    else
398
      newFormatter = new InternationalFormatter(format);
399
 
400
    return new DefaultFormatterFactory(newFormatter);
401
  }
402
 
403
  /**
404
   * Forces the current value from the editor to be set as the current
405
   * value.  If there is no current formatted this has no effect.
406
   *
407
   * @throws ParseException if the formatter cannot format the current value
408
   */
409
  public void commitEdit()
410
    throws ParseException
411
  {
412
    if (formatter == null)
413
      return;
414
    // Note: this code is a lot like setValue except that we don't want
415
    // to create a new formatter.
416
    Object oldValue = this.value;
417
 
418
    this.value = formatter.stringToValue(getText());
419
    editValid = true;
420
 
421
    firePropertyChange("value", oldValue, this.value);
422
  }
423
 
424
  /**
425
   * Gets the command list supplied by the UI augmented by the specific
426
   * Actions for JFormattedTextField.
427
   *
428
   * @return an array of Actions that this text field supports
429
   */
430
  public Action[] getActions()
431
  {
432
    // FIXME: Add JFormattedTextField specific actions
433
    // These are related to committing or cancelling edits.
434
    return super.getActions();
435
  }
436
 
437
  /**
438
   * Returns the behaviour of this JFormattedTextField upon losing focus.  This
439
   * is one of <code>COMMIT</code>, <code>COMMIT_OR_REVERT</code>,
440
   * <code>PERSIST</code>, or <code>REVERT</code>.
441
   * @return the behaviour upon losing focus
442
   */
443
  public int getFocusLostBehavior()
444
  {
445
    return focusLostBehavior;
446
  }
447
 
448
  /**
449
   * Returns the current formatter used for this JFormattedTextField.
450
   * @return the current formatter used for this JFormattedTextField
451
   */
452
  public AbstractFormatter getFormatter()
453
  {
454
    return formatter;
455
  }
456
 
457
  /**
458
   * Returns the factory currently used to generate formatters for this
459
   * JFormattedTextField.
460
   * @return the factory currently used to generate formatters
461
   */
462
  public AbstractFormatterFactory getFormatterFactory()
463
  {
464
    return formatterFactory;
465
  }
466
 
467
  public String getUIClassID()
468
  {
469
    return "FormattedTextFieldUI";
470
  }
471
 
472
  /**
473
   * Returns the last valid value.  This may not be the value currently shown
474
   * in the text field depending on whether or not the formatter commits on
475
   * valid edits and allows invalid input to be temporarily displayed.
476
   * @return the last committed valid value
477
   */
478
  public Object getValue()
479
  {
480
    return value;
481
  }
482
 
483
  /**
484
   * This method is used to provide feedback to the user when an invalid value
485
   * is input during editing.
486
   */
487
  protected void invalidEdit()
488
  {
489
    UIManager.getLookAndFeel().provideErrorFeedback(this);
490
  }
491
 
492
  /**
493
   * Returns true if the current value being edited is valid.  This property is
494
   * managed by the current formatted.
495
   * @return true if the value being edited is valid.
496
   */
497
  public boolean isEditValid()
498
  {
499
    return editValid;
500
  }
501
 
502
  /**
503
   * Processes focus events.  This is overridden because we may want to
504
   * change the formatted depending on whether or not this field has
505
   * focus.
506
   *
507
   * @param evt the FocusEvent
508
   */
509
  protected void processFocusEvent(FocusEvent evt)
510
  {
511
    super.processFocusEvent(evt);
512
    // Let the formatterFactory change the formatter for this text field
513
    // based on whether or not it has focus.
514
    setFormatter (formatterFactory.getFormatter(this));
515
  }
516
 
517
  /**
518
   * Associates this JFormattedTextField with a Document and propagates
519
   * a PropertyChange event to each listener.
520
   *
521
   * @param newDocument the Document to associate with this text field
522
   */
523
  public void setDocument(Document newDocument)
524
  {
525
    // FIXME: This method should do more than this.  Must do some handling
526
    // of the DocumentListeners.
527
    Document oldDocument = getDocument();
528
 
529
    if (oldDocument == newDocument)
530
      return;
531
 
532
    super.setDocument(newDocument);
533
  }
534
 
535
  /**
536
   * Sets the behaviour of this JFormattedTextField upon losing focus.
537
   * This must be <code>COMMIT</code>, <code>COMMIT_OR_REVERT</code>,
538
   * <code>PERSIST</code>, or <code>REVERT</code> or an
539
   * IllegalArgumentException will be thrown.
540
   *
541
   * @param behavior
542
   * @throws IllegalArgumentException if <code>behaviour</code> is not
543
   * one of the above
544
   */
545
  public void setFocusLostBehavior(int behavior)
546
  {
547
    if (behavior != COMMIT
548
        && behavior != COMMIT_OR_REVERT
549
        && behavior != PERSIST
550
        && behavior != REVERT)
551
      throw new IllegalArgumentException("invalid behavior");
552
 
553
    this.focusLostBehavior = behavior;
554
  }
555
 
556
  /**
557
   * Sets the formatter for this JFormattedTextField.  Normally the formatter
558
   * factory will take care of this, or calls to setValue will also make sure
559
   * that the formatter is set appropriately.
560
   *
561
   * @param formatter the AbstractFormatter to use for formatting the value for
562
   * this JFormattedTextField
563
   */
564
  protected void setFormatter(AbstractFormatter formatter)
565
  {
566
    AbstractFormatter oldFormatter = null;
567
 
568
    oldFormatter = this.formatter;
569
 
570
    if (oldFormatter != null)
571
      oldFormatter.uninstall();
572
 
573
    this.formatter = formatter;
574
 
575
    if (formatter != null)
576
      formatter.install(this);
577
 
578
    firePropertyChange("formatter", oldFormatter, formatter);
579
  }
580
 
581
  /**
582
   * Sets the factory from which this JFormattedTextField should obtain
583
   * its formatters.
584
   *
585
   * @param factory the AbstractFormatterFactory that will be used to generate
586
   * formatters for this JFormattedTextField
587
   */
588
  public void setFormatterFactory(AbstractFormatterFactory factory)
589
  {
590
    if (formatterFactory == factory)
591
      return;
592
 
593
    AbstractFormatterFactory oldFactory = formatterFactory;
594
    formatterFactory = factory;
595
    firePropertyChange("formatterFactory", oldFactory, factory);
596
 
597
    // Now set the formatter according to our new factory.
598
    if (formatterFactory != null)
599
      setFormatter(formatterFactory.getFormatter(this));
600
    else
601
      setFormatter(null);
602
  }
603
 
604
  /**
605
   * Sets the value that will be formatted and displayed.
606
   *
607
   * @param newValue the value to be formatted and displayed
608
   */
609
  public void setValue(Object newValue)
610
  {
611
    if (value == newValue)
612
      return;
613
 
614
    Object oldValue = value;
615
    value = newValue;
616
 
617
    // If there is no formatterFactory then make one.
618
    if (formatterFactory == null)
619
      setFormatterFactory(createFormatterFactory(newValue));
620
 
621
    // Set the formatter appropriately.  This is because there may be a new
622
    // formatterFactory from the line above, or we may want a new formatter
623
    // depending on the type of newValue (or if newValue is null).
624
    setFormatter (formatterFactory.getFormatter(this));
625
    firePropertyChange("value", oldValue, newValue);
626
  }
627
 
628
  /**
629
   * A helper method that attempts to create a formatter factory that is
630
   * suitable to format objects of the type like <code>value</code>.
631
   *
632
   * @param value an object which should be formatted by the formatter factory.
633
   *
634
   * @return a formatter factory able to format objects of the class of
635
   *     <code>value</code>
636
   */
637
  AbstractFormatterFactory createFormatterFactory(Object value)
638
  {
639
    AbstractFormatter formatter = null;
640
    if (value instanceof Date)
641
      formatter = new DateFormatter();
642
    else if (value instanceof Number)
643
      formatter = new NumberFormatter();
644
    else
645
      formatter = new DefaultFormatter();
646
    return new DefaultFormatterFactory(formatter);
647
  }
648
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.