KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > TextComponent


1 /*
2  * @(#)TextComponent.java 1.83 04/05/05
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package java.awt;
8
9 import java.awt.peer.TextComponentPeer;
10 import java.awt.event.*;
11 import java.util.EventListener JavaDoc;
12 import java.io.ObjectOutputStream JavaDoc;
13 import java.io.ObjectInputStream JavaDoc;
14 import java.io.IOException JavaDoc;
15 import sun.awt.InputMethodSupport;
16 import java.text.BreakIterator JavaDoc;
17 import javax.swing.text.AttributeSet JavaDoc;
18 import javax.accessibility.*;
19 import java.awt.im.InputMethodRequests JavaDoc;
20
21
22 /**
23  * The <code>TextComponent</code> class is the superclass of
24  * any component that allows the editing of some text.
25  * <p>
26  * A text component embodies a string of text. The
27  * <code>TextComponent</code> class defines a set of methods
28  * that determine whether or not this text is editable. If the
29  * component is editable, it defines another set of methods
30  * that supports a text insertion caret.
31  * <p>
32  * In addition, the class defines methods that are used
33  * to maintain a current <em>selection</em> from the text.
34  * The text selection, a substring of the component's text,
35  * is the target of editing operations. It is also referred
36  * to as the <em>selected text</em>.
37  *
38  * @version 1.83, 05/05/04
39  * @author Sami Shaio
40  * @author Arthur van Hoff
41  * @since JDK1.0
42  */

