1 /*
2  * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package java.awt;
26 
27 import java.awt.peer.TextComponentPeer;
28 import java.awt.event.*;
29 import java.util.EventListener;
30 import java.io.ObjectOutputStream;
31 import java.io.ObjectInputStream;
32 import java.io.IOException;
33 import java.text.BreakIterator;
34 import javax.swing.text.AttributeSet;
35 import javax.accessibility.*;
36 import java.awt.im.InputMethodRequests;
37 import sun.awt.AWTPermissions;
38 import sun.awt.InputMethodSupport;
39 
40 /**
41  * The {@code TextComponent} 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  */
60 public 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      */
TextComponent(String text)133     TextComponent(String text) throws HeadlessException {
134         GraphicsEnvironment.checkHeadless();
135         this.text = (text != null) ? text : "";
136         setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
137     }
138 
enableInputMethodsIfNecessary()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      */
enableInputMethods(boolean enable)168     public void enableInputMethods(boolean enable) {
169         checkForEnableIM = false;
170         super.enableInputMethods(enable);
171     }
172 
areInputMethodsEnabled()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 
getInputMethodRequests()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      */
addNotify()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      */
removeNotify()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      */
setText(String t)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      */
getText()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      */
getSelectedText()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      */
isEditable()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      */
setEditable(boolean b)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      */
getBackground()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      */
setBackground(Color c)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      */
getSelectionStart()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      */
setSelectionStart(int selectionStart)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      */
getSelectionEnd()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      */
setSelectionEnd(int selectionEnd)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      */
select(int selectionStart, int selectionEnd)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      */
selectAll()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      */
setCaretPosition(int position)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      */
getCaretPosition()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      */
addTextListener(TextListener l)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      */
removeTextListener(TextListener l)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      */
getTextListeners()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      */
getListeners(Class<T> listenerType)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
eventEnabled(AWTEvent e)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      */
processEvent(AWTEvent e)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      */
processTextEvent(TextEvent e)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      */
paramString()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      */
canAccessClipboard()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      */
writeObject(java.io.ObjectOutputStream s)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      */
readObject(ObjectInputStream s)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      */
getAccessibleContext()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          */
AccessibleAWTTextComponent()870         public AccessibleAWTTextComponent() {
871             TextComponent.this.addTextListener(this);
872         }
873 
874         /**
875          * TextListener notification of a text value change.
876          */
textValueChanged(TextEvent textEvent)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          */
getAccessibleStateSet()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          */
getAccessibleRole()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          */
getAccessibleText()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          */
getIndexAtPoint(Point p)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          */
getCharacterBounds(int i)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          */
getCharCount()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          */
getCaretPosition()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          */
getCharacterAttribute(int i)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          */
getSelectionStart()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          */
getSelectionEnd()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          */
getSelectedText()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          */
getAtIndex(int part, int index)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          */
findWordLimit(int index, BreakIterator words, boolean direction, String s)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          */
getAfterIndex(int part, int index)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          */
getBeforeIndex(int part, int index)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