/[classpath]/classpath/javax/swing/JFormattedTextField.java
ViewVC logotype

Diff of /classpath/javax/swing/JFormattedTextField.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.18 by abalkiss, Wed Nov 30 23:02:37 2005 UTC revision 1.19 by abalkiss, Fri Dec 2 16:22:53 2005 UTC
# Line 46  import java.text.NumberFormat; Line 46  import java.text.NumberFormat;
46  import java.text.ParseException;  import java.text.ParseException;
47  import java.util.Date;  import java.util.Date;
48    
49    import javax.swing.text.AbstractDocument;
50  import javax.swing.text.DateFormatter;  import javax.swing.text.DateFormatter;
51  import javax.swing.text.DefaultFormatter;  import javax.swing.text.DefaultFormatter;
52  import javax.swing.text.DefaultFormatterFactory;  import javax.swing.text.DefaultFormatterFactory;
# Line 67  import javax.swing.text.NumberFormatter; Line 68  import javax.swing.text.NumberFormatter;
68   * formatting of the value of the JFormattedTextField.   * formatting of the value of the JFormattedTextField.
69   *   *
70   * @author Michael Koch   * @author Michael Koch
71     * @author Anthony Balkissoon abalkiss at redhat dot com
72   *   *
73   * @since 1.4   * @since 1.4
74   */   */
# Line 90  public class JFormattedTextField extends Line 92  public class JFormattedTextField extends
92        //Do nothing here.        //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 ()      protected Object clone ()
105        throws CloneNotSupportedException        throws CloneNotSupportedException
106      {      {
107        throw new InternalError ("not implemented");        // 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 ()      protected Action[] getActions ()
123      {      {
124        return textField.getActions();        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 ()      protected DocumentFilter getDocumentFilter ()
136      {      {
137        throw new InternalError ("not implemented");        // 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 ()      protected JFormattedTextField getFormattedTextField ()
150      {      {
151        return textField;        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 ()      protected NavigationFilter getNavigationFilter ()
163      {      {
164        return textField.getNavigationFilter();        // 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)      public void install(JFormattedTextField textField)
183      {      {
184          // Uninstall the current textfield.
185        if (this.textField != null)        if (this.textField != null)
186          uninstall();          uninstall();
187                
188        this.textField = textField;        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)        if (textField != null)
193          {          {
194            try            try
195            {            {
196                // Set the text of the field.
197              textField.setText(valueToString(textField.getValue()));              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)            catch (ParseException pe)
211            {            {
212              // FIXME: Not sure what to do here.              // 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 ()      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;        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 ()      protected void invalidEdit ()
240      {      {
241        textField.invalidEdit();        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)      protected void setEditValid (boolean valid)
251      {      {
252        textField.editValid = valid;        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)      public abstract Object stringToValue (String text)
263        throws ParseException;        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)      public abstract String valueToString (Object value)
274        throws ParseException;        throws ParseException;
275    }    }
# Line 172  public class JFormattedTextField extends Line 288  public class JFormattedTextField extends
288      public abstract AbstractFormatter getFormatter (JFormattedTextField tf);      public abstract AbstractFormatter getFormatter (JFormattedTextField tf);
289    }    }
290    
291      /** The possible focusLostBehavior options **/
292    public static final int COMMIT = 0;    public static final int COMMIT = 0;
293    public static final int COMMIT_OR_REVERT = 1;    public static final int COMMIT_OR_REVERT = 1;
294    public static final int REVERT = 2;    public static final int REVERT = 2;
295    public static final int PERSIST = 3;    public static final int PERSIST = 3;
296    
297      /** The most recent valid and committed value **/
298    private Object value;    private Object value;
299      
300      /** The behaviour for when this text field loses focus **/
301    private int focusLostBehavior = COMMIT_OR_REVERT;    private int focusLostBehavior = COMMIT_OR_REVERT;
302      
303      /** The formatter factory currently being used **/
304    private AbstractFormatterFactory formatterFactory;    private AbstractFormatterFactory formatterFactory;
305      
306      /** The formatter currently being used **/
307    private AbstractFormatter formatter;    private AbstractFormatter formatter;
308      
309    // Package-private to avoid an accessor method.    // Package-private to avoid an accessor method.
310    boolean editValid = true;    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 ()    public JFormattedTextField ()
319    {    {
320      this((AbstractFormatterFactory) null, null);      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)    public JFormattedTextField (Format format)
332    {    {
333      this ();      this ();
334      setFormatterFactory(getAppropriateFormatterFactory(format));      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)    public JFormattedTextField (AbstractFormatter formatter)
345    {    {
346      this(new DefaultFormatterFactory (formatter), null);      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)    public JFormattedTextField (AbstractFormatterFactory factory)
355    {    {
356      this(factory, null);      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)    public JFormattedTextField (AbstractFormatterFactory factory, Object value)
367    {    {    
368        setFormatterFactory(factory);
369      setValue(value);      setValue(value);
     setFormatterFactory(factory);      
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)    public JFormattedTextField (Object value)
379    {    {
380      setValue(value);      setValue(value);
# Line 236  public class JFormattedTextField extends Line 400  public class JFormattedTextField extends
400      return new DefaultFormatterFactory(newFormatter);      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 ()    public void commitEdit ()
410      throws ParseException      throws ParseException
411    {    {
412      throw new InternalError ("not implemented");      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 ()    public Action[] getActions ()
431    {    {
432      // FIXME: Add JFormattedTextField specific actions      // FIXME: Add JFormattedTextField specific actions
433        // These are related to committing or cancelling edits.
434      return super.getActions();      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()    public int getFocusLostBehavior()
444    {    {
445      return focusLostBehavior;      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 ()    public AbstractFormatter getFormatter ()
453    {    {
454      return formatter;      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 ()    public AbstractFormatterFactory getFormatterFactory ()
463    {    {
464      return formatterFactory;      return formatterFactory;
# Line 268  public class JFormattedTextField extends Line 469  public class JFormattedTextField extends
469      return "FormattedTextFieldUI";      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 ()    public Object getValue ()
479    {    {
480      return value;      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 ()    protected void invalidEdit ()
488    {    {
489      UIManager.getLookAndFeel().provideErrorFeedback(this);      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 ()    public boolean isEditValid ()
498    {    {
499      return editValid;      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)    protected void processFocusEvent (FocusEvent evt)
510    {    {
511      super.processFocusEvent(evt);      super.processFocusEvent(evt);
# Line 290  public class JFormattedTextField extends Line 513  public class JFormattedTextField extends
513      // based on whether or not it has focus.      // based on whether or not it has focus.
514      setFormatter (formatterFactory.getFormatter(this));      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)    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();      Document oldDocument = getDocument();
528    
529      if (oldDocument == newDocument)      if (oldDocument == newDocument)
# Line 301  public class JFormattedTextField extends Line 532  public class JFormattedTextField extends
532      super.setDocument(newDocument);      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)    public void setFocusLostBehavior(int behavior)
546    {    {
547      if (behavior != COMMIT      if (behavior != COMMIT
# Line 312  public class JFormattedTextField extends Line 553  public class JFormattedTextField extends
553      this.focusLostBehavior = behavior;      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)    protected void setFormatter (AbstractFormatter formatter)
565    {    {
566      AbstractFormatter oldFormatter = null;      AbstractFormatter oldFormatter = null;
567            
568      oldFormatter = this.formatter;      oldFormatter = this.formatter;
569    
     if (oldFormatter == formatter)  
       return;  
       
570      if (oldFormatter != null)      if (oldFormatter != null)
571        oldFormatter.uninstall();        oldFormatter.uninstall();
572            
# Line 332  public class JFormattedTextField extends Line 578  public class JFormattedTextField extends
578      firePropertyChange("formatter", oldFormatter, formatter);      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)    public void setFormatterFactory (AbstractFormatterFactory factory)
589    {    {
590      if (formatterFactory == factory)      if (formatterFactory == factory)
# Line 340  public class JFormattedTextField extends Line 593  public class JFormattedTextField extends
593      AbstractFormatterFactory oldFactory = formatterFactory;      AbstractFormatterFactory oldFactory = formatterFactory;
594      formatterFactory = factory;      formatterFactory = factory;
595      firePropertyChange("formatterFactory", oldFactory, factory);      firePropertyChange("formatterFactory", oldFactory, factory);
596      setFormatter(formatterFactory.getFormatter(this));      
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)    public void setValue (Object newValue)
610    {    {
611      if (value == newValue)      if (value == newValue)
# Line 351  public class JFormattedTextField extends Line 614  public class JFormattedTextField extends
614      Object oldValue = value;      Object oldValue = value;
615      value = newValue;      value = newValue;
616            
617      // format value      // If there is no formatterFactory then make one.
618      formatter = createFormatter(newValue);      if (formatterFactory == null)
619      try        setFormatterFactory(createFormatterFactory(newValue));
620        {      
621          setText(formatter.valueToString(newValue));      // 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      catch (ParseException ex)      // depending on the type of newValue (or if newValue is null).
624        {      setFormatter (formatterFactory.getFormatter(this));
         // TODO: what should we do with this?  
       }  
625      firePropertyChange("value", oldValue, newValue);      firePropertyChange("value", oldValue, newValue);
626    }    }
627    
628    /**    /**
629     * A helper method that attempts to create a formatter that is suitable     * A helper method that attempts to create a formatter factory that is
630     * to format objects of the type like <code>value</code>.     * suitable to format objects of the type like <code>value</code>.
    *  
    * If <code>formatterFactory</code> is not null and the returned formatter  
    * is also not <code>null</code> then this formatter is used. Otherwise we  
    * try to create one based on the type of <code>value</code>.  
631     *     *
632     * @param value an object which should be formatted by the formatter     * @param value an object which should be formatted by the formatter factory.
633     *     *
634     * @return a formatter able to format objects of the class of     * @return a formatter factory able to format objects of the class of
635     *     <code>value</code>     *     <code>value</code>
636     */     */
637    AbstractFormatter createFormatter(Object value)    AbstractFormatterFactory createFormatterFactory(Object value)
638    {    {
639      AbstractFormatter formatter = null;      AbstractFormatter formatter = null;
640      if (formatterFactory != null && formatterFactory.getFormatter(this) != null)      if (value instanceof Date)
641        formatter = formatterFactory.getFormatter(this);        formatter = new DateFormatter();
642        else if (value instanceof Number)
643          formatter = new NumberFormatter();
644      else      else
645        {        formatter = new DefaultFormatter();        
646          if (value instanceof Date)      return new DefaultFormatterFactory(formatter);
           formatter = new DateFormatter();  
         else if (value instanceof Number)  
           formatter = new NumberFormatter();  
         else  
           formatter = new DefaultFormatter();  
         formatterFactory = new DefaultFormatterFactory (formatter);  
       }  
     return formatter;  
647    }    }
648  }  }

Legend:
Removed from v.1.18  
changed lines
  Added in v.1.19

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26