1 /*
   2  * Copyright (c) 1997, 2006, 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.*;
  30 import javax.swing.text.*;
  31 import javax.swing.plaf.*;
  32 import javax.swing.event.*;
  33 import javax.accessibility.*;
  34 
  35 import java.io.ObjectOutputStream;
  36 import java.io.ObjectInputStream;
  37 import java.io.IOException;
  38 import java.io.Serializable;
  39 
  40 /**
  41  * <code>JTextField</code> is a lightweight component that allows the editing
  42  * of a single line of text.
  43  * For information on and examples of using text fields,
  44  * see
  45  * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/textfield.html">How to Use Text Fields</a>
  46  * in <em>The Java Tutorial.</em>
  47  *
  48  * <p>
  49  * <code>JTextField</code> is intended to be source-compatible
  50  * with <code>java.awt.TextField</code> where it is reasonable to do so.  This
  51  * component has capabilities not found in the <code>java.awt.TextField</code>
  52  * class.  The superclass should be consulted for additional capabilities.
  53  * <p>
  54  * <code>JTextField</code> has a method to establish the string used as the
  55  * command string for the action event that gets fired.  The
  56  * <code>java.awt.TextField</code> used the text of the field as the command
  57  * string for the <code>ActionEvent</code>.
  58  * <code>JTextField</code> will use the command
  59  * string set with the <code>setActionCommand</code> method if not <code>null</code>,
  60  * otherwise it will use the text of the field as a compatibility with
  61  * <code>java.awt.TextField</code>.
  62  * <p>
  63  * The method <code>setEchoChar</code> and <code>getEchoChar</code>
  64  * are not provided directly to avoid a new implementation of a
  65  * pluggable look-and-feel inadvertently exposing password characters.
  66  * To provide password-like services a separate class <code>JPasswordField</code>
  67  * extends <code>JTextField</code> to provide this service with an independently
  68  * pluggable look-and-feel.
  69  * <p>
  70  * The <code>java.awt.TextField</code> could be monitored for changes by adding
  71  * a <code>TextListener</code> for <code>TextEvent</code>'s.
  72  * In the <code>JTextComponent</code> based
  73  * components, changes are broadcasted from the model via a
  74  * <code>DocumentEvent</code> to <code>DocumentListeners</code>.
  75  * The <code>DocumentEvent</code> gives
  76  * the location of the change and the kind of change if desired.
  77  * The code fragment might look something like:
  78  * <pre><code>
  79  * &nbsp;   DocumentListener myListener = ??;
  80  * &nbsp;   JTextField myArea = ??;
  81  * &nbsp;   myArea.getDocument().addDocumentListener(myListener);
  82  * </code></pre>
  83  * <p>
  84  * The horizontal alignment of <code>JTextField</code> can be set to be left
  85  * justified, leading justified, centered, right justified or trailing justified.
  86  * Right/trailing justification is useful if the required size
  87  * of the field text is smaller than the size allocated to it.
  88  * This is determined by the <code>setHorizontalAlignment</code>
  89  * and <code>getHorizontalAlignment</code> methods.  The default
  90  * is to be leading justified.
  91  * <p>
  92  * How the text field consumes VK_ENTER events depends
  93  * on whether the text field has any action listeners.
  94  * If so, then VK_ENTER results in the listeners
  95  * getting an ActionEvent,
  96  * and the VK_ENTER event is consumed.
  97  * This is compatible with how AWT text fields handle VK_ENTER events.
  98  * If the text field has no action listeners, then as of v 1.3 the VK_ENTER
  99  * event is not consumed.  Instead, the bindings of ancestor components
 100  * are processed, which enables the default button feature of
 101  * JFC/Swing to work.
 102  * <p>
 103  * Customized fields can easily be created by extending the model and
 104  * changing the default model provided.  For example, the following piece
 105  * of code will create a field that holds only upper case characters.  It
 106  * will work even if text is pasted into from the clipboard or it is altered via
 107  * programmatic changes.
 108  * <pre><code>
 109 
 110 &nbsp;public class UpperCaseField extends JTextField {
 111 &nbsp;
 112 &nbsp;    public UpperCaseField(int cols) {
 113 &nbsp;        super(cols);
 114 &nbsp;    }
 115 &nbsp;
 116 &nbsp;    protected Document createDefaultModel() {
 117 &nbsp;        return new UpperCaseDocument();
 118 &nbsp;    }
 119 &nbsp;
 120 &nbsp;    static class UpperCaseDocument extends PlainDocument {
 121 &nbsp;
 122 &nbsp;        public void insertString(int offs, String str, AttributeSet a)
 123 &nbsp;            throws BadLocationException {
 124 &nbsp;
 125 &nbsp;            if (str == null) {
 126 &nbsp;                return;
 127 &nbsp;            }
 128 &nbsp;            char[] upper = str.toCharArray();
 129 &nbsp;            for (int i = 0; i < upper.length; i++) {
 130 &nbsp;                upper[i] = Character.toUpperCase(upper[i]);
 131 &nbsp;            }
 132 &nbsp;            super.insertString(offs, new String(upper), a);
 133 &nbsp;        }
 134 &nbsp;    }
 135 &nbsp;}
 136 
 137  * </code></pre>
 138  * <p>
 139  * <strong>Warning:</strong> Swing is not thread safe. For more
 140  * information see <a
 141  * href="package-summary.html#threading">Swing's Threading
 142  * Policy</a>.
 143  * <p>
 144  * <strong>Warning:</strong>
 145  * Serialized objects of this class will not be compatible with
 146  * future Swing releases. The current serialization support is
 147  * appropriate for short term storage or RMI between applications running
 148  * the same version of Swing.  As of 1.4, support for long term storage
 149  * of all JavaBeans<sup><font size="-2">TM</font></sup>
 150  * has been added to the <code>java.beans</code> package.
 151  * Please see {@link java.beans.XMLEncoder}.
 152  *
 153  * @beaninfo
 154  *   attribute: isContainer false
 155  * description: A component which allows for the editing of a single line of text.
 156  *
 157  * @author  Timothy Prinzing
 158  * @see #setActionCommand
 159  * @see JPasswordField
 160  * @see #addActionListener
 161  */
 162 public class JTextField extends JTextComponent implements SwingConstants {
 163 
 164     /**
 165      * Constructs a new <code>TextField</code>.  A default model is created,
 166      * the initial string is <code>null</code>,
 167      * and the number of columns is set to 0.
 168      */
 169     public JTextField() {
 170         this(null, null, 0);
 171     }
 172 
 173     /**
 174      * Constructs a new <code>TextField</code> initialized with the
 175      * specified text. A default model is created and the number of
 176      * columns is 0.
 177      *
 178      * @param text the text to be displayed, or <code>null</code>
 179      */
 180     public JTextField(String text) {
 181         this(null, text, 0);
 182     }
 183 
 184     /**
 185      * Constructs a new empty <code>TextField</code> with the specified
 186      * number of columns.
 187      * A default model is created and the initial string is set to
 188      * <code>null</code>.
 189      *
 190      * @param columns  the number of columns to use to calculate
 191      *   the preferred width; if columns is set to zero, the
 192      *   preferred width will be whatever naturally results from
 193      *   the component implementation
 194      */
 195     public JTextField(int columns) {
 196         this(null, null, columns);
 197     }
 198 
 199     /**
 200      * Constructs a new <code>TextField</code> initialized with the
 201      * specified text and columns.  A default model is created.
 202      *
 203      * @param text the text to be displayed, or <code>null</code>
 204      * @param columns  the number of columns to use to calculate
 205      *   the preferred width; if columns is set to zero, the
 206      *   preferred width will be whatever naturally results from
 207      *   the component implementation
 208      */
 209     public JTextField(String text, int columns) {
 210         this(null, text, columns);
 211     }
 212 
 213     /**
 214      * Constructs a new <code>JTextField</code> that uses the given text
 215      * storage model and the given number of columns.
 216      * This is the constructor through which the other constructors feed.
 217      * If the document is <code>null</code>, a default model is created.
 218      *
 219      * @param doc  the text storage to use; if this is <code>null</code>,
 220      *          a default will be provided by calling the
 221      *          <code>createDefaultModel</code> method
 222      * @param text  the initial string to display, or <code>null</code>
 223      * @param columns  the number of columns to use to calculate
 224      *   the preferred width >= 0; if <code>columns</code>
 225      *   is set to zero, the preferred width will be whatever
 226      *   naturally results from the component implementation
 227      * @exception IllegalArgumentException if <code>columns</code> < 0
 228      */
 229     public JTextField(Document doc, String text, int columns) {
 230         if (columns < 0) {
 231             throw new IllegalArgumentException("columns less than zero.");
 232         }
 233         visibility = new DefaultBoundedRangeModel();
 234         visibility.addChangeListener(new ScrollRepainter());
 235         this.columns = columns;
 236         if (doc == null) {
 237             doc = createDefaultModel();
 238         }
 239         setDocument(doc);
 240         if (text != null) {
 241             setText(text);
 242         }
 243     }
 244 
 245     /**
 246      * Gets the class ID for a UI.
 247      *
 248      * @return the string "TextFieldUI"
 249      * @see JComponent#getUIClassID
 250      * @see UIDefaults#getUI
 251      */
 252     public String getUIClassID() {
 253         return uiClassID;
 254     }
 255 
 256 
 257     /**
 258      * Associates the editor with a text document.
 259      * The currently registered factory is used to build a view for
 260      * the document, which gets displayed by the editor after revalidation.
 261      * A PropertyChange event ("document") is propagated to each listener.
 262      *
 263      * @param doc  the document to display/edit
 264      * @see #getDocument
 265      * @beaninfo
 266      *  description: the text document model
 267      *        bound: true
 268      *       expert: true
 269      */
 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      */
 290     public boolean isValidateRoot() {
 291         Component parent = getParent();
 292         if (parent instanceof JViewport) {
 293             return false;
 294         }
 295         return true;
 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 >= 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 >= 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 >= 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 (ActionListener[])listenerList.getListeners(
 479                 ActionListener.class);
 480     }
 481 
 482     /**
 483      * Notifies all listeners that have registered interest for
 484      * notification on this event type.  The event instance
 485      * is lazily created.
 486      * The listener list is processed in last to
 487      * first order.
 488      * @see EventListenerList
 489      */
 490     protected void fireActionPerformed() {
 491         // Guaranteed to return a non-null array
 492         Object[] listeners = listenerList.getListenerList();
 493         int modifiers = 0;
 494         AWTEvent currentEvent = EventQueue.getCurrentEvent();
 495         if (currentEvent instanceof InputEvent) {
 496             modifiers = ((InputEvent)currentEvent).getModifiers();
 497         } else if (currentEvent instanceof ActionEvent) {
 498             modifiers = ((ActionEvent)currentEvent).getModifiers();
 499         }
 500         ActionEvent e =
 501             new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
 502                             (command != null) ? command : getText(),
 503                             EventQueue.getMostRecentEventTime(), modifiers);
 504 
 505         // Process the listeners last to first, notifying
 506         // those that are interested in this event
 507         for (int i = listeners.length-2; i>=0; i-=2) {
 508             if (listeners[i]==ActionListener.class) {
 509                 ((ActionListener)listeners[i+1]).actionPerformed(e);
 510             }
 511         }
 512     }
 513 
 514     /**
 515      * Sets the command string used for action events.
 516      *
 517      * @param command the command string
 518      */
 519     public void setActionCommand(String command) {
 520         this.command = command;
 521     }
 522 
 523     private Action action;
 524     private PropertyChangeListener actionPropertyChangeListener;
 525 
 526     /**
 527      * Sets the <code>Action</code> for the <code>ActionEvent</code> source.
 528      * The new <code>Action</code> replaces
 529      * any previously set <code>Action</code> but does not affect
 530      * <code>ActionListeners</code> independently
 531      * added with <code>addActionListener</code>.
 532      * If the <code>Action</code> is already a registered
 533      * <code>ActionListener</code>
 534      * for the <code>ActionEvent</code> source, it is not re-registered.
 535      * <p>
 536      * Setting the <code>Action</code> results in immediately changing
 537      * all the properties described in <a href="Action.html#buttonActions">
 538      * Swing Components Supporting <code>Action</code></a>.
 539      * Subsequently, the textfield's properties are automatically updated
 540      * as the <code>Action</code>'s properties change.
 541      * <p>
 542      * This method uses three other methods to set
 543      * and help track the <code>Action</code>'s property values.
 544      * It uses the <code>configurePropertiesFromAction</code> method
 545      * to immediately change the textfield's properties.
 546      * To track changes in the <code>Action</code>'s property values,
 547      * this method registers the <code>PropertyChangeListener</code>
 548      * returned by <code>createActionPropertyChangeListener</code>. The
 549      * default {@code PropertyChangeListener} invokes the
 550      * {@code actionPropertyChanged} method when a property in the
 551      * {@code Action} changes.
 552      *
 553      * @param a the <code>Action</code> for the <code>JTextField</code>,
 554      *          or <code>null</code>
 555      * @since 1.3
 556      * @see Action
 557      * @see #getAction
 558      * @see #configurePropertiesFromAction
 559      * @see #createActionPropertyChangeListener
 560      * @see #actionPropertyChanged
 561      * @beaninfo
 562      *        bound: true
 563      *    attribute: visualUpdate true
 564      *  description: the Action instance connected with this ActionEvent source
 565      */
 566     public void setAction(Action a) {
 567         Action oldValue = getAction();
 568         if (action==null || !action.equals(a)) {
 569             action = a;
 570             if (oldValue!=null) {
 571                 removeActionListener(oldValue);
 572                 oldValue.removePropertyChangeListener(actionPropertyChangeListener);
 573                 actionPropertyChangeListener = null;
 574             }
 575             configurePropertiesFromAction(action);
 576             if (action!=null) {
 577                 // Don't add if it is already a listener
 578                 if (!isListener(ActionListener.class, action)) {
 579                     addActionListener(action);
 580                 }
 581                 // Reverse linkage:
 582                 actionPropertyChangeListener = createActionPropertyChangeListener(action);
 583                 action.addPropertyChangeListener(actionPropertyChangeListener);
 584             }
 585             firePropertyChange("action", oldValue, action);
 586         }
 587     }
 588 
 589     private boolean isListener(Class c, ActionListener a) {
 590         boolean isListener = false;
 591         Object[] listeners = listenerList.getListenerList();
 592         for (int i = listeners.length-2; i>=0; i-=2) {
 593             if (listeners[i]==c && listeners[i+1]==a) {
 594                     isListener=true;
 595             }
 596         }
 597         return isListener;
 598     }
 599 
 600     /**
 601      * Returns the currently set <code>Action</code> for this
 602      * <code>ActionEvent</code> source, or <code>null</code>
 603      * if no <code>Action</code> is set.
 604      *
 605      * @return the <code>Action</code> for this <code>ActionEvent</code> source,
 606      *          or <code>null</code>
 607      * @since 1.3
 608      * @see Action
 609      * @see #setAction
 610      */
 611     public Action getAction() {
 612         return action;
 613     }
 614 
 615     /**
 616      * Sets the properties on this textfield to match those in the specified
 617      * <code>Action</code>.  Refer to <a href="Action.html#buttonActions">
 618      * Swing Components Supporting <code>Action</code></a> for more
 619      * details as to which properties this sets.
 620      *
 621      * @param a the <code>Action</code> from which to get the properties,
 622      *          or <code>null</code>
 623      * @since 1.3
 624      * @see Action
 625      * @see #setAction
 626      */
 627     protected void configurePropertiesFromAction(Action a) {
 628         AbstractAction.setEnabledFromAction(this, a);
 629         AbstractAction.setToolTipTextFromAction(this, a);
 630         setActionCommandFromAction(a);
 631     }
 632 
 633     /**
 634      * Updates the textfield's state in response to property changes in
 635      * associated action. This method is invoked from the
 636      * {@code PropertyChangeListener} returned from
 637      * {@code createActionPropertyChangeListener}. Subclasses do not normally
 638      * need to invoke this. Subclasses that support additional {@code Action}
 639      * properties should override this and
 640      * {@code configurePropertiesFromAction}.
 641      * <p>
 642      * Refer to the table at <a href="Action.html#buttonActions">
 643      * Swing Components Supporting <code>Action</code></a> for a list of
 644      * the properties this method sets.
 645      *
 646      * @param action the <code>Action</code> associated with this textfield
 647      * @param propertyName the name of the property that changed
 648      * @since 1.6
 649      * @see Action
 650      * @see #configurePropertiesFromAction
 651      */
 652     protected void actionPropertyChanged(Action action, String propertyName) {
 653         if (propertyName == Action.ACTION_COMMAND_KEY) {
 654             setActionCommandFromAction(action);
 655         } else if (propertyName == "enabled") {
 656             AbstractAction.setEnabledFromAction(this, action);
 657         } else if (propertyName == Action.SHORT_DESCRIPTION) {
 658             AbstractAction.setToolTipTextFromAction(this, action);
 659         }
 660     }
 661 
 662     private void setActionCommandFromAction(Action action) {
 663         setActionCommand((action == null) ? null :
 664                          (String)action.getValue(Action.ACTION_COMMAND_KEY));
 665     }
 666 
 667     /**
 668      * Creates and returns a <code>PropertyChangeListener</code> that is
 669      * responsible for listening for changes from the specified
 670      * <code>Action</code> and updating the appropriate properties.
 671      * <p>
 672      * <b>Warning:</b> If you subclass this do not create an anonymous
 673      * inner class.  If you do the lifetime of the textfield will be tied to
 674      * that of the <code>Action</code>.
 675      *
 676      * @param a the textfield's action
 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     public Action[] getActions() {
 712         return TextAction.augmentList(super.getActions(), defaultActions);
 713     }
 714 
 715     /**
 716      * Processes action events occurring on this textfield by
 717      * dispatching them to any registered <code>ActionListener</code> objects.
 718      * This is normally called by the controller registered with
 719      * textfield.
 720      */
 721     public void postActionEvent() {
 722         fireActionPerformed();
 723     }
 724 
 725     // --- Scrolling support -----------------------------------
 726 
 727     /**
 728      * Gets the visibility of the text field.  This can
 729      * be adjusted to change the location of the visible
 730      * area if the size of the field is greater than
 731      * the area that was allocated to the field.
 732      *
 733      * <p>
 734      * The fields look-and-feel implementation manages
 735      * the values of the minimum, maximum, and extent
 736      * properties on the <code>BoundedRangeModel</code>.
 737      *
 738      * @return the visibility
 739      * @see BoundedRangeModel
 740      */
 741     public BoundedRangeModel getHorizontalVisibility() {
 742         return visibility;
 743     }
 744 
 745     /**
 746      * Gets the scroll offset, in pixels.
 747      *
 748      * @return the offset >= 0
 749      */
 750     public int getScrollOffset() {
 751         return visibility.getValue();
 752     }
 753 
 754     /**
 755      * Sets the scroll offset, in pixels.
 756      *
 757      * @param scrollOffset the offset >= 0
 758      */
 759     public void setScrollOffset(int scrollOffset) {
 760         visibility.setValue(scrollOffset);
 761     }
 762 
 763     /**
 764      * Scrolls the field left or right.
 765      *
 766      * @param r the region to scroll
 767      */
 768     public void scrollRectToVisible(Rectangle r) {
 769         // convert to coordinate system of the bounded range
 770         Insets i = getInsets();
 771         int x0 = r.x + visibility.getValue() - i.left;
 772         int x1 = x0 + r.width;
 773         if (x0 < visibility.getValue()) {
 774             // Scroll to the left
 775             visibility.setValue(x0);
 776         } else if(x1 > visibility.getValue() + visibility.getExtent()) {
 777             // Scroll to the right
 778             visibility.setValue(x1 - visibility.getExtent());
 779         }
 780     }
 781 
 782     /**
 783      * Returns true if the receiver has an <code>ActionListener</code>
 784      * installed.
 785      */
 786     boolean hasActionListener() {
 787         // Guaranteed to return a non-null array
 788         Object[] listeners = listenerList.getListenerList();
 789         // Process the listeners last to first, notifying
 790         // those that are interested in this event
 791         for (int i = listeners.length-2; i>=0; i-=2) {
 792             if (listeners[i]==ActionListener.class) {
 793                 return true;
 794             }
 795         }
 796         return false;
 797     }
 798 
 799     // --- variables -------------------------------------------
 800 
 801     /**
 802      * Name of the action to send notification that the
 803      * contents of the field have been accepted.  Typically
 804      * this is bound to a carriage-return.
 805      */
 806     public static final String notifyAction = "notify-field-accept";
 807 
 808     private BoundedRangeModel visibility;
 809     private int horizontalAlignment = LEADING;
 810     private int columns;
 811     private int columnWidth;
 812     private String command;
 813 
 814     private static final Action[] defaultActions = {
 815         new NotifyAction()
 816     };
 817 
 818     /**
 819      * @see #getUIClassID
 820      * @see #readObject
 821      */
 822     private static final String uiClassID = "TextFieldUI";
 823 
 824     // --- Action implementations -----------------------------------
 825 
 826     // Note that JFormattedTextField.CommitAction extends this
 827     static class NotifyAction extends TextAction {
 828 
 829         NotifyAction() {
 830             super(notifyAction);
 831         }
 832 
 833         public void actionPerformed(ActionEvent e) {
 834             JTextComponent target = getFocusedComponent();
 835             if (target instanceof JTextField) {
 836                 JTextField field = (JTextField) target;
 837                 field.postActionEvent();
 838             }
 839         }
 840 
 841         public boolean isEnabled() {
 842             JTextComponent target = getFocusedComponent();
 843             if (target instanceof JTextField) {
 844                 return ((JTextField)target).hasActionListener();
 845             }
 846             return false;
 847         }
 848     }
 849 
 850     class ScrollRepainter implements ChangeListener, Serializable {
 851 
 852         public void stateChanged(ChangeEvent e) {
 853             repaint();
 854         }
 855 
 856     }
 857 
 858 
 859     /**
 860      * See <code>readObject</code> and <code>writeObject</code> in
 861      * <code>JComponent</code> for more
 862      * information about serialization in Swing.
 863      */
 864     private void writeObject(ObjectOutputStream s) throws IOException {
 865         s.defaultWriteObject();
 866         if (getUIClassID().equals(uiClassID)) {
 867             byte count = JComponent.getWriteObjCounter(this);
 868             JComponent.setWriteObjCounter(this, --count);
 869             if (count == 0 && ui != null) {
 870                 ui.installUI(this);
 871             }
 872         }
 873     }
 874 
 875 
 876     /**
 877      * Returns a string representation of this <code>JTextField</code>.
 878      * This method is intended to be used only for debugging purposes,
 879      * and the content and format of the returned string may vary between
 880      * implementations. The returned string may be empty but may not
 881      * be <code>null</code>.
 882      *
 883      * @return  a string representation of this <code>JTextField</code>
 884      */
 885     protected String paramString() {
 886         String horizontalAlignmentString;
 887         if (horizontalAlignment == LEFT) {
 888             horizontalAlignmentString = "LEFT";
 889         } else if (horizontalAlignment == CENTER) {
 890             horizontalAlignmentString = "CENTER";
 891         } else if (horizontalAlignment == RIGHT) {
 892             horizontalAlignmentString = "RIGHT";
 893         } else if (horizontalAlignment == LEADING) {
 894             horizontalAlignmentString = "LEADING";
 895         } else if (horizontalAlignment == TRAILING) {
 896             horizontalAlignmentString = "TRAILING";
 897         } else horizontalAlignmentString = "";
 898         String commandString = (command != null ?
 899                                 command : "");
 900 
 901         return super.paramString() +
 902         ",columns=" + columns +
 903         ",columnWidth=" + columnWidth +
 904         ",command=" + commandString +
 905         ",horizontalAlignment=" + horizontalAlignmentString;
 906     }
 907 
 908 
 909 /////////////////
 910 // Accessibility support
 911 ////////////////
 912 
 913 
 914     /**
 915      * Gets the <code>AccessibleContext</code> associated with this
 916      * <code>JTextField</code>. For <code>JTextFields</code>,
 917      * the <code>AccessibleContext</code> takes the form of an
 918      * <code>AccessibleJTextField</code>.
 919      * A new <code>AccessibleJTextField</code> instance is created
 920      * if necessary.
 921      *
 922      * @return an <code>AccessibleJTextField</code> that serves as the
 923      *         <code>AccessibleContext</code> of this <code>JTextField</code>
 924      */
 925     public AccessibleContext getAccessibleContext() {
 926         if (accessibleContext == null) {
 927             accessibleContext = new AccessibleJTextField();
 928         }
 929         return accessibleContext;
 930     }
 931 
 932     /**
 933      * This class implements accessibility support for the
 934      * <code>JTextField</code> class.  It provides an implementation of the
 935      * Java Accessibility API appropriate to text field user-interface
 936      * elements.
 937      * <p>
 938      * <strong>Warning:</strong>
 939      * Serialized objects of this class will not be compatible with
 940      * future Swing releases. The current serialization support is
 941      * appropriate for short term storage or RMI between applications running
 942      * the same version of Swing.  As of 1.4, support for long term storage
 943      * of all JavaBeans<sup><font size="-2">TM</font></sup>
 944      * has been added to the <code>java.beans</code> package.
 945      * Please see {@link java.beans.XMLEncoder}.
 946      */
 947     protected class AccessibleJTextField extends AccessibleJTextComponent {
 948 
 949         /**
 950          * Gets the state set of this object.
 951          *
 952          * @return an instance of AccessibleStateSet describing the states
 953          * of the object
 954          * @see AccessibleState
 955          */
 956         public AccessibleStateSet getAccessibleStateSet() {
 957             AccessibleStateSet states = super.getAccessibleStateSet();
 958             states.add(AccessibleState.SINGLE_LINE);
 959             return states;
 960         }
 961     }
 962 }