src/java.desktop/share/classes/java/awt/TextComponent.java
changeset 47216 71c04702a3d5
parent 35667 ed476aba94de
child 54871 c2e4aef5edf2
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 1995, 2014, 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 java.awt;
       
    26 
       
    27 import java.awt.peer.TextComponentPeer;
       
    28 import java.awt.event.*;
       
    29 import java.util.EventListener;
       
    30 import java.io.ObjectOutputStream;
       
    31 import java.io.ObjectInputStream;
       
    32 import java.io.IOException;
       
    33 import java.text.BreakIterator;
       
    34 import javax.swing.text.AttributeSet;
       
    35 import javax.accessibility.*;
       
    36 import java.awt.im.InputMethodRequests;
       
    37 import sun.awt.AWTPermissions;
       
    38 import sun.awt.InputMethodSupport;
       
    39 
       
    40 /**
       
    41  * The {@code TextComponent} class is the superclass of
       
    42  * any component that allows the editing of some text.
       
    43  * <p>
       
    44  * A text component embodies a string of text.  The
       
    45  * {@code TextComponent} class defines a set of methods
       
    46  * that determine whether or not this text is editable. If the
       
    47  * component is editable, it defines another set of methods
       
    48  * that supports a text insertion caret.
       
    49  * <p>
       
    50  * In addition, the class defines methods that are used
       
    51  * to maintain a current <em>selection</em> from the text.
       
    52  * The text selection, a substring of the component's text,
       
    53  * is the target of editing operations. It is also referred
       
    54  * to as the <em>selected text</em>.
       
    55  *
       
    56  * @author      Sami Shaio
       
    57  * @author      Arthur van Hoff
       
    58  * @since       1.0
       
    59  */
       
    60 public class TextComponent extends Component implements Accessible {
       
    61 
       
    62     /**
       
    63      * The value of the text.
       
    64      * A {@code null} value is the same as "".
       
    65      *
       
    66      * @serial
       
    67      * @see #setText(String)
       
    68      * @see #getText()
       
    69      */
       
    70     String text;
       
    71 
       
    72     /**
       
    73      * A boolean indicating whether or not this
       
    74      * {@code TextComponent} is editable.
       
    75      * It will be {@code true} if the text component
       
    76      * is editable and {@code false} if not.
       
    77      *
       
    78      * @serial
       
    79      * @see #isEditable()
       
    80      */
       
    81     boolean editable = true;
       
    82 
       
    83     /**
       
    84      * The selection refers to the selected text, and the
       
    85      * {@code selectionStart} is the start position
       
    86      * of the selected text.
       
    87      *
       
    88      * @serial
       
    89      * @see #getSelectionStart()
       
    90      * @see #setSelectionStart(int)
       
    91      */
       
    92     int selectionStart;
       
    93 
       
    94     /**
       
    95      * The selection refers to the selected text, and the
       
    96      * {@code selectionEnd}
       
    97      * is the end position of the selected text.
       
    98      *
       
    99      * @serial
       
   100      * @see #getSelectionEnd()
       
   101      * @see #setSelectionEnd(int)
       
   102      */
       
   103     int selectionEnd;
       
   104 
       
   105     // A flag used to tell whether the background has been set by
       
   106     // developer code (as opposed to AWT code).  Used to determine
       
   107     // the background color of non-editable TextComponents.
       
   108     boolean backgroundSetByClientCode = false;
       
   109 
       
   110     /**
       
   111      * A list of listeners that will receive events from this object.
       
   112      */
       
   113     protected transient TextListener textListener;
       
   114 
       
   115     /*
       
   116      * JDK 1.1 serialVersionUID
       
   117      */
       
   118     private static final long serialVersionUID = -2214773872412987419L;
       
   119 
       
   120     /**
       
   121      * Constructs a new text component initialized with the
       
   122      * specified text. Sets the value of the cursor to
       
   123      * {@code Cursor.TEXT_CURSOR}.
       
   124      * @param      text       the text to be displayed; if
       
   125      *             {@code text} is {@code null}, the empty
       
   126      *             string {@code ""} will be displayed
       
   127      * @exception  HeadlessException if
       
   128      *             {@code GraphicsEnvironment.isHeadless}
       
   129      *             returns true
       
   130      * @see        java.awt.GraphicsEnvironment#isHeadless
       
   131      * @see        java.awt.Cursor
       
   132      */
       
   133     TextComponent(String text) throws HeadlessException {
       
   134         GraphicsEnvironment.checkHeadless();
       
   135         this.text = (text != null) ? text : "";
       
   136         setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
       
   137     }
       
   138 
       
   139     private void enableInputMethodsIfNecessary() {
       
   140         if (checkForEnableIM) {
       
   141             checkForEnableIM = false;
       
   142             try {
       
   143                 Toolkit toolkit = Toolkit.getDefaultToolkit();
       
   144                 boolean shouldEnable = false;
       
   145                 if (toolkit instanceof InputMethodSupport) {
       
   146                     shouldEnable = ((InputMethodSupport)toolkit)
       
   147                       .enableInputMethodsForTextComponent();
       
   148                 }
       
   149                 enableInputMethods(shouldEnable);
       
   150             } catch (Exception e) {
       
   151                 // if something bad happens, just don't enable input methods
       
   152             }
       
   153         }
       
   154     }
       
   155 
       
   156     /**
       
   157      * Enables or disables input method support for this text component. If input
       
   158      * method support is enabled and the text component also processes key events,
       
   159      * incoming events are offered to the current input method and will only be
       
   160      * processed by the component or dispatched to its listeners if the input method
       
   161      * does not consume them. Whether and how input method support for this text
       
   162      * component is enabled or disabled by default is implementation dependent.
       
   163      *
       
   164      * @param enable true to enable, false to disable
       
   165      * @see #processKeyEvent
       
   166      * @since 1.2
       
   167      */
       
   168     public void enableInputMethods(boolean enable) {
       
   169         checkForEnableIM = false;
       
   170         super.enableInputMethods(enable);
       
   171     }
       
   172 
       
   173     boolean areInputMethodsEnabled() {
       
   174         // moved from the constructor above to here and addNotify below,
       
   175         // this call will initialize the toolkit if not already initialized.
       
   176         if (checkForEnableIM) {
       
   177             enableInputMethodsIfNecessary();
       
   178         }
       
   179 
       
   180         // TextComponent handles key events without touching the eventMask or
       
   181         // having a key listener, so just check whether the flag is set
       
   182         return (eventMask & AWTEvent.INPUT_METHODS_ENABLED_MASK) != 0;
       
   183     }
       
   184 
       
   185     public InputMethodRequests getInputMethodRequests() {
       
   186         TextComponentPeer peer = (TextComponentPeer)this.peer;
       
   187         if (peer != null) return peer.getInputMethodRequests();
       
   188         else return null;
       
   189     }
       
   190 
       
   191 
       
   192 
       
   193     /**
       
   194      * Makes this Component displayable by connecting it to a
       
   195      * native screen resource.
       
   196      * This method is called internally by the toolkit and should
       
   197      * not be called directly by programs.
       
   198      * @see       java.awt.TextComponent#removeNotify
       
   199      */
       
   200     public void addNotify() {
       
   201         super.addNotify();
       
   202         enableInputMethodsIfNecessary();
       
   203     }
       
   204 
       
   205     /**
       
   206      * Removes the {@code TextComponent}'s peer.
       
   207      * The peer allows us to modify the appearance of the
       
   208      * {@code TextComponent} without changing its
       
   209      * functionality.
       
   210      */
       
   211     public void removeNotify() {
       
   212         synchronized (getTreeLock()) {
       
   213             TextComponentPeer peer = (TextComponentPeer)this.peer;
       
   214             if (peer != null) {
       
   215                 text = peer.getText();
       
   216                 selectionStart = peer.getSelectionStart();
       
   217                 selectionEnd = peer.getSelectionEnd();
       
   218             }
       
   219             super.removeNotify();
       
   220         }
       
   221     }
       
   222 
       
   223     /**
       
   224      * Sets the text that is presented by this
       
   225      * text component to be the specified text.
       
   226      * @param       t   the new text;
       
   227      *                  if this parameter is {@code null} then
       
   228      *                  the text is set to the empty string ""
       
   229      * @see         java.awt.TextComponent#getText
       
   230      */
       
   231     public synchronized void setText(String t) {
       
   232         if (t == null) {
       
   233             t = "";
       
   234         }
       
   235         TextComponentPeer peer = (TextComponentPeer)this.peer;
       
   236         if (peer != null) {
       
   237             text = peer.getText();
       
   238             // Please note that we do not want to post an event
       
   239             // if TextArea.setText() or TextField.setText() replaces text
       
   240             // by same text, that is, if component's text remains unchanged.
       
   241             if (!t.equals(text)) {
       
   242                 text = t;
       
   243                 peer.setText(text);
       
   244             }
       
   245         } else {
       
   246             text = t;
       
   247         }
       
   248     }
       
   249 
       
   250     /**
       
   251      * Returns the text that is presented by this text component.
       
   252      * By default, this is an empty string.
       
   253      *
       
   254      * @return the value of this {@code TextComponent}
       
   255      * @see     java.awt.TextComponent#setText
       
   256      */
       
   257     public synchronized String getText() {
       
   258         TextComponentPeer peer = (TextComponentPeer)this.peer;
       
   259         if (peer != null) {
       
   260             text = peer.getText();
       
   261         }
       
   262         return text;
       
   263     }
       
   264 
       
   265     /**
       
   266      * Returns the selected text from the text that is
       
   267      * presented by this text component.
       
   268      * @return      the selected text of this text component
       
   269      * @see         java.awt.TextComponent#select
       
   270      */
       
   271     public synchronized String getSelectedText() {
       
   272         return getText().substring(getSelectionStart(), getSelectionEnd());
       
   273     }
       
   274 
       
   275     /**
       
   276      * Indicates whether or not this text component is editable.
       
   277      * @return     {@code true} if this text component is
       
   278      *                  editable; {@code false} otherwise.
       
   279      * @see        java.awt.TextComponent#setEditable
       
   280      * @since      1.0
       
   281      */
       
   282     public boolean isEditable() {
       
   283         return editable;
       
   284     }
       
   285 
       
   286     /**
       
   287      * Sets the flag that determines whether or not this
       
   288      * text component is editable.
       
   289      * <p>
       
   290      * If the flag is set to {@code true}, this text component
       
   291      * becomes user editable. If the flag is set to {@code false},
       
   292      * the user cannot change the text of this text component.
       
   293      * By default, non-editable text components have a background color
       
   294      * of SystemColor.control.  This default can be overridden by
       
   295      * calling setBackground.
       
   296      *
       
   297      * @param     b   a flag indicating whether this text component
       
   298      *                      is user editable.
       
   299      * @see       java.awt.TextComponent#isEditable
       
   300      * @since     1.0
       
   301      */
       
   302     public synchronized void setEditable(boolean b) {
       
   303         if (editable == b) {
       
   304             return;
       
   305         }
       
   306 
       
   307         editable = b;
       
   308         TextComponentPeer peer = (TextComponentPeer)this.peer;
       
   309         if (peer != null) {
       
   310             peer.setEditable(b);
       
   311         }
       
   312     }
       
   313 
       
   314     /**
       
   315      * Gets the background color of this text component.
       
   316      *
       
   317      * By default, non-editable text components have a background color
       
   318      * of SystemColor.control.  This default can be overridden by
       
   319      * calling setBackground.
       
   320      *
       
   321      * @return This text component's background color.
       
   322      *         If this text component does not have a background color,
       
   323      *         the background color of its parent is returned.
       
   324      * @see #setBackground(Color)
       
   325      * @since 1.0
       
   326      */
       
   327     public Color getBackground() {
       
   328         if (!editable && !backgroundSetByClientCode) {
       
   329             return SystemColor.control;
       
   330         }
       
   331 
       
   332         return super.getBackground();
       
   333     }
       
   334 
       
   335     /**
       
   336      * Sets the background color of this text component.
       
   337      *
       
   338      * @param c The color to become this text component's color.
       
   339      *        If this parameter is null then this text component
       
   340      *        will inherit the background color of its parent.
       
   341      * @see #getBackground()
       
   342      * @since 1.0
       
   343      */
       
   344     public void setBackground(Color c) {
       
   345         backgroundSetByClientCode = true;
       
   346         super.setBackground(c);
       
   347     }
       
   348 
       
   349     /**
       
   350      * Gets the start position of the selected text in
       
   351      * this text component.
       
   352      * @return      the start position of the selected text
       
   353      * @see         java.awt.TextComponent#setSelectionStart
       
   354      * @see         java.awt.TextComponent#getSelectionEnd
       
   355      */
       
   356     public synchronized int getSelectionStart() {
       
   357         TextComponentPeer peer = (TextComponentPeer)this.peer;
       
   358         if (peer != null) {
       
   359             selectionStart = peer.getSelectionStart();
       
   360         }
       
   361         return selectionStart;
       
   362     }
       
   363 
       
   364     /**
       
   365      * Sets the selection start for this text component to
       
   366      * the specified position. The new start point is constrained
       
   367      * to be at or before the current selection end. It also
       
   368      * cannot be set to less than zero, the beginning of the
       
   369      * component's text.
       
   370      * If the caller supplies a value for {@code selectionStart}
       
   371      * that is out of bounds, the method enforces these constraints
       
   372      * silently, and without failure.
       
   373      * @param       selectionStart   the start position of the
       
   374      *                        selected text
       
   375      * @see         java.awt.TextComponent#getSelectionStart
       
   376      * @see         java.awt.TextComponent#setSelectionEnd
       
   377      * @since       1.1
       
   378      */
       
   379     public synchronized void setSelectionStart(int selectionStart) {
       
   380         /* Route through select method to enforce consistent policy
       
   381          * between selectionStart and selectionEnd.
       
   382          */
       
   383         select(selectionStart, getSelectionEnd());
       
   384     }
       
   385 
       
   386     /**
       
   387      * Gets the end position of the selected text in
       
   388      * this text component.
       
   389      * @return      the end position of the selected text
       
   390      * @see         java.awt.TextComponent#setSelectionEnd
       
   391      * @see         java.awt.TextComponent#getSelectionStart
       
   392      */
       
   393     public synchronized int getSelectionEnd() {
       
   394         TextComponentPeer peer = (TextComponentPeer)this.peer;
       
   395         if (peer != null) {
       
   396             selectionEnd = peer.getSelectionEnd();
       
   397         }
       
   398         return selectionEnd;
       
   399     }
       
   400 
       
   401     /**
       
   402      * Sets the selection end for this text component to
       
   403      * the specified position. The new end point is constrained
       
   404      * to be at or after the current selection start. It also
       
   405      * cannot be set beyond the end of the component's text.
       
   406      * If the caller supplies a value for {@code selectionEnd}
       
   407      * that is out of bounds, the method enforces these constraints
       
   408      * silently, and without failure.
       
   409      * @param       selectionEnd   the end position of the
       
   410      *                        selected text
       
   411      * @see         java.awt.TextComponent#getSelectionEnd
       
   412      * @see         java.awt.TextComponent#setSelectionStart
       
   413      * @since       1.1
       
   414      */
       
   415     public synchronized void setSelectionEnd(int selectionEnd) {
       
   416         /* Route through select method to enforce consistent policy
       
   417          * between selectionStart and selectionEnd.
       
   418          */
       
   419         select(getSelectionStart(), selectionEnd);
       
   420     }
       
   421 
       
   422     /**
       
   423      * Selects the text between the specified start and end positions.
       
   424      * <p>
       
   425      * This method sets the start and end positions of the
       
   426      * selected text, enforcing the restriction that the start position
       
   427      * must be greater than or equal to zero.  The end position must be
       
   428      * greater than or equal to the start position, and less than or
       
   429      * equal to the length of the text component's text.  The
       
   430      * character positions are indexed starting with zero.
       
   431      * The length of the selection is
       
   432      * {@code endPosition} - {@code startPosition}, so the
       
   433      * character at {@code endPosition} is not selected.
       
   434      * If the start and end positions of the selected text are equal,
       
   435      * all text is deselected.
       
   436      * <p>
       
   437      * If the caller supplies values that are inconsistent or out of
       
   438      * bounds, the method enforces these constraints silently, and
       
   439      * without failure. Specifically, if the start position or end
       
   440      * position is greater than the length of the text, it is reset to
       
   441      * equal the text length. If the start position is less than zero,
       
   442      * it is reset to zero, and if the end position is less than the
       
   443      * start position, it is reset to the start position.
       
   444      *
       
   445      * @param        selectionStart the zero-based index of the first
       
   446      *               character ({@code char} value) to be selected
       
   447      * @param        selectionEnd the zero-based end position of the
       
   448      *               text to be selected; the character ({@code char} value) at
       
   449      *               {@code selectionEnd} is not selected
       
   450      * @see          java.awt.TextComponent#setSelectionStart
       
   451      * @see          java.awt.TextComponent#setSelectionEnd
       
   452      * @see          java.awt.TextComponent#selectAll
       
   453      */
       
   454     public synchronized void select(int selectionStart, int selectionEnd) {
       
   455         String text = getText();
       
   456         if (selectionStart < 0) {
       
   457             selectionStart = 0;
       
   458         }
       
   459         if (selectionStart > text.length()) {
       
   460             selectionStart = text.length();
       
   461         }
       
   462         if (selectionEnd > text.length()) {
       
   463             selectionEnd = text.length();
       
   464         }
       
   465         if (selectionEnd < selectionStart) {
       
   466             selectionEnd = selectionStart;
       
   467         }
       
   468 
       
   469         this.selectionStart = selectionStart;
       
   470         this.selectionEnd = selectionEnd;
       
   471 
       
   472         TextComponentPeer peer = (TextComponentPeer)this.peer;
       
   473         if (peer != null) {
       
   474             peer.select(selectionStart, selectionEnd);
       
   475         }
       
   476     }
       
   477 
       
   478     /**
       
   479      * Selects all the text in this text component.
       
   480      * @see        java.awt.TextComponent#select
       
   481      */
       
   482     public synchronized void selectAll() {
       
   483         this.selectionStart = 0;
       
   484         this.selectionEnd = getText().length();
       
   485 
       
   486         TextComponentPeer peer = (TextComponentPeer)this.peer;
       
   487         if (peer != null) {
       
   488             peer.select(selectionStart, selectionEnd);
       
   489         }
       
   490     }
       
   491 
       
   492     /**
       
   493      * Sets the position of the text insertion caret.
       
   494      * The caret position is constrained to be between 0
       
   495      * and the last character of the text, inclusive.
       
   496      * If the passed-in value is greater than this range,
       
   497      * the value is set to the last character (or 0 if
       
   498      * the {@code TextComponent} contains no text)
       
   499      * and no error is returned.  If the passed-in value is
       
   500      * less than 0, an {@code IllegalArgumentException}
       
   501      * is thrown.
       
   502      *
       
   503      * @param        position the position of the text insertion caret
       
   504      * @exception    IllegalArgumentException if {@code position}
       
   505      *               is less than zero
       
   506      * @since        1.1
       
   507      */
       
   508     public synchronized void setCaretPosition(int position) {
       
   509         if (position < 0) {
       
   510             throw new IllegalArgumentException("position less than zero.");
       
   511         }
       
   512 
       
   513         int maxposition = getText().length();
       
   514         if (position > maxposition) {
       
   515             position = maxposition;
       
   516         }
       
   517 
       
   518         TextComponentPeer peer = (TextComponentPeer)this.peer;
       
   519         if (peer != null) {
       
   520             peer.setCaretPosition(position);
       
   521         } else {
       
   522             select(position, position);
       
   523         }
       
   524     }
       
   525 
       
   526     /**
       
   527      * Returns the position of the text insertion caret.
       
   528      * The caret position is constrained to be between 0
       
   529      * and the last character of the text, inclusive.
       
   530      * If the text or caret have not been set, the default
       
   531      * caret position is 0.
       
   532      *
       
   533      * @return       the position of the text insertion caret
       
   534      * @see #setCaretPosition(int)
       
   535      * @since        1.1
       
   536      */
       
   537     public synchronized int getCaretPosition() {
       
   538         TextComponentPeer peer = (TextComponentPeer)this.peer;
       
   539         int position = 0;
       
   540 
       
   541         if (peer != null) {
       
   542             position = peer.getCaretPosition();
       
   543         } else {
       
   544             position = selectionStart;
       
   545         }
       
   546         int maxposition = getText().length();
       
   547         if (position > maxposition) {
       
   548             position = maxposition;
       
   549         }
       
   550         return position;
       
   551     }
       
   552 
       
   553     /**
       
   554      * Adds the specified text event listener to receive text events
       
   555      * from this text component.
       
   556      * If {@code l} is {@code null}, no exception is
       
   557      * thrown and no action is performed.
       
   558      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
       
   559      * >AWT Threading Issues</a> for details on AWT's threading model.
       
   560      *
       
   561      * @param l the text event listener
       
   562      * @see             #removeTextListener
       
   563      * @see             #getTextListeners
       
   564      * @see             java.awt.event.TextListener
       
   565      */
       
   566     public synchronized void addTextListener(TextListener l) {
       
   567         if (l == null) {
       
   568             return;
       
   569         }
       
   570         textListener = AWTEventMulticaster.add(textListener, l);
       
   571         newEventsOnly = true;
       
   572     }
       
   573 
       
   574     /**
       
   575      * Removes the specified text event listener so that it no longer
       
   576      * receives text events from this text component
       
   577      * If {@code l} is {@code null}, no exception is
       
   578      * thrown and no action is performed.
       
   579      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
       
   580      * >AWT Threading Issues</a> for details on AWT's threading model.
       
   581      *
       
   582      * @param           l     the text listener
       
   583      * @see             #addTextListener
       
   584      * @see             #getTextListeners
       
   585      * @see             java.awt.event.TextListener
       
   586      * @since           1.1
       
   587      */
       
   588     public synchronized void removeTextListener(TextListener l) {
       
   589         if (l == null) {
       
   590             return;
       
   591         }
       
   592         textListener = AWTEventMulticaster.remove(textListener, l);
       
   593     }
       
   594 
       
   595     /**
       
   596      * Returns an array of all the text listeners
       
   597      * registered on this text component.
       
   598      *
       
   599      * @return all of this text component's {@code TextListener}s
       
   600      *         or an empty array if no text
       
   601      *         listeners are currently registered
       
   602      *
       
   603      *
       
   604      * @see #addTextListener
       
   605      * @see #removeTextListener
       
   606      * @since 1.4
       
   607      */
       
   608     public synchronized TextListener[] getTextListeners() {
       
   609         return getListeners(TextListener.class);
       
   610     }
       
   611 
       
   612     /**
       
   613      * Returns an array of all the objects currently registered
       
   614      * as <code><em>Foo</em>Listener</code>s
       
   615      * upon this {@code TextComponent}.
       
   616      * <code><em>Foo</em>Listener</code>s are registered using the
       
   617      * <code>add<em>Foo</em>Listener</code> method.
       
   618      *
       
   619      * <p>
       
   620      * You can specify the {@code listenerType} argument
       
   621      * with a class literal, such as
       
   622      * <code><em>Foo</em>Listener.class</code>.
       
   623      * For example, you can query a
       
   624      * {@code TextComponent t}
       
   625      * for its text listeners with the following code:
       
   626      *
       
   627      * <pre>TextListener[] tls = (TextListener[])(t.getListeners(TextListener.class));</pre>
       
   628      *
       
   629      * If no such listeners exist, this method returns an empty array.
       
   630      *
       
   631      * @param listenerType the type of listeners requested; this parameter
       
   632      *          should specify an interface that descends from
       
   633      *          {@code java.util.EventListener}
       
   634      * @return an array of all objects registered as
       
   635      *          <code><em>Foo</em>Listener</code>s on this text component,
       
   636      *          or an empty array if no such
       
   637      *          listeners have been added
       
   638      * @exception ClassCastException if {@code listenerType}
       
   639      *          doesn't specify a class or interface that implements
       
   640      *          {@code java.util.EventListener}
       
   641      *
       
   642      * @see #getTextListeners
       
   643      * @since 1.3
       
   644      */
       
   645     public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
       
   646         EventListener l = null;
       
   647         if  (listenerType == TextListener.class) {
       
   648             l = textListener;
       
   649         } else {
       
   650             return super.getListeners(listenerType);
       
   651         }
       
   652         return AWTEventMulticaster.getListeners(l, listenerType);
       
   653     }
       
   654 
       
   655     // REMIND: remove when filtering is done at lower level
       
   656     boolean eventEnabled(AWTEvent e) {
       
   657         if (e.id == TextEvent.TEXT_VALUE_CHANGED) {
       
   658             if ((eventMask & AWTEvent.TEXT_EVENT_MASK) != 0 ||
       
   659                 textListener != null) {
       
   660                 return true;
       
   661             }
       
   662             return false;
       
   663         }
       
   664         return super.eventEnabled(e);
       
   665     }
       
   666 
       
   667     /**
       
   668      * Processes events on this text component. If the event is a
       
   669      * {@code TextEvent}, it invokes the {@code processTextEvent}
       
   670      * method else it invokes its superclass's {@code processEvent}.
       
   671      * <p>Note that if the event parameter is {@code null}
       
   672      * the behavior is unspecified and may result in an
       
   673      * exception.
       
   674      *
       
   675      * @param e the event
       
   676      */
       
   677     protected void processEvent(AWTEvent e) {
       
   678         if (e instanceof TextEvent) {
       
   679             processTextEvent((TextEvent)e);
       
   680             return;
       
   681         }
       
   682         super.processEvent(e);
       
   683     }
       
   684 
       
   685     /**
       
   686      * Processes text events occurring on this text component by
       
   687      * dispatching them to any registered {@code TextListener} objects.
       
   688      * <p>
       
   689      * NOTE: This method will not be called unless text events
       
   690      * are enabled for this component. This happens when one of the
       
   691      * following occurs:
       
   692      * <ul>
       
   693      * <li>A {@code TextListener} object is registered
       
   694      * via {@code addTextListener}
       
   695      * <li>Text events are enabled via {@code enableEvents}
       
   696      * </ul>
       
   697      * <p>Note that if the event parameter is {@code null}
       
   698      * the behavior is unspecified and may result in an
       
   699      * exception.
       
   700      *
       
   701      * @param e the text event
       
   702      * @see Component#enableEvents
       
   703      */
       
   704     protected void processTextEvent(TextEvent e) {
       
   705         TextListener listener = textListener;
       
   706         if (listener != null) {
       
   707             int id = e.getID();
       
   708             switch (id) {
       
   709             case TextEvent.TEXT_VALUE_CHANGED:
       
   710                 listener.textValueChanged(e);
       
   711                 break;
       
   712             }
       
   713         }
       
   714     }
       
   715 
       
   716     /**
       
   717      * Returns a string representing the state of this
       
   718      * {@code TextComponent}. This
       
   719      * method is intended to be used only for debugging purposes, and the
       
   720      * content and format of the returned string may vary between
       
   721      * implementations. The returned string may be empty but may not be
       
   722      * {@code null}.
       
   723      *
       
   724      * @return      the parameter string of this text component
       
   725      */
       
   726     protected String paramString() {
       
   727         String str = super.paramString() + ",text=" + getText();
       
   728         if (editable) {
       
   729             str += ",editable";
       
   730         }
       
   731         return str + ",selection=" + getSelectionStart() + "-" + getSelectionEnd();
       
   732     }
       
   733 
       
   734     /**
       
   735      * Assigns a valid value to the canAccessClipboard instance variable.
       
   736      */
       
   737     private boolean canAccessClipboard() {
       
   738         SecurityManager sm = System.getSecurityManager();
       
   739         if (sm == null) return true;
       
   740         try {
       
   741             sm.checkPermission(AWTPermissions.ACCESS_CLIPBOARD_PERMISSION);
       
   742             return true;
       
   743         } catch (SecurityException e) {}
       
   744         return false;
       
   745     }
       
   746 
       
   747     /*
       
   748      * Serialization support.
       
   749      */
       
   750     /**
       
   751      * The textComponent SerializedDataVersion.
       
   752      *
       
   753      * @serial
       
   754      */
       
   755     private int textComponentSerializedDataVersion = 1;
       
   756 
       
   757     /**
       
   758      * Writes default serializable fields to stream.  Writes
       
   759      * a list of serializable TextListener(s) as optional data.
       
   760      * The non-serializable TextListener(s) are detected and
       
   761      * no attempt is made to serialize them.
       
   762      *
       
   763      * @serialData Null terminated sequence of zero or more pairs.
       
   764      *             A pair consists of a String and Object.
       
   765      *             The String indicates the type of object and
       
   766      *             is one of the following :
       
   767      *             textListenerK indicating and TextListener object.
       
   768      *
       
   769      * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
       
   770      * @see java.awt.Component#textListenerK
       
   771      */
       
   772     private void writeObject(java.io.ObjectOutputStream s)
       
   773       throws IOException
       
   774     {
       
   775         // Serialization support.  Since the value of the fields
       
   776         // selectionStart, selectionEnd, and text aren't necessarily
       
   777         // up to date, we sync them up with the peer before serializing.
       
   778         TextComponentPeer peer = (TextComponentPeer)this.peer;
       
   779         if (peer != null) {
       
   780             text = peer.getText();
       
   781             selectionStart = peer.getSelectionStart();
       
   782             selectionEnd = peer.getSelectionEnd();
       
   783         }
       
   784 
       
   785         s.defaultWriteObject();
       
   786 
       
   787         AWTEventMulticaster.save(s, textListenerK, textListener);
       
   788         s.writeObject(null);
       
   789     }
       
   790 
       
   791     /**
       
   792      * Read the ObjectInputStream, and if it isn't null,
       
   793      * add a listener to receive text events fired by the
       
   794      * TextComponent.  Unrecognized keys or values will be
       
   795      * ignored.
       
   796      *
       
   797      * @exception HeadlessException if
       
   798      * {@code GraphicsEnvironment.isHeadless()} returns
       
   799      * {@code true}
       
   800      * @see #removeTextListener
       
   801      * @see #addTextListener
       
   802      * @see java.awt.GraphicsEnvironment#isHeadless
       
   803      */
       
   804     private void readObject(ObjectInputStream s)
       
   805         throws ClassNotFoundException, IOException, HeadlessException
       
   806     {
       
   807         GraphicsEnvironment.checkHeadless();
       
   808         s.defaultReadObject();
       
   809 
       
   810         // Make sure the state we just read in for text,
       
   811         // selectionStart and selectionEnd has legal values
       
   812         this.text = (text != null) ? text : "";
       
   813         select(selectionStart, selectionEnd);
       
   814 
       
   815         Object keyOrNull;
       
   816         while(null != (keyOrNull = s.readObject())) {
       
   817             String key = ((String)keyOrNull).intern();
       
   818 
       
   819             if (textListenerK == key) {
       
   820                 addTextListener((TextListener)(s.readObject()));
       
   821             } else {
       
   822                 // skip value for unrecognized key
       
   823                 s.readObject();
       
   824             }
       
   825         }
       
   826         enableInputMethodsIfNecessary();
       
   827     }
       
   828 
       
   829 
       
   830 /////////////////
       
   831 // Accessibility support
       
   832 ////////////////
       
   833 
       
   834     /**
       
   835      * Gets the AccessibleContext associated with this TextComponent.
       
   836      * For text components, the AccessibleContext takes the form of an
       
   837      * AccessibleAWTTextComponent.
       
   838      * A new AccessibleAWTTextComponent instance is created if necessary.
       
   839      *
       
   840      * @return an AccessibleAWTTextComponent that serves as the
       
   841      *         AccessibleContext of this TextComponent
       
   842      * @since 1.3
       
   843      */
       
   844     public AccessibleContext getAccessibleContext() {
       
   845         if (accessibleContext == null) {
       
   846             accessibleContext = new AccessibleAWTTextComponent();
       
   847         }
       
   848         return accessibleContext;
       
   849     }
       
   850 
       
   851     /**
       
   852      * This class implements accessibility support for the
       
   853      * {@code TextComponent} class.  It provides an implementation of the
       
   854      * Java Accessibility API appropriate to text component user-interface
       
   855      * elements.
       
   856      * @since 1.3
       
   857      */
       
   858     protected class AccessibleAWTTextComponent extends AccessibleAWTComponent
       
   859         implements AccessibleText, TextListener
       
   860     {
       
   861         /*
       
   862          * JDK 1.3 serialVersionUID
       
   863          */
       
   864         private static final long serialVersionUID = 3631432373506317811L;
       
   865 
       
   866         /**
       
   867          * Constructs an AccessibleAWTTextComponent.  Adds a listener to track
       
   868          * caret change.
       
   869          */
       
   870         public AccessibleAWTTextComponent() {
       
   871             TextComponent.this.addTextListener(this);
       
   872         }
       
   873 
       
   874         /**
       
   875          * TextListener notification of a text value change.
       
   876          */
       
   877         public void textValueChanged(TextEvent textEvent)  {
       
   878             Integer cpos = Integer.valueOf(TextComponent.this.getCaretPosition());
       
   879             firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, cpos);
       
   880         }
       
   881 
       
   882         /**
       
   883          * Gets the state set of the TextComponent.
       
   884          * The AccessibleStateSet of an object is composed of a set of
       
   885          * unique AccessibleStates.  A change in the AccessibleStateSet
       
   886          * of an object will cause a PropertyChangeEvent to be fired
       
   887          * for the AccessibleContext.ACCESSIBLE_STATE_PROPERTY property.
       
   888          *
       
   889          * @return an instance of AccessibleStateSet containing the
       
   890          * current state set of the object
       
   891          * @see AccessibleStateSet
       
   892          * @see AccessibleState
       
   893          * @see #addPropertyChangeListener
       
   894          */
       
   895         public AccessibleStateSet getAccessibleStateSet() {
       
   896             AccessibleStateSet states = super.getAccessibleStateSet();
       
   897             if (TextComponent.this.isEditable()) {
       
   898                 states.add(AccessibleState.EDITABLE);
       
   899             }
       
   900             return states;
       
   901         }
       
   902 
       
   903 
       
   904         /**
       
   905          * Gets the role of this object.
       
   906          *
       
   907          * @return an instance of AccessibleRole describing the role of the
       
   908          * object (AccessibleRole.TEXT)
       
   909          * @see AccessibleRole
       
   910          */
       
   911         public AccessibleRole getAccessibleRole() {
       
   912             return AccessibleRole.TEXT;
       
   913         }
       
   914 
       
   915         /**
       
   916          * Get the AccessibleText associated with this object.  In the
       
   917          * implementation of the Java Accessibility API for this class,
       
   918          * return this object, which is responsible for implementing the
       
   919          * AccessibleText interface on behalf of itself.
       
   920          *
       
   921          * @return this object
       
   922          */
       
   923         public AccessibleText getAccessibleText() {
       
   924             return this;
       
   925         }
       
   926 
       
   927 
       
   928         // --- interface AccessibleText methods ------------------------
       
   929 
       
   930         /**
       
   931          * Many of these methods are just convenience methods; they
       
   932          * just call the equivalent on the parent
       
   933          */
       
   934 
       
   935         /**
       
   936          * Given a point in local coordinates, return the zero-based index
       
   937          * of the character under that Point.  If the point is invalid,
       
   938          * this method returns -1.
       
   939          *
       
   940          * @param p the Point in local coordinates
       
   941          * @return the zero-based index of the character under Point p.
       
   942          */
       
   943         public int getIndexAtPoint(Point p) {
       
   944             return -1;
       
   945         }
       
   946 
       
   947         /**
       
   948          * Determines the bounding box of the character at the given
       
   949          * index into the string.  The bounds are returned in local
       
   950          * coordinates.  If the index is invalid a null rectangle
       
   951          * is returned.
       
   952          *
       
   953          * @param i the index into the String &gt;= 0
       
   954          * @return the screen coordinates of the character's bounding box
       
   955          */
       
   956         public Rectangle getCharacterBounds(int i) {
       
   957             return null;
       
   958         }
       
   959 
       
   960         /**
       
   961          * Returns the number of characters (valid indices)
       
   962          *
       
   963          * @return the number of characters &gt;= 0
       
   964          */
       
   965         public int getCharCount() {
       
   966             return TextComponent.this.getText().length();
       
   967         }
       
   968 
       
   969         /**
       
   970          * Returns the zero-based offset of the caret.
       
   971          *
       
   972          * Note: The character to the right of the caret will have the
       
   973          * same index value as the offset (the caret is between
       
   974          * two characters).
       
   975          *
       
   976          * @return the zero-based offset of the caret.
       
   977          */
       
   978         public int getCaretPosition() {
       
   979             return TextComponent.this.getCaretPosition();
       
   980         }
       
   981 
       
   982         /**
       
   983          * Returns the AttributeSet for a given character (at a given index).
       
   984          *
       
   985          * @param i the zero-based index into the text
       
   986          * @return the AttributeSet of the character
       
   987          */
       
   988         public AttributeSet getCharacterAttribute(int i) {
       
   989             return null; // No attributes in TextComponent
       
   990         }
       
   991 
       
   992         /**
       
   993          * Returns the start offset within the selected text.
       
   994          * If there is no selection, but there is
       
   995          * a caret, the start and end offsets will be the same.
       
   996          * Return 0 if the text is empty, or the caret position
       
   997          * if no selection.
       
   998          *
       
   999          * @return the index into the text of the start of the selection &gt;= 0
       
  1000          */
       
  1001         public int getSelectionStart() {
       
  1002             return TextComponent.this.getSelectionStart();
       
  1003         }
       
  1004 
       
  1005         /**
       
  1006          * Returns the end offset within the selected text.
       
  1007          * If there is no selection, but there is
       
  1008          * a caret, the start and end offsets will be the same.
       
  1009          * Return 0 if the text is empty, or the caret position
       
  1010          * if no selection.
       
  1011          *
       
  1012          * @return the index into the text of the end of the selection &gt;= 0
       
  1013          */
       
  1014         public int getSelectionEnd() {
       
  1015             return TextComponent.this.getSelectionEnd();
       
  1016         }
       
  1017 
       
  1018         /**
       
  1019          * Returns the portion of the text that is selected.
       
  1020          *
       
  1021          * @return the text, null if no selection
       
  1022          */
       
  1023         public String getSelectedText() {
       
  1024             String selText = TextComponent.this.getSelectedText();
       
  1025             // Fix for 4256662
       
  1026             if (selText == null || selText.equals("")) {
       
  1027                 return null;
       
  1028             }
       
  1029             return selText;
       
  1030         }
       
  1031 
       
  1032         /**
       
  1033          * Returns the String at a given index.
       
  1034          *
       
  1035          * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
       
  1036          * or AccessibleText.SENTENCE to retrieve
       
  1037          * @param index an index within the text &gt;= 0
       
  1038          * @return the letter, word, or sentence,
       
  1039          *   null for an invalid index or part
       
  1040          */
       
  1041         public String getAtIndex(int part, int index) {
       
  1042             if (index < 0 || index >= TextComponent.this.getText().length()) {
       
  1043                 return null;
       
  1044             }
       
  1045             switch (part) {
       
  1046             case AccessibleText.CHARACTER:
       
  1047                 return TextComponent.this.getText().substring(index, index+1);
       
  1048             case AccessibleText.WORD:  {
       
  1049                     String s = TextComponent.this.getText();
       
  1050                     BreakIterator words = BreakIterator.getWordInstance();
       
  1051                     words.setText(s);
       
  1052                     int end = words.following(index);
       
  1053                     return s.substring(words.previous(), end);
       
  1054                 }
       
  1055             case AccessibleText.SENTENCE:  {
       
  1056                     String s = TextComponent.this.getText();
       
  1057                     BreakIterator sentence = BreakIterator.getSentenceInstance();
       
  1058                     sentence.setText(s);
       
  1059                     int end = sentence.following(index);
       
  1060                     return s.substring(sentence.previous(), end);
       
  1061                 }
       
  1062             default:
       
  1063                 return null;
       
  1064             }
       
  1065         }
       
  1066 
       
  1067         private static final boolean NEXT = true;
       
  1068         private static final boolean PREVIOUS = false;
       
  1069 
       
  1070         /**
       
  1071          * Needed to unify forward and backward searching.
       
  1072          * The method assumes that s is the text assigned to words.
       
  1073          */
       
  1074         private int findWordLimit(int index, BreakIterator words, boolean direction,
       
  1075                                          String s) {
       
  1076             // Fix for 4256660 and 4256661.
       
  1077             // Words iterator is different from character and sentence iterators
       
  1078             // in that end of one word is not necessarily start of another word.
       
  1079             // Please see java.text.BreakIterator JavaDoc. The code below is
       
  1080             // based on nextWordStartAfter example from BreakIterator.java.
       
  1081             int last = (direction == NEXT) ? words.following(index)
       
  1082                                            : words.preceding(index);
       
  1083             int current = (direction == NEXT) ? words.next()
       
  1084                                               : words.previous();
       
  1085             while (current != BreakIterator.DONE) {
       
  1086                 for (int p = Math.min(last, current); p < Math.max(last, current); p++) {
       
  1087                     if (Character.isLetter(s.charAt(p))) {
       
  1088                         return last;
       
  1089                     }
       
  1090                 }
       
  1091                 last = current;
       
  1092                 current = (direction == NEXT) ? words.next()
       
  1093                                               : words.previous();
       
  1094             }
       
  1095             return BreakIterator.DONE;
       
  1096         }
       
  1097 
       
  1098         /**
       
  1099          * Returns the String after a given index.
       
  1100          *
       
  1101          * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
       
  1102          * or AccessibleText.SENTENCE to retrieve
       
  1103          * @param index an index within the text &gt;= 0
       
  1104          * @return the letter, word, or sentence, null for an invalid
       
  1105          *  index or part
       
  1106          */
       
  1107         public String getAfterIndex(int part, int index) {
       
  1108             if (index < 0 || index >= TextComponent.this.getText().length()) {
       
  1109                 return null;
       
  1110             }
       
  1111             switch (part) {
       
  1112             case AccessibleText.CHARACTER:
       
  1113                 if (index+1 >= TextComponent.this.getText().length()) {
       
  1114                    return null;
       
  1115                 }
       
  1116                 return TextComponent.this.getText().substring(index+1, index+2);
       
  1117             case AccessibleText.WORD:  {
       
  1118                     String s = TextComponent.this.getText();
       
  1119                     BreakIterator words = BreakIterator.getWordInstance();
       
  1120                     words.setText(s);
       
  1121                     int start = findWordLimit(index, words, NEXT, s);
       
  1122                     if (start == BreakIterator.DONE || start >= s.length()) {
       
  1123                         return null;
       
  1124                     }
       
  1125                     int end = words.following(start);
       
  1126                     if (end == BreakIterator.DONE || end >= s.length()) {
       
  1127                         return null;
       
  1128                     }
       
  1129                     return s.substring(start, end);
       
  1130                 }
       
  1131             case AccessibleText.SENTENCE:  {
       
  1132                     String s = TextComponent.this.getText();
       
  1133                     BreakIterator sentence = BreakIterator.getSentenceInstance();
       
  1134                     sentence.setText(s);
       
  1135                     int start = sentence.following(index);
       
  1136                     if (start == BreakIterator.DONE || start >= s.length()) {
       
  1137                         return null;
       
  1138                     }
       
  1139                     int end = sentence.following(start);
       
  1140                     if (end == BreakIterator.DONE || end >= s.length()) {
       
  1141                         return null;
       
  1142                     }
       
  1143                     return s.substring(start, end);
       
  1144                 }
       
  1145             default:
       
  1146                 return null;
       
  1147             }
       
  1148         }
       
  1149 
       
  1150 
       
  1151         /**
       
  1152          * Returns the String before a given index.
       
  1153          *
       
  1154          * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
       
  1155          *   or AccessibleText.SENTENCE to retrieve
       
  1156          * @param index an index within the text &gt;= 0
       
  1157          * @return the letter, word, or sentence, null for an invalid index
       
  1158          *  or part
       
  1159          */
       
  1160         public String getBeforeIndex(int part, int index) {
       
  1161             if (index < 0 || index > TextComponent.this.getText().length()-1) {
       
  1162                 return null;
       
  1163             }
       
  1164             switch (part) {
       
  1165             case AccessibleText.CHARACTER:
       
  1166                 if (index == 0) {
       
  1167                     return null;
       
  1168                 }
       
  1169                 return TextComponent.this.getText().substring(index-1, index);
       
  1170             case AccessibleText.WORD:  {
       
  1171                     String s = TextComponent.this.getText();
       
  1172                     BreakIterator words = BreakIterator.getWordInstance();
       
  1173                     words.setText(s);
       
  1174                     int end = findWordLimit(index, words, PREVIOUS, s);
       
  1175                     if (end == BreakIterator.DONE) {
       
  1176                         return null;
       
  1177                     }
       
  1178                     int start = words.preceding(end);
       
  1179                     if (start == BreakIterator.DONE) {
       
  1180                         return null;
       
  1181                     }
       
  1182                     return s.substring(start, end);
       
  1183                 }
       
  1184             case AccessibleText.SENTENCE:  {
       
  1185                     String s = TextComponent.this.getText();
       
  1186                     BreakIterator sentence = BreakIterator.getSentenceInstance();
       
  1187                     sentence.setText(s);
       
  1188                     int end = sentence.following(index);
       
  1189                     end = sentence.previous();
       
  1190                     int start = sentence.previous();
       
  1191                     if (start == BreakIterator.DONE) {
       
  1192                         return null;
       
  1193                     }
       
  1194                     return s.substring(start, end);
       
  1195                 }
       
  1196             default:
       
  1197                 return null;
       
  1198             }
       
  1199         }
       
  1200     }  // end of AccessibleAWTTextComponent
       
  1201 
       
  1202     private boolean checkForEnableIM = true;
       
  1203 }