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