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