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  */
  25 package javax.swing;
  26 
  27 import java.awt.*;
  28 import java.awt.event.*;
  29 import java.beans.JavaBean;
  30 import java.beans.BeanProperty;
  31 import java.beans.PropertyChangeEvent;
  32 import java.beans.PropertyChangeListener;
  33 import javax.swing.text.*;
  34 import javax.swing.event.*;
  35 import javax.accessibility.*;
  36 
  37 import java.io.ObjectOutputStream;
  38 import java.io.IOException;
  39 import 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="https://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
 163 public 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 }