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