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