View Javadoc
1   /*
2    * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  package javax.swing;
26  
27  import sun.swing.SwingUtilities2;
28  
29  import java.awt.*;
30  import java.awt.event.*;
31  import java.beans.*;
32  import javax.swing.text.*;
33  import javax.swing.plaf.*;
34  import javax.swing.event.*;
35  import javax.accessibility.*;
36  
37  import java.io.ObjectOutputStream;
38  import java.io.ObjectInputStream;
39  import java.io.IOException;
40  import java.io.Serializable;
41  
42  /**
43   * <code>JTextField</code> is a lightweight component that allows the editing
44   * of a single line of text.
45   * For information on and examples of using text fields,
46   * see
47   * <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html">How to Use Text Fields</a>
48   * in <em>The Java Tutorial.</em>
49   *
50   * <p>
51   * <code>JTextField</code> is intended to be source-compatible
52   * with <code>java.awt.TextField</code> where it is reasonable to do so.  This
53   * component has capabilities not found in the <code>java.awt.TextField</code>
54   * class.  The superclass should be consulted for additional capabilities.
55   * <p>
56   * <code>JTextField</code> has a method to establish the string used as the
57   * command string for the action event that gets fired.  The
58   * <code>java.awt.TextField</code> used the text of the field as the command
59   * string for the <code>ActionEvent</code>.
60   * <code>JTextField</code> will use the command
61   * string set with the <code>setActionCommand</code> method if not <code>null</code>,
62   * otherwise it will use the text of the field as a compatibility with
63   * <code>java.awt.TextField</code>.
64   * <p>
65   * The method <code>setEchoChar</code> and <code>getEchoChar</code>
66   * are not provided directly to avoid a new implementation of a
67   * pluggable look-and-feel inadvertently exposing password characters.
68   * To provide password-like services a separate class <code>JPasswordField</code>
69   * extends <code>JTextField</code> to provide this service with an independently
70   * pluggable look-and-feel.
71   * <p>
72   * The <code>java.awt.TextField</code> could be monitored for changes by adding
73   * a <code>TextListener</code> for <code>TextEvent</code>'s.
74   * In the <code>JTextComponent</code> based
75   * components, changes are broadcasted from the model via a
76   * <code>DocumentEvent</code> to <code>DocumentListeners</code>.
77   * The <code>DocumentEvent</code> gives
78   * the location of the change and the kind of change if desired.
79   * The code fragment might look something like:
80   * <pre><code>
81   * &nbsp;   DocumentListener myListener = ??;
82   * &nbsp;   JTextField myArea = ??;
83   * &nbsp;   myArea.getDocument().addDocumentListener(myListener);
84   * </code></pre>
85   * <p>
86   * The horizontal alignment of <code>JTextField</code> can be set to be left
87   * justified, leading justified, centered, right justified or trailing justified.
88   * Right/trailing justification is useful if the required size
89   * of the field text is smaller than the size allocated to it.
90   * This is determined by the <code>setHorizontalAlignment</code>
91   * and <code>getHorizontalAlignment</code> methods.  The default
92   * is to be leading justified.
93   * <p>
94   * How the text field consumes VK_ENTER events depends
95   * on whether the text field has any action listeners.
96   * If so, then VK_ENTER results in the listeners
97   * getting an ActionEvent,
98   * and the VK_ENTER event is consumed.
99   * This is compatible with how AWT text fields handle VK_ENTER events.
100  * If the text field has no action listeners, then as of v 1.3 the VK_ENTER
101  * event is not consumed.  Instead, the bindings of ancestor components
102  * are processed, which enables the default button feature of
103  * JFC/Swing to work.
104  * <p>
105  * Customized fields can easily be created by extending the model and
106  * changing the default model provided.  For example, the following piece
107  * of code will create a field that holds only upper case characters.  It
108  * will work even if text is pasted into from the clipboard or it is altered via
109  * programmatic changes.
110  * <pre><code>
111 
112 &nbsp;public class UpperCaseField extends JTextField {
113 &nbsp;
114 &nbsp;    public UpperCaseField(int cols) {
115 &nbsp;        super(cols);
116 &nbsp;    }
117 &nbsp;
118 &nbsp;    protected Document createDefaultModel() {
119 &nbsp;        return new UpperCaseDocument();
120 &nbsp;    }
121 &nbsp;
122 &nbsp;    static class UpperCaseDocument extends PlainDocument {
123 &nbsp;
124 &nbsp;        public void insertString(int offs, String str, AttributeSet a)
125 &nbsp;            throws BadLocationException {
126 &nbsp;
127 &nbsp;            if (str == null) {
128 &nbsp;                return;
129 &nbsp;            }
130 &nbsp;            char[] upper = str.toCharArray();
131 &nbsp;            for (int i = 0; i &lt; upper.length; i++) {
132 &nbsp;                upper[i] = Character.toUpperCase(upper[i]);
133 &nbsp;            }
134 &nbsp;            super.insertString(offs, new String(upper), a);
135 &nbsp;        }
136 &nbsp;    }
137 &nbsp;}
138 
139  * </code></pre>
140  * <p>
141  * <strong>Warning:</strong> Swing is not thread safe. For more
142  * information see <a
143  * href="package-summary.html#threading">Swing's Threading
144  * Policy</a>.
145  * <p>
146  * <strong>Warning:</strong>
147  * Serialized objects of this class will not be compatible with
148  * future Swing releases. The current serialization support is
149  * appropriate for short term storage or RMI between applications running
150  * the same version of Swing.  As of 1.4, support for long term storage
151  * of all JavaBeans&trade;
152  * has been added to the <code>java.beans</code> package.
153  * Please see {@link java.beans.XMLEncoder}.
154  *
155  * @beaninfo
156  *   attribute: isContainer false
157  * description: A component which allows for the editing of a single line of text.
158  *
159  * @author  Timothy Prinzing
160  * @see #setActionCommand
161  * @see JPasswordField
162  * @see #addActionListener
163  */
164 public class JTextField extends JTextComponent implements SwingConstants {
165 
166     /**
167      * Constructs a new <code>TextField</code>.  A default model is created,
168      * the initial string is <code>null</code>,
169      * and the number of columns is set to 0.
170      */
171     public JTextField() {
172         this(null, null, 0);
173     }
174 
175     /**
176      * Constructs a new <code>TextField</code> initialized with the
177      * specified text. A default model is created and the number of
178      * columns is 0.
179      *
180      * @param text the text to be displayed, or <code>null</code>
181      */
182     public JTextField(String text) {
183         this(null, text, 0);
184     }
185 
186     /**
187      * Constructs a new empty <code>TextField</code> with the specified
188      * number of columns.
189      * A default model is created and the initial string is set to
190      * <code>null</code>.
191      *
192      * @param columns  the number of columns to use to calculate
193      *   the preferred width; if columns is set to zero, the
194      *   preferred width will be whatever naturally results from
195      *   the component implementation
196      */
197     public JTextField(int columns) {
198         this(null, null, columns);
199     }
200 
201     /**
202      * Constructs a new <code>TextField</code> initialized with the
203      * specified text and columns.  A default model is created.
204      *
205      * @param text the text to be displayed, or <code>null</code>
206      * @param columns  the number of columns to use to calculate
207      *   the preferred width; if columns is set to zero, the
208      *   preferred width will be whatever naturally results from
209      *   the component implementation
210      */
211     public JTextField(String text, int columns) {
212         this(null, text, columns);
213     }
214 
215     /**
216      * Constructs a new <code>JTextField</code> that uses the given text
217      * storage model and the given number of columns.
218      * This is the constructor through which the other constructors feed.
219      * If the document is <code>null</code>, a default model is created.
220      *
221      * @param doc  the text storage to use; if this is <code>null</code>,
222      *          a default will be provided by calling the
223      *          <code>createDefaultModel</code> method
224      * @param text  the initial string to display, or <code>null</code>
225      * @param columns  the number of columns to use to calculate
226      *   the preferred width &gt;= 0; if <code>columns</code>
227      *   is set to zero, the preferred width will be whatever
228      *   naturally results from the component implementation
229      * @exception IllegalArgumentException if <code>columns</code> &lt; 0
230      */
231     public JTextField(Document doc, String text, int columns) {
232         if (columns < 0) {
233             throw new IllegalArgumentException("columns less than zero.");
234         }
235         visibility = new DefaultBoundedRangeModel();
236         visibility.addChangeListener(new ScrollRepainter());
237         this.columns = columns;
238         if (doc == null) {
239             doc = createDefaultModel();
240         }
241         setDocument(doc);
242         if (text != null) {
243             setText(text);
244         }
245     }
246 
247     /**
248      * Gets the class ID for a UI.
249      *
250      * @return the string "TextFieldUI"
251      * @see JComponent#getUIClassID
252      * @see UIDefaults#getUI
253      */
254     public String getUIClassID() {
255         return uiClassID;
256     }
257 
258 
259     /**
260      * Associates the editor with a text document.
261      * The currently registered factory is used to build a view for
262      * the document, which gets displayed by the editor after revalidation.
263      * A PropertyChange event ("document") is propagated to each listener.
264      *
265      * @param doc  the document to display/edit
266      * @see #getDocument
267      * @beaninfo
268      *  description: the text document model
269      *        bound: true
270      *       expert: true
271      */
272     public void setDocument(Document doc) {
273         if (doc != null) {
274             doc.putProperty("filterNewlines", Boolean.TRUE);
275         }
276         super.setDocument(doc);
277     }
278 
279     /**
280      * Calls to <code>revalidate</code> that come from within the
281      * textfield itself will
282      * be handled by validating the textfield, unless the textfield
283      * is contained within a <code>JViewport</code>,
284      * in which case this returns false.
285      *
286      * @return if the parent of this textfield is a <code>JViewPort</code>
287      *          return false, otherwise return true
288      *
289      * @see JComponent#revalidate
290      * @see JComponent#isValidateRoot
291      * @see java.awt.Container#isValidateRoot
292      */
293     @Override
294     public boolean isValidateRoot() {
295         return !(SwingUtilities.getUnwrappedParent(this) instanceof JViewport);
296     }
297 
298 
299     /**
300      * Returns the horizontal alignment of the text.
301      * Valid keys are:
302      * <ul>
303      * <li><code>JTextField.LEFT</code>
304      * <li><code>JTextField.CENTER</code>
305      * <li><code>JTextField.RIGHT</code>
306      * <li><code>JTextField.LEADING</code>
307      * <li><code>JTextField.TRAILING</code>
308      * </ul>
309      *
310      * @return the horizontal alignment
311      */
312     public int getHorizontalAlignment() {
313         return horizontalAlignment;
314     }
315 
316     /**
317      * Sets the horizontal alignment of the text.
318      * Valid keys are:
319      * <ul>
320      * <li><code>JTextField.LEFT</code>
321      * <li><code>JTextField.CENTER</code>
322      * <li><code>JTextField.RIGHT</code>
323      * <li><code>JTextField.LEADING</code>
324      * <li><code>JTextField.TRAILING</code>
325      * </ul>
326      * <code>invalidate</code> and <code>repaint</code> are called when the
327      * alignment is set,
328      * and a <code>PropertyChange</code> event ("horizontalAlignment") is fired.
329      *
330      * @param alignment the alignment
331      * @exception IllegalArgumentException if <code>alignment</code>
332      *  is not a valid key
333      * @beaninfo
334      *   preferred: true
335      *       bound: true
336      * description: Set the field alignment to LEFT, CENTER, RIGHT,
337      *              LEADING (the default) or TRAILING
338      *        enum: LEFT JTextField.LEFT CENTER JTextField.CENTER RIGHT JTextField.RIGHT
339      *              LEADING JTextField.LEADING TRAILING JTextField.TRAILING
340      */
341      public void setHorizontalAlignment(int alignment) {
342         if (alignment == horizontalAlignment) return;
343         int oldValue = horizontalAlignment;
344         if ((alignment == LEFT) || (alignment == CENTER) ||
345             (alignment == RIGHT)|| (alignment == LEADING) ||
346             (alignment == TRAILING)) {
347             horizontalAlignment = alignment;
348         } else {
349             throw new IllegalArgumentException("horizontalAlignment");
350         }
351         firePropertyChange("horizontalAlignment", oldValue, horizontalAlignment);
352         invalidate();
353         repaint();
354     }
355 
356     /**
357      * Creates the default implementation of the model
358      * to be used at construction if one isn't explicitly
359      * given.  An instance of <code>PlainDocument</code> is returned.
360      *
361      * @return the default model implementation
362      */
363     protected Document createDefaultModel() {
364         return new PlainDocument();
365     }
366 
367     /**
368      * Returns the number of columns in this <code>TextField</code>.
369      *
370      * @return the number of columns &gt;= 0
371      */
372     public int getColumns() {
373         return columns;
374     }
375 
376     /**
377      * Sets the number of columns in this <code>TextField</code>,
378      * and then invalidate the layout.
379      *
380      * @param columns the number of columns &gt;= 0
381      * @exception IllegalArgumentException if <code>columns</code>
382      *          is less than 0
383      * @beaninfo
384      * description: the number of columns preferred for display
385      */
386     public void setColumns(int columns) {
387         int oldVal = this.columns;
388         if (columns < 0) {
389             throw new IllegalArgumentException("columns less than zero.");
390         }
391         if (columns != oldVal) {
392             this.columns = columns;
393             invalidate();
394         }
395     }
396 
397     /**
398      * Returns the column width.
399      * The meaning of what a column is can be considered a fairly weak
400      * notion for some fonts.  This method is used to define the width
401      * of a column.  By default this is defined to be the width of the
402      * character <em>m</em> for the font used.  This method can be
403      * redefined to be some alternative amount
404      *
405      * @return the column width &gt;= 1
406      */
407     protected int getColumnWidth() {
408         if (columnWidth == 0) {
409             FontMetrics metrics = getFontMetrics(getFont());
410             columnWidth = metrics.charWidth('m');
411         }
412         return columnWidth;
413     }
414 
415     /**
416      * Returns the preferred size <code>Dimensions</code> needed for this
417      * <code>TextField</code>.  If a non-zero number of columns has been
418      * set, the width is set to the columns multiplied by
419      * the column width.
420      *
421      * @return the dimension of this textfield
422      */
423     public Dimension getPreferredSize() {
424         Dimension size = super.getPreferredSize();
425         if (columns != 0) {
426             Insets insets = getInsets();
427             size.width = columns * getColumnWidth() +
428                 insets.left + insets.right;
429         }
430         return size;
431     }
432 
433     /**
434      * Sets the current font.  This removes cached row height and column
435      * width so the new font will be reflected.
436      * <code>revalidate</code> is called after setting the font.
437      *
438      * @param f the new font
439      */
440     public void setFont(Font f) {
441         super.setFont(f);
442         columnWidth = 0;
443     }
444 
445     /**
446      * Adds the specified action listener to receive
447      * action events from this textfield.
448      *
449      * @param l the action listener to be added
450      */
451     public synchronized void addActionListener(ActionListener l) {
452         listenerList.add(ActionListener.class, l);
453     }
454 
455     /**
456      * Removes the specified action listener so that it no longer
457      * receives action events from this textfield.
458      *
459      * @param l the action listener to be removed
460      */
461     public synchronized void removeActionListener(ActionListener l) {
462         if ((l != null) && (getAction() == l)) {
463             setAction(null);
464         } else {
465             listenerList.remove(ActionListener.class, l);
466         }
467     }
468 
469     /**
470      * Returns an array of all the <code>ActionListener</code>s added
471      * to this JTextField with addActionListener().
472      *
473      * @return all of the <code>ActionListener</code>s added or an empty
474      *         array if no listeners have been added
475      * @since 1.4
476      */
477     public synchronized ActionListener[] getActionListeners() {
478         return listenerList.getListeners(ActionListener.class);
479     }
480 
481     /**
482      * Notifies all listeners that have registered interest for
483      * notification on this event type.  The event instance
484      * is lazily created.
485      * The listener list is processed in last to
486      * first order.
487      * @see EventListenerList
488      */
489     protected void fireActionPerformed() {
490         // Guaranteed to return a non-null array
491         Object[] listeners = listenerList.getListenerList();
492         int modifiers = 0;
493         AWTEvent currentEvent = EventQueue.getCurrentEvent();
494         if (currentEvent instanceof InputEvent) {
495             modifiers = ((InputEvent)currentEvent).getModifiers();
496         } else if (currentEvent instanceof ActionEvent) {
497             modifiers = ((ActionEvent)currentEvent).getModifiers();
498         }
499         ActionEvent e =
500             new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
501                             (command != null) ? command : getText(),
502                             EventQueue.getMostRecentEventTime(), modifiers);
503 
504         // Process the listeners last to first, notifying
505         // those that are interested in this event
506         for (int i = listeners.length-2; i>=0; i-=2) {
507             if (listeners[i]==ActionListener.class) {
508                 ((ActionListener)listeners[i+1]).actionPerformed(e);
509             }
510         }
511     }
512 
513     /**
514      * Sets the command string used for action events.
515      *
516      * @param command the command string
517      */
518     public void setActionCommand(String command) {
519         this.command = command;
520     }
521 
522     private Action action;
523     private PropertyChangeListener actionPropertyChangeListener;
524 
525     /**
526      * Sets the <code>Action</code> for the <code>ActionEvent</code> source.
527      * The new <code>Action</code> replaces
528      * any previously set <code>Action</code> but does not affect
529      * <code>ActionListeners</code> independently
530      * added with <code>addActionListener</code>.
531      * If the <code>Action</code> is already a registered
532      * <code>ActionListener</code>
533      * for the <code>ActionEvent</code> source, it is not re-registered.
534      * <p>
535      * Setting the <code>Action</code> results in immediately changing
536      * all the properties described in <a href="Action.html#buttonActions">
537      * Swing Components Supporting <code>Action</code></a>.
538      * Subsequently, the textfield's properties are automatically updated
539      * as the <code>Action</code>'s properties change.
540      * <p>
541      * This method uses three other methods to set
542      * and help track the <code>Action</code>'s property values.
543      * It uses the <code>configurePropertiesFromAction</code> method
544      * to immediately change the textfield's properties.
545      * To track changes in the <code>Action</code>'s property values,
546      * this method registers the <code>PropertyChangeListener</code>
547      * returned by <code>createActionPropertyChangeListener</code>. The
548      * default {@code PropertyChangeListener} invokes the
549      * {@code actionPropertyChanged} method when a property in the
550      * {@code Action} changes.
551      *
552      * @param a the <code>Action</code> for the <code>JTextField</code>,
553      *          or <code>null</code>
554      * @since 1.3
555      * @see Action
556      * @see #getAction
557      * @see #configurePropertiesFromAction
558      * @see #createActionPropertyChangeListener
559      * @see #actionPropertyChanged
560      * @beaninfo
561      *        bound: true
562      *    attribute: visualUpdate true
563      *  description: the Action instance connected with this ActionEvent source
564      */
565     public void setAction(Action a) {
566         Action oldValue = getAction();
567         if (action==null || !action.equals(a)) {
568             action = a;
569             if (oldValue!=null) {
570                 removeActionListener(oldValue);
571                 oldValue.removePropertyChangeListener(actionPropertyChangeListener);
572                 actionPropertyChangeListener = null;
573             }
574             configurePropertiesFromAction(action);
575             if (action!=null) {
576                 // Don't add if it is already a listener
577                 if (!isListener(ActionListener.class, action)) {
578                     addActionListener(action);
579                 }
580                 // Reverse linkage:
581                 actionPropertyChangeListener = createActionPropertyChangeListener(action);
582                 action.addPropertyChangeListener(actionPropertyChangeListener);
583             }
584             firePropertyChange("action", oldValue, action);
585         }
586     }
587 
588     private boolean isListener(Class c, ActionListener a) {
589         boolean isListener = false;
590         Object[] listeners = listenerList.getListenerList();
591         for (int i = listeners.length-2; i>=0; i-=2) {
592             if (listeners[i]==c && listeners[i+1]==a) {
593                     isListener=true;
594             }
595         }
596         return isListener;
597     }
598 
599     /**
600      * Returns the currently set <code>Action</code> for this
601      * <code>ActionEvent</code> source, or <code>null</code>
602      * if no <code>Action</code> is set.
603      *
604      * @return the <code>Action</code> for this <code>ActionEvent</code> source,
605      *          or <code>null</code>
606      * @since 1.3
607      * @see Action
608      * @see #setAction
609      */
610     public Action getAction() {
611         return action;
612     }
613 
614     /**
615      * Sets the properties on this textfield to match those in the specified
616      * <code>Action</code>.  Refer to <a href="Action.html#buttonActions">
617      * Swing Components Supporting <code>Action</code></a> for more
618      * details as to which properties this sets.
619      *
620      * @param a the <code>Action</code> from which to get the properties,
621      *          or <code>null</code>
622      * @since 1.3
623      * @see Action
624      * @see #setAction
625      */
626     protected void configurePropertiesFromAction(Action a) {
627         AbstractAction.setEnabledFromAction(this, a);
628         AbstractAction.setToolTipTextFromAction(this, a);
629         setActionCommandFromAction(a);
630     }
631 
632     /**
633      * Updates the textfield's state in response to property changes in
634      * associated action. This method is invoked from the
635      * {@code PropertyChangeListener} returned from
636      * {@code createActionPropertyChangeListener}. Subclasses do not normally
637      * need to invoke this. Subclasses that support additional {@code Action}
638      * properties should override this and
639      * {@code configurePropertiesFromAction}.
640      * <p>
641      * Refer to the table at <a href="Action.html#buttonActions">
642      * Swing Components Supporting <code>Action</code></a> for a list of
643      * the properties this method sets.
644      *
645      * @param action the <code>Action</code> associated with this textfield
646      * @param propertyName the name of the property that changed
647      * @since 1.6
648      * @see Action
649      * @see #configurePropertiesFromAction
650      */
651     protected void actionPropertyChanged(Action action, String propertyName) {
652         if (propertyName == Action.ACTION_COMMAND_KEY) {
653             setActionCommandFromAction(action);
654         } else if (propertyName == "enabled") {
655             AbstractAction.setEnabledFromAction(this, action);
656         } else if (propertyName == Action.SHORT_DESCRIPTION) {
657             AbstractAction.setToolTipTextFromAction(this, action);
658         }
659     }
660 
661     private void setActionCommandFromAction(Action action) {
662         setActionCommand((action == null) ? null :
663                          (String)action.getValue(Action.ACTION_COMMAND_KEY));
664     }
665 
666     /**
667      * Creates and returns a <code>PropertyChangeListener</code> that is
668      * responsible for listening for changes from the specified
669      * <code>Action</code> and updating the appropriate properties.
670      * <p>
671      * <b>Warning:</b> If you subclass this do not create an anonymous
672      * inner class.  If you do the lifetime of the textfield will be tied to
673      * that of the <code>Action</code>.
674      *
675      * @param a the textfield's action
676      * @since 1.3
677      * @see Action
678      * @see #setAction
679      */
680     protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
681         return new TextFieldActionPropertyChangeListener(this, a);
682     }
683 
684     private static class TextFieldActionPropertyChangeListener extends
685                          ActionPropertyChangeListener<JTextField> {
686         TextFieldActionPropertyChangeListener(JTextField tf, Action a) {
687             super(tf, a);
688         }
689 
690         protected void actionPropertyChanged(JTextField textField,
691                                              Action action,
692                                              PropertyChangeEvent e) {
693             if (AbstractAction.shouldReconfigure(e)) {
694                 textField.configurePropertiesFromAction(action);
695             } else {
696                 textField.actionPropertyChanged(action, e.getPropertyName());
697             }
698         }
699     }
700 
701     /**
702      * Fetches the command list for the editor.  This is
703      * the list of commands supported by the plugged-in UI
704      * augmented by the collection of commands that the
705      * editor itself supports.  These are useful for binding
706      * to events, such as in a keymap.
707      *
708      * @return the command list
709      */
710     public Action[] getActions() {
711         return TextAction.augmentList(super.getActions(), defaultActions);
712     }
713 
714     /**
715      * Processes action events occurring on this textfield by
716      * dispatching them to any registered <code>ActionListener</code> objects.
717      * This is normally called by the controller registered with
718      * textfield.
719      */
720     public void postActionEvent() {
721         fireActionPerformed();
722     }
723 
724     // --- Scrolling support -----------------------------------
725 
726     /**
727      * Gets the visibility of the text field.  This can
728      * be adjusted to change the location of the visible
729      * area if the size of the field is greater than
730      * the area that was allocated to the field.
731      *
732      * <p>
733      * The fields look-and-feel implementation manages
734      * the values of the minimum, maximum, and extent
735      * properties on the <code>BoundedRangeModel</code>.
736      *
737      * @return the visibility
738      * @see BoundedRangeModel
739      */
740     public BoundedRangeModel getHorizontalVisibility() {
741         return visibility;
742     }
743 
744     /**
745      * Gets the scroll offset, in pixels.
746      *
747      * @return the offset &gt;= 0
748      */
749     public int getScrollOffset() {
750         return visibility.getValue();
751     }
752 
753     /**
754      * Sets the scroll offset, in pixels.
755      *
756      * @param scrollOffset the offset &gt;= 0
757      */
758     public void setScrollOffset(int scrollOffset) {
759         visibility.setValue(scrollOffset);
760     }
761 
762     /**
763      * Scrolls the field left or right.
764      *
765      * @param r the region to scroll
766      */
767     public void scrollRectToVisible(Rectangle r) {
768         // convert to coordinate system of the bounded range
769         Insets i = getInsets();
770         int x0 = r.x + visibility.getValue() - i.left;
771         int x1 = x0 + r.width;
772         if (x0 < visibility.getValue()) {
773             // Scroll to the left
774             visibility.setValue(x0);
775         } else if(x1 > visibility.getValue() + visibility.getExtent()) {
776             // Scroll to the right
777             visibility.setValue(x1 - visibility.getExtent());
778         }
779     }
780 
781     /**
782      * Returns true if the receiver has an <code>ActionListener</code>
783      * installed.
784      */
785     boolean hasActionListener() {
786         // Guaranteed to return a non-null array
787         Object[] listeners = listenerList.getListenerList();
788         // Process the listeners last to first, notifying
789         // those that are interested in this event
790         for (int i = listeners.length-2; i>=0; i-=2) {
791             if (listeners[i]==ActionListener.class) {
792                 return true;
793             }
794         }
795         return false;
796     }
797 
798     // --- variables -------------------------------------------
799 
800     /**
801      * Name of the action to send notification that the
802      * contents of the field have been accepted.  Typically
803      * this is bound to a carriage-return.
804      */
805     public static final String notifyAction = "notify-field-accept";
806 
807     private BoundedRangeModel visibility;
808     private int horizontalAlignment = LEADING;
809     private int columns;
810     private int columnWidth;
811     private String command;
812 
813     private static final Action[] defaultActions = {
814         new NotifyAction()
815     };
816 
817     /**
818      * @see #getUIClassID
819      * @see #readObject
820      */
821     private static final String uiClassID = "TextFieldUI";
822 
823     // --- Action implementations -----------------------------------
824 
825     // Note that JFormattedTextField.CommitAction extends this
826     static class NotifyAction extends TextAction {
827 
828         NotifyAction() {
829             super(notifyAction);
830         }
831 
832         public void actionPerformed(ActionEvent e) {
833             JTextComponent target = getFocusedComponent();
834             if (target instanceof JTextField) {
835                 JTextField field = (JTextField) target;
836                 field.postActionEvent();
837             }
838         }
839 
840         public boolean isEnabled() {
841             JTextComponent target = getFocusedComponent();
842             if (target instanceof JTextField) {
843                 return ((JTextField)target).hasActionListener();
844             }
845             return false;
846         }
847     }
848 
849     class ScrollRepainter implements ChangeListener, Serializable {
850 
851         public void stateChanged(ChangeEvent e) {
852             repaint();
853         }
854 
855     }
856 
857 
858     /**
859      * See <code>readObject</code> and <code>writeObject</code> in
860      * <code>JComponent</code> for more
861      * information about serialization in Swing.
862      */
863     private void writeObject(ObjectOutputStream s) throws IOException {
864         s.defaultWriteObject();
865         if (getUIClassID().equals(uiClassID)) {
866             byte count = JComponent.getWriteObjCounter(this);
867             JComponent.setWriteObjCounter(this, --count);
868             if (count == 0 && ui != null) {
869                 ui.installUI(this);
870             }
871         }
872     }
873 
874 
875     /**
876      * Returns a string representation of this <code>JTextField</code>.
877      * This method is intended to be used only for debugging purposes,
878      * and the content and format of the returned string may vary between
879      * implementations. The returned string may be empty but may not
880      * be <code>null</code>.
881      *
882      * @return  a string representation of this <code>JTextField</code>
883      */
884     protected String paramString() {
885         String horizontalAlignmentString;
886         if (horizontalAlignment == LEFT) {
887             horizontalAlignmentString = "LEFT";
888         } else if (horizontalAlignment == CENTER) {
889             horizontalAlignmentString = "CENTER";
890         } else if (horizontalAlignment == RIGHT) {
891             horizontalAlignmentString = "RIGHT";
892         } else if (horizontalAlignment == LEADING) {
893             horizontalAlignmentString = "LEADING";
894         } else if (horizontalAlignment == TRAILING) {
895             horizontalAlignmentString = "TRAILING";
896         } else horizontalAlignmentString = "";
897         String commandString = (command != null ?
898                                 command : "");
899 
900         return super.paramString() +
901         ",columns=" + columns +
902         ",columnWidth=" + columnWidth +
903         ",command=" + commandString +
904         ",horizontalAlignment=" + horizontalAlignmentString;
905     }
906 
907 
908 /////////////////
909 // Accessibility support
910 ////////////////
911 
912 
913     /**
914      * Gets the <code>AccessibleContext</code> associated with this
915      * <code>JTextField</code>. For <code>JTextFields</code>,
916      * the <code>AccessibleContext</code> takes the form of an
917      * <code>AccessibleJTextField</code>.
918      * A new <code>AccessibleJTextField</code> instance is created
919      * if necessary.
920      *
921      * @return an <code>AccessibleJTextField</code> that serves as the
922      *         <code>AccessibleContext</code> of this <code>JTextField</code>
923      */
924     public AccessibleContext getAccessibleContext() {
925         if (accessibleContext == null) {
926             accessibleContext = new AccessibleJTextField();
927         }
928         return accessibleContext;
929     }
930 
931     /**
932      * This class implements accessibility support for the
933      * <code>JTextField</code> class.  It provides an implementation of the
934      * Java Accessibility API appropriate to text field user-interface
935      * elements.
936      * <p>
937      * <strong>Warning:</strong>
938      * Serialized objects of this class will not be compatible with
939      * future Swing releases. The current serialization support is
940      * appropriate for short term storage or RMI between applications running
941      * the same version of Swing.  As of 1.4, support for long term storage
942      * of all JavaBeans&trade;
943      * has been added to the <code>java.beans</code> package.
944      * Please see {@link java.beans.XMLEncoder}.
945      */
946     protected class AccessibleJTextField extends AccessibleJTextComponent {
947 
948         /**
949          * Gets the state set of this object.
950          *
951          * @return an instance of AccessibleStateSet describing the states
952          * of the object
953          * @see AccessibleState
954          */
955         public AccessibleStateSet getAccessibleStateSet() {
956             AccessibleStateSet states = super.getAccessibleStateSet();
957             states.add(AccessibleState.SINGLE_LINE);
958             return states;
959         }
960     }
961 }