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