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