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