43 public class TextComponent extends Component JavaDoc implements Accessible {
44
45     /**
46      * The value of the text.
47      * A <code>null</code> value is the same as "".
48      *
49      * @serial
50      * @see #setText(String)
51      * @see #getText()
52      */

53     String JavaDoc text;
54
55     /**
56      * A boolean indicating whether or not this
57      * <code>TextComponent</code> is editable.
58      * It will be <code>true</code> if the text component
59      * is editable and <code>false</code> if not.
60      *
61      * @serial
62      * @see #isEditable()
63      */

64     boolean editable = true;
65
66     /**
67      * The selection refers to the selected text, and the
68      * <code>selectionStart</code> is the start position
69      * of the selected text.
70      *
71      * @serial
72      * @see #getSelectionStart()
73      * @see #setSelectionStart(int)
74      */

75     int selectionStart;
76
77     /**
78      * The selection refers to the selected text, and the
79      * <code>selectionEnd</code>
80      * is the end position of the selected text.
81      *
82      * @serial
83      * @see #getSelectionEnd()
84      * @see #setSelectionEnd(int)
85      */

86     int selectionEnd;
87
88     // A flag used to tell whether the background has been set by
89
// developer code (as opposed to AWT code). Used to determine
90
// the background color of non-editable TextComponents.
91
boolean backgroundSetByClientCode = false;
92
93     /**
94      * True if this <code>TextComponent</code> has access
95      * to the System clipboard.
96      */

97     transient private boolean canAccessClipboard;
98
99     transient protected TextListener textListener;
100
101     /*
102      * JDK 1.1 serialVersionUID
103      */

104     private static final long serialVersionUID = -2214773872412987419L;
105
106     /**
107      * Constructs a new text component initialized with the
108      * specified text. Sets the value of the cursor to
109      * <code>Cursor.TEXT_CURSOR</code>.
110      * @param text the text to be displayed; if
111      * <code>text</code> is <code>null</code>, the empty
112      * string <code>""</code> will be displayed
113      * @exception HeadlessException if
114      * <code>GraphicsEnvironment.isHeadless</code>
115      * returns true
116      * @see java.awt.GraphicsEnvironment#isHeadless
117      * @see java.awt.Cursor
118      */

119     TextComponent(String JavaDoc text) throws HeadlessException JavaDoc {
120         GraphicsEnvironment.checkHeadless();
121     this.text = (text != null) ? text : "";
122     setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
123     checkSystemClipboardAccess();
124     }
125
126     private void enableInputMethodsIfNecessary() {
127     if (checkForEnableIM) {
128             checkForEnableIM = false;
129             try {
130                 Toolkit JavaDoc toolkit = Toolkit.getDefaultToolkit();
131                 boolean shouldEnable = false;
132                 if (toolkit instanceof InputMethodSupport) {
133                     shouldEnable = ((InputMethodSupport)toolkit)
134                       .enableInputMethodsForTextComponent();
135                 }
136                 enableInputMethods(shouldEnable);
137             } catch (Exception JavaDoc e) {
138                 // if something bad happens, just don't enable input methods
139
}
140         }
141     }
142
143     public void enableInputMethods(boolean enable) {
144         checkForEnableIM = false;
145         super.enableInputMethods(enable);
146     }
147
148     boolean areInputMethodsEnabled() {
149         // moved from the constructor above to here and addNotify below,
150
// this call will initialize the toolkit if not already initialized.
151
if (checkForEnableIM) {
152             enableInputMethodsIfNecessary();
153         }
154
155         // TextComponent handles key events without touching the eventMask or
156
// having a key listener, so just check whether the flag is set
157
return (eventMask & AWTEvent.INPUT_METHODS_ENABLED_MASK) != 0;
158     }
159
160     public InputMethodRequests JavaDoc getInputMethodRequests() {
161         TextComponentPeer peer = (TextComponentPeer)this.peer;
162         if (peer != null) return peer.getInputMethodRequests();
163         else return null;
164     }
165
166
167
168     /**
169      * Makes this Component displayable by connecting it to a
170      * native screen resource.
171      * This method is called internally by the toolkit and should
172      * not be called directly by programs.
173      * @see java.awt.TextComponent#removeNotify
174      */

175     public void addNotify() {
176         super.addNotify();
177         enableInputMethodsIfNecessary();
178     }
179
180     /**
181      * Removes the <code>TextComponent</code>'s peer.
182      * The peer allows us to modify the appearance of the
183      * <code>TextComponent</code> without changing its
184      * functionality.
185      */

186     public void removeNotify() {
187         synchronized (getTreeLock()) {
188         TextComponentPeer peer = (TextComponentPeer)this.peer;
189         if (peer != null) {
190             text = peer.getText();
191         selectionStart = peer.getSelectionStart();
192         selectionEnd = peer.getSelectionEnd();
193         }
194         super.removeNotify();
195     }
196     }
197
198     /**
199      * Sets the text that is presented by this
200      * text component to be the specified text.
201      * @param t the new text;
202      * if this parameter is <code>null</code> then
203      * the text is set to the empty string ""
204      * @see java.awt.TextComponent#getText
205      */

206     public synchronized void setText(String JavaDoc t) {
207     text = (t != null) ? t : "";
208     TextComponentPeer peer = (TextComponentPeer)this.peer;
209     if (peer != null) {
210         peer.setText(text);
211     }
212     }
213
214     /**
215      * Returns the text that is presented by this text component.
216      * By default, this is an empty string.
217      *
218      * @return the value of this <code>TextComponent</code>
219      * @see java.awt.TextComponent#setText
220      */

221     public synchronized String JavaDoc getText() {
222     TextComponentPeer peer = (TextComponentPeer)this.peer;
223     if (peer != null) {
224         text = peer.getText();
225     }
226     return text;
227     }
228
229     /**
230      * Returns the selected text from the text that is
231      * presented by this text component.
232      * @return the selected text of this text component
233      * @see java.awt.TextComponent#select
234      */

235     public synchronized String JavaDoc getSelectedText() {
236     return getText().substring(getSelectionStart(), getSelectionEnd());
237     }
238
239     /**
240      * Indicates whether or not this text component is editable.
241      * @return <code>true</code> if this text component is
242      * editable; <code>false</code> otherwise.
243      * @see java.awt.TextComponent#setEditable
244      * @since JDK1.0
245      */

246     public boolean isEditable() {
247     return editable;
248     }
249
250     /**
251      * Sets the flag that determines whether or not this
252      * text component is editable.
253      * <p>
254      * If the flag is set to <code>true</code>, this text component
255      * becomes user editable. If the flag is set to <code>false</code>,
256      * the user cannot change the text of this text component.
257      * By default, non-editable text components have a background color
258      * of SystemColor.control. This default can be overridden by
259      * calling setBackground.
260      *
261      * @param b a flag indicating whether this text component
262      * is user editable.
263      * @see java.awt.TextComponent#isEditable
264      * @since JDK1.0
265      */

266     public synchronized void setEditable(boolean b) {
267         if (editable == b) {
268             return;
269         }
270
271     editable = b;
272     TextComponentPeer peer = (TextComponentPeer)this.peer;
273     if (peer != null) {
274         peer.setEditable(b);
275     }
276     }
277
278     /**
279      * Gets the background color of this text component.
280      *
281      * By default, non-editable text components have a background color
282      * of SystemColor.control. This default can be overridden by
283      * calling setBackground.
284      *
285      * @return This text component's background color.
286      * If this text component does not have a background color,
287      * the background color of its parent is returned.
288      * @see #setBackground(Color)
289      * @since JDK1.0
290      */

291     public Color JavaDoc getBackground() {
292         if (!editable && !backgroundSetByClientCode) {
293             return SystemColor.control;
294         }
295
296         return super.getBackground();
297     }
298
299     /**
300      * Sets the background color of this text component.
301      *
302      * @param c The color to become this text component's color.
303      * If this parameter is null then this text component
304      * will inherit the background color of its parent.
305      * @see #getBackground()
306      * @since JDK1.0
307      */

308     public void setBackground(Color JavaDoc c) {
309         backgroundSetByClientCode = true;
310         super.setBackground(c);
311     }
312
313     /**
314      * Gets the start position of the selected text in
315      * this text component.
316      * @return the start position of the selected text
317      * @see java.awt.TextComponent#setSelectionStart
318      * @see java.awt.TextComponent#getSelectionEnd
319      */

320     public synchronized int getSelectionStart() {
321     TextComponentPeer peer = (TextComponentPeer)this.peer;
322     if (peer != null) {
323         selectionStart = peer.getSelectionStart();
324     }
325     return selectionStart;
326     }
327
328     /**
329      * Sets the selection start for this text component to
330      * the specified position. The new start point is constrained
331      * to be at or before the current selection end. It also
332      * cannot be set to less than zero, the beginning of the
333      * component's text.
334      * If the caller supplies a value for <code>selectionStart</code>
335      * that is out of bounds, the method enforces these constraints
336      * silently, and without failure.
337      * @param selectionStart the start position of the
338      * selected text
339      * @see java.awt.TextComponent#getSelectionStart
340      * @see java.awt.TextComponent#setSelectionEnd
341      * @since JDK1.1
342      */

343     public synchronized void setSelectionStart(int selectionStart) {
344     /* Route through select method to enforce consistent policy
345          * between selectionStart and selectionEnd.
346          */

347     select(selectionStart, getSelectionEnd());
348     }
349
350     /**
351      * Gets the end position of the selected text in
352      * this text component.
353      * @return the end position of the selected text
354      * @see java.awt.TextComponent#setSelectionEnd
355      * @see java.awt.TextComponent#getSelectionStart
356      */

357     public synchronized int getSelectionEnd() {
358     TextComponentPeer peer = (TextComponentPeer)this.peer;
359     if (peer != null) {
360         selectionEnd = peer.getSelectionEnd();
361     }
362     return selectionEnd;
363     }
364
365     /**
366      * Sets the selection end for this text component to
367      * the specified position. The new end point is constrained
368      * to be at or after the current selection start. It also
369      * cannot be set beyond the end of the component's text.
370      * If the caller supplies a value for <code>selectionEnd</code>
371      * that is out of bounds, the method enforces these constraints
372      * silently, and without failure.
373      * @param selectionEnd the end position of the
374      * selected text
375      * @see java.awt.TextComponent#getSelectionEnd
376      * @see java.awt.TextComponent#setSelectionStart
377      * @since JDK1.1
378      */

379     public synchronized void setSelectionEnd(int selectionEnd) {
380     /* Route through select method to enforce consistent policy
381          * between selectionStart and selectionEnd.
382          */

383     select(getSelectionStart(), selectionEnd);
384     }
385     
386     /**
387      * Selects the text between the specified start and end positions.
388      * <p>
389      * This method sets the start and end positions of the
390      * selected text, enforcing the restriction that the start position
391      * must be greater than or equal to zero. The end position must be
392      * greater than or equal to the start position, and less than or
393      * equal to the length of the text component's text. The
394      * character positions are indexed starting with zero.
395      * The length of the selection is
396      * <code>endPosition</code> - <code>startPosition</code>, so the
397      * character at <code>endPosition</code> is not selected.
398      * If the start and end positions of the selected text are equal,
399      * all text is deselected.
400      * <p>
401      * If the caller supplies values that are inconsistent or out of
402      * bounds, the method enforces these constraints silently, and
403      * without failure. Specifically, if the start position or end
404      * position is greater than the length of the text, it is reset to
405      * equal the text length. If the start position is less than zero,
406      * it is reset to zero, and if the end position is less than the
407      * start position, it is reset to the start position.
408      *
409      * @param selectionStart the zero-based index of the first
410                        character (<code>char</code> value) to be selected
411      * @param selectionEnd the zero-based end position of the
412                        text to be selected; the character (<code>char</code> value) at
413                        <code>selectionEnd</code> is not selected
414      * @see java.awt.TextComponent#setSelectionStart
415      * @see java.awt.TextComponent#setSelectionEnd
416      * @see java.awt.TextComponent#selectAll
417      */

418     public synchronized void select(int selectionStart, int selectionEnd) {
419     String JavaDoc text = getText();
420     if (selectionStart < 0) {
421         selectionStart = 0;
422     }
423     if (selectionStart > text.length()) {
424         selectionStart = text.length();
425     }
426     if (selectionEnd > text.length()) {
427         selectionEnd = text.length();
428     }
429     if (selectionEnd < selectionStart) {
430         selectionEnd = selectionStart;
431     }
432
433     this.selectionStart = selectionStart;
434     this.selectionEnd = selectionEnd;
435
436     TextComponentPeer peer = (TextComponentPeer)this.peer;
437     if (peer != null) {
438         peer.select(selectionStart, selectionEnd);
439     }
440     }
441
442     /**
443      * Selects all the text in this text component.
444      * @see java.awt.TextComponent#select
445      */

446     public synchronized void selectAll() {
447     String JavaDoc text = getText();
448     this.selectionStart = 0;
449     this.selectionEnd = getText().length();
450
451     TextComponentPeer peer = (TextComponentPeer)this.peer;
452     if (peer != null) {
453         peer.select(selectionStart, selectionEnd);
454     }
455     }
456
457     /**
458      * Sets the position of the text insertion caret.
459      * The caret position is constrained to be between 0
460      * and the last character of the text, inclusive.
461      * If the passed-in value is greater than this range,
462      * the value is set to the last character (or 0 if
463      * the <code>TextComponent</code> contains no text)
464      * and no error is returned. If the passed-in value is
465      * less than 0, an <code>IllegalArgumentException</code>
466      * is thrown.
467      *
468      * @param position the position of the text insertion caret
469      * @exception IllegalArgumentException if <code>position</code>
470      * is less than zero
471      * @since JDK1.1
472      */

473     public synchronized void setCaretPosition(int position) {
474     if (position < 0) {
475         throw new IllegalArgumentException JavaDoc("position less than zero.");
476     }
477
478     int maxposition = getText().length();
479     if (position > maxposition) {
480         position = maxposition;
481     }
482
483     TextComponentPeer peer = (TextComponentPeer)this.peer;
484     if (peer != null) {
485         peer.setCaretPosition(position);
486     } else {
487         select(position, position);
488     }
489     }
490
491     /**
492      * Returns the position of the text insertion caret.
493      * The caret position is constrained to be between 0
494      * and the last character of the text, inclusive.
495      * If the text or caret have not been set, the default
496      * caret position is 0.
497      *
498      * @return the position of the text insertion caret
499      * @see #setCaretPosition(int)
500      * @since JDK1.1
501      */

502     public synchronized int getCaretPosition() {
503         TextComponentPeer peer = (TextComponentPeer)this.peer;
504     int position = 0;
505
506     if (peer != null) {
507         position = peer.getCaretPosition();
508     } else {
509         position = selectionStart;
510     }
511     return position;
512     }
513
514     /**
515      * Adds the specified text event listener to receive text events
516      * from this text component.
517      * If <code>l</code> is <code>null</code>, no exception is
518      * thrown and no action is performed.
519      *
520      * @param l the text event listener
521      * @see #removeTextListener
522      * @see #getTextListeners
523      * @see java.awt.event.TextListener
524      */

525     public synchronized void addTextListener(TextListener l) {
526     if (l == null) {
527         return;
528     }
529     textListener = AWTEventMulticaster.add(textListener, l);
530         newEventsOnly = true;
531     }
532
533     /**
534      * Removes the specified text event listener so that it no longer
535      * receives text events from this text component
536      * If <code>l</code> is <code>null</code>, no exception is
537      * thrown and no action is performed.
538      *
539      * @param l the text listener
540      * @see #addTextListener
541      * @see #getTextListeners
542      * @see java.awt.event.TextListener
543      * @since JDK1.1
544      */

545     public synchronized void removeTextListener(TextListener l) {
546     if (l == null) {
547         return;
548     }
549     textListener = AWTEventMulticaster.remove(textListener, l);
550     }
551
552     /**
553      * Returns an array of all the text listeners
554      * registered on this text component.
555      *
556      * @return all of this text component's <code>TextListener</code>s
557      * or an empty array if no text
558      * listeners are currently registered
559      *
560      *
561      * @see #addTextListener
562      * @see #removeTextListener
563      * @since 1.4
564      */

565     public synchronized TextListener[] getTextListeners() {
566         return (TextListener[])(getListeners(TextListener.class));
567     }
568
569     /**
570      * Returns an array of all the objects currently registered
571      * as <code><em>Foo</em>Listener</code>s
572      * upon this <code>TextComponent</code>.
573      * <code><em>Foo</em>Listener</code>s are registered using the
574      * <code>add<em>Foo</em>Listener</code> method.
575      *
576      * <p>
577      * You can specify the <code>listenerType</code> argument
578      * with a class literal, such as
579      * <code><em>Foo</em>Listener.class</code>.
580      * For example, you can query a
581      * <code>TextComponent</code> <code>t</code>
582      * for its text listeners with the following code:
583      *
584      * <pre>TextListener[] tls = (TextListener[])(t.getListeners(TextListener.class));</pre>
585      *
586      * If no such listeners exist, this method returns an empty array.
587      *
588      * @param listenerType the type of listeners requested; this parameter
589      * should specify an interface that descends from
590      * <code>java.util.EventListener</code>
591      * @return an array of all objects registered as
592      * <code><em>Foo</em>Listener</code>s on this text component,
593      * or an empty array if no such
594      * listeners have been added
595      * @exception ClassCastException if <code>listenerType</code>
596      * doesn't specify a class or interface that implements
597      * <code>java.util.EventListener</code>
598      *
599      * @see #getTextListeners
600      * @since 1.3
601      */

602     public <T extends EventListener JavaDoc> T[] getListeners(Class JavaDoc<T> listenerType) {
603     EventListener JavaDoc l = null;
604     if (listenerType == TextListener.class) {
605         l = textListener;
606     } else {
607         return super.getListeners(listenerType);
608     }
609     return AWTEventMulticaster.getListeners(l, listenerType);
610     }
611
612     // REMIND: remove when filtering is done at lower level
613
boolean eventEnabled(AWTEvent JavaDoc e) {
614         if (e.id == TextEvent.TEXT_VALUE_CHANGED) {
615             if ((eventMask & AWTEvent.TEXT_EVENT_MASK) != 0 ||
616                 textListener != null) {
617                 return true;
618             }
619             return false;
620         }
621         return super.eventEnabled(e);
622     }
623
624     /**
625      * Processes events on this text component. If the event is a
626      * <code>TextEvent</code>, it invokes the <code>processTextEvent</code>
627      * method else it invokes its superclass's <code>processEvent</code>.
628      * <p>Note that if the event parameter is <code>null</code>
629      * the behavior is unspecified and may result in an
630      * exception.
631      *
632      * @param e the event
633      */

634     protected void processEvent(AWTEvent JavaDoc e) {
635         if (e instanceof TextEvent) {
636             processTextEvent((TextEvent)e);
637             return;
638         }
639     super.processEvent(e);
640     }
641
642     /**
643      * Processes text events occurring on this text component by
644      * dispatching them to any registered <code>TextListener</code> objects.
645      * <p>
646      * NOTE: This method will not be called unless text events
647      * are enabled for this component. This happens when one of the
648      * following occurs:
649      * <ul>
650      * <li>A <code>TextListener</code> object is registered
651      * via <code>addTextListener</code>
652      * <li>Text events are enabled via <code>enableEvents</code>
653      * </ul>
654      * <p>Note that if the event parameter is <code>null</code>
655      * the behavior is unspecified and may result in an
656      * exception.
657      *
658      * @param e the text event
659      * @see Component#enableEvents
660      */

661     protected void processTextEvent(TextEvent e) {
662         TextListener listener = textListener;
663         if (listener != null) {
664             int id = e.getID();
665         switch (id) {
666         case TextEvent.TEXT_VALUE_CHANGED:
667         listener.textValueChanged(e);
668         break;
669         }
670         }
671     }
672
673     /**
674      * Returns a string representing the state of this
675      * <code>TextComponent</code>. This
676      * method is intended to be used only for debugging purposes, and the
677      * content and format of the returned string may vary between
678      * implementations. The returned string may be empty but may not be
679      * <code>null</code>.
680      *
681      * @return the parameter string of this text component
682      */

683     protected String JavaDoc paramString() {
684     String JavaDoc str = super.paramString() + ",text=" + getText();
685     if (editable) {
686         str += ",editable";
687     }
688     return str + ",selection=" + getSelectionStart() + "-" + getSelectionEnd();
689     }
690
691     /**
692      * Assigns a valid value to the canAccessClipboard instance variable.
693      */

694     private void checkSystemClipboardAccess() {
695         canAccessClipboard = true;
696     SecurityManager JavaDoc sm = System.getSecurityManager();
697     if (sm != null) {
698         try {
699             sm.checkSystemClipboardAccess();
700         }
701         catch (SecurityException JavaDoc e) {
702             canAccessClipboard = false;
703         }
704     }
705     }
706
707     /*
708      * Serialization support.
709      */

710     /**
711      * The textComponent SerializedDataVersion.
712      *
713      * @serial
714      */

715     private int textComponentSerializedDataVersion = 1;
716
717     /**
718      * Writes default serializable fields to stream. Writes
719      * a list of serializable TextListener(s) as optional data.
720      * The non-serializable TextListener(s) are detected and
721      * no attempt is made to serialize them.
722      *
723      * @serialData Null terminated sequence of zero or more pairs.
724      * A pair consists of a String and Object.
725      * The String indicates the type of object and
726      * is one of the following :
727      * textListenerK indicating and TextListener object.
728      *
729      * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
730      * @see java.awt.Component#textListenerK
731      */

732     private void writeObject(java.io.ObjectOutputStream JavaDoc s)
733       throws IOException JavaDoc
734     {
735         // Serialization support. Since the value of the fields
736
// selectionStart, selectionEnd, and text aren't necessarily
737
// up to date, we sync them up with the peer before serializing.
738
TextComponentPeer peer = (TextComponentPeer)this.peer;
739         if (peer != null) {
740             text = peer.getText();
741             selectionStart = peer.getSelectionStart();
742             selectionEnd = peer.getSelectionEnd();
743         }
744
745         s.defaultWriteObject();
746
747         AWTEventMulticaster.save(s, textListenerK, textListener);
748         s.writeObject(null);
749     }
750
751     /**
752      * Read the ObjectInputStream, and if it isn't null,
753      * add a listener to receive text events fired by the
754      * TextComponent. Unrecognized keys or values will be
755      * ignored.
756      *
757      * @exception HeadlessException if
758      * <code>GraphicsEnvironment.isHeadless()</code> returns
759      * <code>true</code>
760      * @see #removeTextListener()
761      * @see #addTextListener()
762      * @see java.awt.GraphicsEnvironment#isHeadless
763      */

764     private void readObject(ObjectInputStream JavaDoc s)
765         throws ClassNotFoundException JavaDoc, IOException JavaDoc, HeadlessException JavaDoc
766     {
767         GraphicsEnvironment.checkHeadless();
768         s.defaultReadObject();
769
770         // Make sure the state we just read in for text,
771
// selectionStart and selectionEnd has legal values
772
this.text = (text != null) ? text : "";
773         select(selectionStart, selectionEnd);
774
775         Object JavaDoc keyOrNull;
776         while(null != (keyOrNull = s.readObject())) {
777         String JavaDoc key = ((String JavaDoc)keyOrNull).intern();
778
779         if (textListenerK == key) {
780             addTextListener((TextListener)(s.readObject()));
781             } else {
782                 // skip value for unrecognized key
783
s.readObject();
784             }
785         }
786     enableInputMethodsIfNecessary();
787     checkSystemClipboardAccess();
788     }
789
790
791 /////////////////
792
// Accessibility support
793
////////////////
794

795
796     /**
797      *
798      */

799     int getIndexAtPoint(Point JavaDoc p) {
800     return -1;
801 /* To be fully implemented in a future release
802     if (peer == null) {
803         return -1;
804     }
805     TextComponentPeer peer = (TextComponentPeer)this.peer;
806     return peer.getIndexAtPoint(p.x, p.y);
807 */

808     }
809
810
811     /**
812      *
813      */

814     Rectangle JavaDoc getCharacterBounds(int i) {
815         return null;
816 /* To be fully implemented in a future release
817     if (peer == null) {
818         return null;
819     }
820     TextComponentPeer peer = (TextComponentPeer)this.peer;
821     return peer.getCharacterBounds(i);
822 */

823     }
824
825
826     /**
827      * Gets the AccessibleContext associated with this TextComponent.
828      * For text components, the AccessibleContext takes the form of an
829      * AccessibleAWTTextComponent.
830      * A new AccessibleAWTTextComponent instance is created if necessary.
831      *
832      * @return an AccessibleAWTTextComponent that serves as the
833      * AccessibleContext of this TextComponent
834      */

835     public AccessibleContext getAccessibleContext() {
836         if (accessibleContext == null) {
837             accessibleContext = new AccessibleAWTTextComponent();
838         }
839         return accessibleContext;
840     }
841
842     /**
843      * This class implements accessibility support for the
844      * <code>TextComponent</code> class. It provides an implementation of the
845      * Java Accessibility API appropriate to text component user-interface
846      * elements.
847      */

848     protected class AccessibleAWTTextComponent extends AccessibleAWTComponent
849         implements AccessibleText, TextListener
850     {
851         /*
852          * JDK 1.3 serialVersionUID
853          */

854         private static final long serialVersionUID = 3631432373506317811L;
855
856         /**
857          * Constructs an AccessibleAWTTextComponent. Adds a listener to track
858          * caret change.
859          */

860         public AccessibleAWTTextComponent() {
861             TextComponent.this.addTextListener(this);
862         }
863
864         /**
865          * TextListener notification of a text value change.
866          */

867         public void textValueChanged(TextEvent textEvent) {
868             Integer JavaDoc cpos = new Integer JavaDoc(TextComponent.this.getCaretPosition());
869             firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, cpos);
870         }
871
872         /**
873          * Gets the state set of the TextComponent.
874          * The AccessibleStateSet of an object is composed of a set of
875          * unique AccessibleStates. A change in the AccessibleStateSet
876          * of an object will cause a PropertyChangeEvent to be fired
877          * for the AccessibleContext.ACCESSIBLE_STATE_PROPERTY property.
878          *
879          * @return an instance of AccessibleStateSet containing the
880          * current state set of the object
881          * @see AccessibleStateSet
882          * @see AccessibleState
883          * @see #addPropertyChangeListener
884          */

885         public AccessibleStateSet getAccessibleStateSet() {
886             AccessibleStateSet states = super.getAccessibleStateSet();
887             if (TextComponent.this.isEditable()) {
888                 states.add(AccessibleState.EDITABLE);
889             }
890             return states;
891         }
892
893
894         /**
895          * Gets the role of this object.
896          *
897          * @return an instance of AccessibleRole describing the role of the
898          * object (AccessibleRole.TEXT)
899          * @see AccessibleRole
900          */

901         public AccessibleRole getAccessibleRole() {
902             return AccessibleRole.TEXT;
903         }
904
905         /**
906          * Get the AccessibleText associated with this object. In the
907          * implementation of the Java Accessibility API for this class,
908      * return this object, which is responsible for implementing the
909          * AccessibleText interface on behalf of itself.
910      *
911      * @return this object
912          */

913         public AccessibleText getAccessibleText() {
914             return this;
915         }
916
917
918         // --- interface AccessibleText methods ------------------------
919

920         /**
921          * Many of these methods are just convenience methods; they
922          * just call the equivalent on the parent
923          */

924
925         /**
926          * Given a point in local coordinates, return the zero-based index
927          * of the character under that Point. If the point is invalid,
928          * this method returns -1.
929          *
930          * @param p the Point in local coordinates
931          * @return the zero-based index of the character under Point p.
932          */

933         public int getIndexAtPoint(Point JavaDoc p) {
934         return TextComponent.this.getIndexAtPoint(p);
935         }
936
937         /**
938          * Determines the bounding box of the character at the given
939          * index into the string. The bounds are returned in local
940          * coordinates. If the index is invalid a null rectangle
941          * is returned.
942          *
943          * @param i the index into the String >= 0
944          * @return the screen coordinates of the character's bounding box
945          */

946         public Rectangle JavaDoc getCharacterBounds(int i) {
947         return TextComponent.this.getCharacterBounds(i);
948         }
949
950         /**
951          * Returns the number of characters (valid indicies)
952          *
953          * @return the number of characters >= 0
954          */

955         public int getCharCount() {
956             return TextComponent.this.getText().length();
957         }
958
959         /**
960          * Returns the zero-based offset of the caret.
961          *
962          * Note: The character to the right of the caret will have the
963          * same index value as the offset (the caret is between
964          * two characters).
965          *
966          * @return the zero-based offset of the caret.
967          */

968         public int getCaretPosition() {
969             return TextComponent.this.getCaretPosition();
970         }
971
972         /**
973          * Returns the AttributeSet for a given character (at a given index).
974          *
975          * @param i the zero-based index into the text
976          * @return the AttributeSet of the character
977          */

978         public AttributeSet JavaDoc getCharacterAttribute(int i) {
979             return null; // No attributes in TextComponent
980
}
981
982         /**
983          * Returns the start offset within the selected text.
984          * If there is no selection, but there is
985          * a caret, the start and end offsets will be the same.
986          * Return 0 if the text is empty, or the caret position
987          * if no selection.
988          *
989          * @return the index into the text of the start of the selection >= 0
990          */

991         public int getSelectionStart() {
992             return TextComponent.this.getSelectionStart();
993         }
994
995         /**
996          * Returns the end offset within the selected text.
997          * If there is no selection, but there is
998          * a caret, the start and end offsets will be the same.
999          * Return 0 if the text is empty, or the caret position
1000         * if no selection.
1001         *
1002         * @return the index into teh text of the end of the selection >= 0
1003         */

1004        public int getSelectionEnd() {
1005            return TextComponent.this.getSelectionEnd();
1006        }
1007
1008        /**
1009         * Returns the portion of the text that is selected.
1010         *
1011         * @return the text, null if no selection
1012         */

1013        public String JavaDoc getSelectedText() {
1014            String JavaDoc selText = TextComponent.this.getSelectedText();
1015            // Fix for 4256662
1016
if (selText == null || selText.equals("")) {
1017                return null;
1018            }
1019            return selText;
1020        }
1021
1022        /**
1023         * Returns the String at a given index.
1024         *
1025         * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
1026         * or AccessibleText.SENTENCE to retrieve
1027         * @param index an index within the text >= 0
1028         * @return the letter, word, or sentence,
1029         * null for an invalid index or part
1030         */

1031        public String JavaDoc getAtIndex(int part, int index) {
1032            if (index < 0 || index >= TextComponent.this.getText().length()) {
1033                return null;
1034            }
1035            switch (part) {
1036            case AccessibleText.CHARACTER:
1037                return TextComponent.this.getText().substring(index, index+1);
1038            case AccessibleText.WORD: {
1039                    String JavaDoc s = TextComponent.this.getText();
1040                    BreakIterator JavaDoc words = BreakIterator.getWordInstance();
1041                    words.setText(s);
1042                    int end = words.following(index);
1043                    return s.substring(words.previous(), end);
1044                }
1045            case AccessibleText.SENTENCE: {
1046                    String JavaDoc s = TextComponent.this.getText();
1047                    BreakIterator JavaDoc sentence = BreakIterator.getSentenceInstance();
1048                    sentence.setText(s);
1049                    int end = sentence.following(index);
1050                    return s.substring(sentence.previous(), end);
1051                }
1052            default:
1053                return null;
1054            }
1055        }
1056
1057        private static final boolean NEXT = true;
1058        private static final boolean PREVIOUS = false;
1059
1060        /**
1061         * Needed to unify forward and backward searching.
1062         * The method assumes that s is the text assigned to words.
1063         */

1064        private int findWordLimit(int index, BreakIterator JavaDoc words, boolean direction,
1065                                         String JavaDoc s) {
1066            // Fix for 4256660 and 4256661.
1067
// Words iterator is different from character and sentence iterators
1068
// in that end of one word is not necessarily start of another word.
1069
// Please see java.text.BreakIterator JavaDoc. The code below is
1070
// based on nextWordStartAfter example from BreakIterator.java.
1071
int last = (direction == NEXT) ? words.following(index)
1072                                           : words.preceding(index);
1073            int current = (direction == NEXT) ? words.next()
1074                                              : words.previous();
1075            while (current != BreakIterator.DONE) {
1076                for (int p = Math.min(last, current); p < Math.max(last, current); p++) {
1077                    if (Character.isLetter(s.charAt(p))) {
1078                        return last;
1079                    }
1080                }
1081                last = current;
1082                current = (direction == NEXT) ? words.next()
1083                                              : words.previous();
1084            }
1085            return BreakIterator.DONE;
1086        }
1087
1088        /**
1089         * Returns the String after a given index.
1090         *
1091         * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
1092         * or AccessibleText.SENTENCE to retrieve
1093         * @param index an index within the text >= 0
1094         * @return the letter, word, or sentence, null for an invalid
1095         * index or part
1096         */

1097        public String JavaDoc getAfterIndex(int part, int index) {
1098            if (index < 0 || index >= TextComponent.this.getText().length()) {
1099                return null;
1100            }
1101            switch (part) {
1102            case AccessibleText.CHARACTER:
1103                if (index+1 >= TextComponent.this.getText().length()) {
1104           return null;
1105        }
1106                return TextComponent.this.getText().substring(index+1, index+2);
1107            case AccessibleText.WORD: {
1108                    String JavaDoc s = TextComponent.this.getText();
1109                    BreakIterator JavaDoc words = BreakIterator.getWordInstance();
1110                    words.setText(s);
1111                    int start = findWordLimit(index, words, NEXT, s);
1112                    if (start == BreakIterator.DONE || start >= s.length()) {
1113                        return null;
1114                    }
1115                    int end = words.following(start);
1116                    if (end == BreakIterator.DONE || end >= s.length()) {
1117                        return null;
1118                    }
1119                    return s.substring(start, end);
1120                }
1121            case AccessibleText.SENTENCE: {
1122                    String JavaDoc s = TextComponent.this.getText();
1123                    BreakIterator JavaDoc sentence = BreakIterator.getSentenceInstance();
1124                    sentence.setText(s);
1125                    int start = sentence.following(index);
1126                    if (start == BreakIterator.DONE || start >= s.length()) {
1127                        return null;
1128                    }
1129                    int end = sentence.following(start);
1130                    if (end == BreakIterator.DONE || end >= s.length()) {
1131                        return null;
1132                    }
1133                    return s.substring(start, end);
1134                }
1135            default:
1136                return null;
1137            }
1138        }
1139
1140
1141        /**
1142         * Returns the String before a given index.
1143         *
1144         * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
1145         * or AccessibleText.SENTENCE to retrieve
1146         * @param index an index within the text >= 0
1147         * @return the letter, word, or sentence, null for an invalid index
1148         * or part
1149         */

1150        public String JavaDoc getBeforeIndex(int part, int index) {
1151            if (index < 0 || index > TextComponent.this.getText().length()-1) {
1152                return null;
1153            }
1154            switch (part) {
1155            case AccessibleText.CHARACTER:
1156        if (index == 0) {
1157            return null;
1158        }
1159                return TextComponent.this.getText().substring(index-1, index);
1160            case AccessibleText.WORD: {
1161                    String JavaDoc s = TextComponent.this.getText();
1162                    BreakIterator JavaDoc words = BreakIterator.getWordInstance();
1163                    words.setText(s);
1164                    int end = findWordLimit(index, words, PREVIOUS, s);
1165                    if (end == BreakIterator.DONE) {
1166                        return null;
1167                    }
1168                    int start = words.preceding(end);
1169                    if (start == BreakIterator.DONE) {
1170                        return null;
1171                    }
1172                    return s.substring(start, end);
1173                }
1174            case AccessibleText.SENTENCE: {
1175                    String JavaDoc s = TextComponent.this.getText();
1176                    BreakIterator JavaDoc sentence = BreakIterator.getSentenceInstance();
1177                    sentence.setText(s);
1178                    int end = sentence.following(index);
1179                    end = sentence.previous();
1180                    int start = sentence.previous();
1181                    if (start == BreakIterator.DONE) {
1182                        return null;
1183                    }
1184                    return s.substring(start, end);
1185                }
1186            default:
1187                return null;
1188            }
1189        }
1190    } // end of AccessibleAWTTextComponent
1191

1192    private boolean checkForEnableIM = true;
1193}
1194
Popular Tags