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</code> class is the superclass of
42 * any component that allows the editing of some text.
43 * <p>
44 * A text component embodies a string of text. The
45 * <code>TextComponent</code> class defines a set of methods
46 * that determine whether or not this text is editable. If the
47 * component is editable, it defines another set of methods
48 * that supports a text insertion caret.
49 * <p>
50 * In addition, the class defines methods that are used
51 * to maintain a current <em>selection</em> from the text.
52 * The text selection, a substring of the component's text,
53 * is the target of editing operations. It is also referred
54 * to as the <em>selected text</em>.
55 *
56 * @author Sami Shaio
57 * @author Arthur van Hoff
58 * @since 1.0
59 */
60 public class TextComponent extends Component implements Accessible {
61
62 /**
63 * The value of the text.
64 * A <code>null</code> value is the same as "".
65 *
66 * @serial
67 * @see #setText(String)
68 * @see #getText()
69 */
70 String text;
71
72 /**
73 * A boolean indicating whether or not this
74 * <code>TextComponent</code> is editable.
75 * It will be <code>true</code> if the text component
76 * is editable and <code>false</code> if not.
77 *
78 * @serial
79 * @see #isEditable()
80 */
81 boolean editable = true;
82
83 /**
84 * The selection refers to the selected text, and the
85 * <code>selectionStart</code> is the start position
86 * of the selected text.
87 *
88 * @serial
89 * @see #getSelectionStart()
90 * @see #setSelectionStart(int)
91 */
92 int selectionStart;
93
94 /**
95 * The selection refers to the selected text, and the
96 * <code>selectionEnd</code>
97 * is the end position of the selected text.
98 *
99 * @serial
100 * @see #getSelectionEnd()
101 * @see #setSelectionEnd(int)
102 */
103 int selectionEnd;
104
105 // A flag used to tell whether the background has been set by
106 // developer code (as opposed to AWT code). Used to determine
107 // the background color of non-editable TextComponents.
108 boolean backgroundSetByClientCode = false;
109
110 /**
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</code>.
124 * @param text the text to be displayed; if
125 * <code>text</code> is <code>null</code>, the empty
126 * string <code>""</code> will be displayed
127 * @exception HeadlessException if
128 * <code>GraphicsEnvironment.isHeadless</code>
129 * returns true
130 * @see java.awt.GraphicsEnvironment#isHeadless
131 * @see java.awt.Cursor
132 */
133 TextComponent(String text) throws HeadlessException {
134 GraphicsEnvironment.checkHeadless();
135 this.text = (text != null) ? text : "";
136 setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
137 }
138
139 private void enableInputMethodsIfNecessary() {
140 if (checkForEnableIM) {
141 checkForEnableIM = false;
142 try {
143 Toolkit toolkit = Toolkit.getDefaultToolkit();
144 boolean shouldEnable = false;
145 if (toolkit instanceof InputMethodSupport) {
146 shouldEnable = ((InputMethodSupport)toolkit)
147 .enableInputMethodsForTextComponent();
148 }
186 TextComponentPeer peer = (TextComponentPeer)this.peer;
187 if (peer != null) return peer.getInputMethodRequests();
188 else return null;
189 }
190
191
192
193 /**
194 * Makes this Component displayable by connecting it to a
195 * native screen resource.
196 * This method is called internally by the toolkit and should
197 * not be called directly by programs.
198 * @see java.awt.TextComponent#removeNotify
199 */
200 public void addNotify() {
201 super.addNotify();
202 enableInputMethodsIfNecessary();
203 }
204
205 /**
206 * Removes the <code>TextComponent</code>'s peer.
207 * The peer allows us to modify the appearance of the
208 * <code>TextComponent</code> without changing its
209 * functionality.
210 */
211 public void removeNotify() {
212 synchronized (getTreeLock()) {
213 TextComponentPeer peer = (TextComponentPeer)this.peer;
214 if (peer != null) {
215 text = peer.getText();
216 selectionStart = peer.getSelectionStart();
217 selectionEnd = peer.getSelectionEnd();
218 }
219 super.removeNotify();
220 }
221 }
222
223 /**
224 * Sets the text that is presented by this
225 * text component to be the specified text.
226 * @param t the new text;
227 * if this parameter is <code>null</code> then
228 * the text is set to the empty string ""
229 * @see java.awt.TextComponent#getText
230 */
231 public synchronized void setText(String t) {
232 boolean skipTextEvent = (text == null || text.isEmpty())
233 && (t == null || t.isEmpty());
234 text = (t != null) ? t : "";
235 TextComponentPeer peer = (TextComponentPeer)this.peer;
236 // Please note that we do not want to post an event
237 // if TextArea.setText() or TextField.setText() replaces an empty text
238 // by an empty text, that is, if component's text remains unchanged.
239 if (peer != null && !skipTextEvent) {
240 peer.setText(text);
241 }
242 }
243
244 /**
245 * Returns the text that is presented by this text component.
246 * By default, this is an empty string.
247 *
248 * @return the value of this <code>TextComponent</code>
249 * @see java.awt.TextComponent#setText
250 */
251 public synchronized String getText() {
252 TextComponentPeer peer = (TextComponentPeer)this.peer;
253 if (peer != null) {
254 text = peer.getText();
255 }
256 return text;
257 }
258
259 /**
260 * Returns the selected text from the text that is
261 * presented by this text component.
262 * @return the selected text of this text component
263 * @see java.awt.TextComponent#select
264 */
265 public synchronized String getSelectedText() {
266 return getText().substring(getSelectionStart(), getSelectionEnd());
267 }
268
269 /**
270 * Indicates whether or not this text component is editable.
271 * @return <code>true</code> if this text component is
272 * editable; <code>false</code> otherwise.
273 * @see java.awt.TextComponent#setEditable
274 * @since 1.0
275 */
276 public boolean isEditable() {
277 return editable;
278 }
279
280 /**
281 * Sets the flag that determines whether or not this
282 * text component is editable.
283 * <p>
284 * If the flag is set to <code>true</code>, this text component
285 * becomes user editable. If the flag is set to <code>false</code>,
286 * the user cannot change the text of this text component.
287 * By default, non-editable text components have a background color
288 * of SystemColor.control. This default can be overridden by
289 * calling setBackground.
290 *
291 * @param b a flag indicating whether this text component
292 * is user editable.
293 * @see java.awt.TextComponent#isEditable
294 * @since 1.0
295 */
296 public synchronized void setEditable(boolean b) {
297 if (editable == b) {
298 return;
299 }
300
301 editable = b;
302 TextComponentPeer peer = (TextComponentPeer)this.peer;
303 if (peer != null) {
304 peer.setEditable(b);
305 }
344 * Gets the start position of the selected text in
345 * this text component.
346 * @return the start position of the selected text
347 * @see java.awt.TextComponent#setSelectionStart
348 * @see java.awt.TextComponent#getSelectionEnd
349 */
350 public synchronized int getSelectionStart() {
351 TextComponentPeer peer = (TextComponentPeer)this.peer;
352 if (peer != null) {
353 selectionStart = peer.getSelectionStart();
354 }
355 return selectionStart;
356 }
357
358 /**
359 * Sets the selection start for this text component to
360 * the specified position. The new start point is constrained
361 * to be at or before the current selection end. It also
362 * cannot be set to less than zero, the beginning of the
363 * component's text.
364 * If the caller supplies a value for <code>selectionStart</code>
365 * that is out of bounds, the method enforces these constraints
366 * silently, and without failure.
367 * @param selectionStart the start position of the
368 * selected text
369 * @see java.awt.TextComponent#getSelectionStart
370 * @see java.awt.TextComponent#setSelectionEnd
371 * @since 1.1
372 */
373 public synchronized void setSelectionStart(int selectionStart) {
374 /* Route through select method to enforce consistent policy
375 * between selectionStart and selectionEnd.
376 */
377 select(selectionStart, getSelectionEnd());
378 }
379
380 /**
381 * Gets the end position of the selected text in
382 * this text component.
383 * @return the end position of the selected text
384 * @see java.awt.TextComponent#setSelectionEnd
385 * @see java.awt.TextComponent#getSelectionStart
386 */
387 public synchronized int getSelectionEnd() {
388 TextComponentPeer peer = (TextComponentPeer)this.peer;
389 if (peer != null) {
390 selectionEnd = peer.getSelectionEnd();
391 }
392 return selectionEnd;
393 }
394
395 /**
396 * Sets the selection end for this text component to
397 * the specified position. The new end point is constrained
398 * to be at or after the current selection start. It also
399 * cannot be set beyond the end of the component's text.
400 * If the caller supplies a value for <code>selectionEnd</code>
401 * that is out of bounds, the method enforces these constraints
402 * silently, and without failure.
403 * @param selectionEnd the end position of the
404 * selected text
405 * @see java.awt.TextComponent#getSelectionEnd
406 * @see java.awt.TextComponent#setSelectionStart
407 * @since 1.1
408 */
409 public synchronized void setSelectionEnd(int selectionEnd) {
410 /* Route through select method to enforce consistent policy
411 * between selectionStart and selectionEnd.
412 */
413 select(getSelectionStart(), selectionEnd);
414 }
415
416 /**
417 * Selects the text between the specified start and end positions.
418 * <p>
419 * This method sets the start and end positions of the
420 * selected text, enforcing the restriction that the start position
421 * must be greater than or equal to zero. The end position must be
422 * greater than or equal to the start position, and less than or
423 * equal to the length of the text component's text. The
424 * character positions are indexed starting with zero.
425 * The length of the selection is
426 * <code>endPosition</code> - <code>startPosition</code>, so the
427 * character at <code>endPosition</code> is not selected.
428 * If the start and end positions of the selected text are equal,
429 * all text is deselected.
430 * <p>
431 * If the caller supplies values that are inconsistent or out of
432 * bounds, the method enforces these constraints silently, and
433 * without failure. Specifically, if the start position or end
434 * position is greater than the length of the text, it is reset to
435 * equal the text length. If the start position is less than zero,
436 * it is reset to zero, and if the end position is less than the
437 * start position, it is reset to the start position.
438 *
439 * @param selectionStart the zero-based index of the first
440 character (<code>char</code> value) to be selected
441 * @param selectionEnd the zero-based end position of the
442 text to be selected; the character (<code>char</code> value) at
443 <code>selectionEnd</code> is not selected
444 * @see java.awt.TextComponent#setSelectionStart
445 * @see java.awt.TextComponent#setSelectionEnd
446 * @see java.awt.TextComponent#selectAll
447 */
448 public synchronized void select(int selectionStart, int selectionEnd) {
449 String text = getText();
450 if (selectionStart < 0) {
451 selectionStart = 0;
452 }
453 if (selectionStart > text.length()) {
454 selectionStart = text.length();
455 }
456 if (selectionEnd > text.length()) {
457 selectionEnd = text.length();
458 }
459 if (selectionEnd < selectionStart) {
460 selectionEnd = selectionStart;
461 }
462
463 this.selectionStart = selectionStart;
472 /**
473 * Selects all the text in this text component.
474 * @see java.awt.TextComponent#select
475 */
476 public synchronized void selectAll() {
477 this.selectionStart = 0;
478 this.selectionEnd = getText().length();
479
480 TextComponentPeer peer = (TextComponentPeer)this.peer;
481 if (peer != null) {
482 peer.select(selectionStart, selectionEnd);
483 }
484 }
485
486 /**
487 * Sets the position of the text insertion caret.
488 * The caret position is constrained to be between 0
489 * and the last character of the text, inclusive.
490 * If the passed-in value is greater than this range,
491 * the value is set to the last character (or 0 if
492 * the <code>TextComponent</code> contains no text)
493 * and no error is returned. If the passed-in value is
494 * less than 0, an <code>IllegalArgumentException</code>
495 * is thrown.
496 *
497 * @param position the position of the text insertion caret
498 * @exception IllegalArgumentException if <code>position</code>
499 * is less than zero
500 * @since 1.1
501 */
502 public synchronized void setCaretPosition(int position) {
503 if (position < 0) {
504 throw new IllegalArgumentException("position less than zero.");
505 }
506
507 int maxposition = getText().length();
508 if (position > maxposition) {
509 position = maxposition;
510 }
511
512 TextComponentPeer peer = (TextComponentPeer)this.peer;
513 if (peer != null) {
514 peer.setCaretPosition(position);
515 } else {
516 select(position, position);
517 }
518 }
530 */
531 public synchronized int getCaretPosition() {
532 TextComponentPeer peer = (TextComponentPeer)this.peer;
533 int position = 0;
534
535 if (peer != null) {
536 position = peer.getCaretPosition();
537 } else {
538 position = selectionStart;
539 }
540 int maxposition = getText().length();
541 if (position > maxposition) {
542 position = maxposition;
543 }
544 return position;
545 }
546
547 /**
548 * Adds the specified text event listener to receive text events
549 * from this text component.
550 * If <code>l</code> is <code>null</code>, no exception is
551 * thrown and no action is performed.
552 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
553 * >AWT Threading Issues</a> for details on AWT's threading model.
554 *
555 * @param l the text event listener
556 * @see #removeTextListener
557 * @see #getTextListeners
558 * @see java.awt.event.TextListener
559 */
560 public synchronized void addTextListener(TextListener l) {
561 if (l == null) {
562 return;
563 }
564 textListener = AWTEventMulticaster.add(textListener, l);
565 newEventsOnly = true;
566 }
567
568 /**
569 * Removes the specified text event listener so that it no longer
570 * receives text events from this text component
571 * If <code>l</code> is <code>null</code>, no exception is
572 * thrown and no action is performed.
573 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
574 * >AWT Threading Issues</a> for details on AWT's threading model.
575 *
576 * @param l the text listener
577 * @see #addTextListener
578 * @see #getTextListeners
579 * @see java.awt.event.TextListener
580 * @since 1.1
581 */
582 public synchronized void removeTextListener(TextListener l) {
583 if (l == null) {
584 return;
585 }
586 textListener = AWTEventMulticaster.remove(textListener, l);
587 }
588
589 /**
590 * Returns an array of all the text listeners
591 * registered on this text component.
592 *
593 * @return all of this text component's <code>TextListener</code>s
594 * or an empty array if no text
595 * listeners are currently registered
596 *
597 *
598 * @see #addTextListener
599 * @see #removeTextListener
600 * @since 1.4
601 */
602 public synchronized TextListener[] getTextListeners() {
603 return getListeners(TextListener.class);
604 }
605
606 /**
607 * Returns an array of all the objects currently registered
608 * as <code><em>Foo</em>Listener</code>s
609 * upon this <code>TextComponent</code>.
610 * <code><em>Foo</em>Listener</code>s are registered using the
611 * <code>add<em>Foo</em>Listener</code> method.
612 *
613 * <p>
614 * You can specify the <code>listenerType</code> argument
615 * with a class literal, such as
616 * <code><em>Foo</em>Listener.class</code>.
617 * For example, you can query a
618 * <code>TextComponent</code> <code>t</code>
619 * for its text listeners with the following code:
620 *
621 * <pre>TextListener[] tls = (TextListener[])(t.getListeners(TextListener.class));</pre>
622 *
623 * If no such listeners exist, this method returns an empty array.
624 *
625 * @param listenerType the type of listeners requested; this parameter
626 * should specify an interface that descends from
627 * <code>java.util.EventListener</code>
628 * @return an array of all objects registered as
629 * <code><em>Foo</em>Listener</code>s on this text component,
630 * or an empty array if no such
631 * listeners have been added
632 * @exception ClassCastException if <code>listenerType</code>
633 * doesn't specify a class or interface that implements
634 * <code>java.util.EventListener</code>
635 *
636 * @see #getTextListeners
637 * @since 1.3
638 */
639 public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
640 EventListener l = null;
641 if (listenerType == TextListener.class) {
642 l = textListener;
643 } else {
644 return super.getListeners(listenerType);
645 }
646 return AWTEventMulticaster.getListeners(l, listenerType);
647 }
648
649 // REMIND: remove when filtering is done at lower level
650 boolean eventEnabled(AWTEvent e) {
651 if (e.id == TextEvent.TEXT_VALUE_CHANGED) {
652 if ((eventMask & AWTEvent.TEXT_EVENT_MASK) != 0 ||
653 textListener != null) {
654 return true;
655 }
656 return false;
657 }
658 return super.eventEnabled(e);
659 }
660
661 /**
662 * Processes events on this text component. If the event is a
663 * <code>TextEvent</code>, it invokes the <code>processTextEvent</code>
664 * method else it invokes its superclass's <code>processEvent</code>.
665 * <p>Note that if the event parameter is <code>null</code>
666 * the behavior is unspecified and may result in an
667 * exception.
668 *
669 * @param e the event
670 */
671 protected void processEvent(AWTEvent e) {
672 if (e instanceof TextEvent) {
673 processTextEvent((TextEvent)e);
674 return;
675 }
676 super.processEvent(e);
677 }
678
679 /**
680 * Processes text events occurring on this text component by
681 * dispatching them to any registered <code>TextListener</code> objects.
682 * <p>
683 * NOTE: This method will not be called unless text events
684 * are enabled for this component. This happens when one of the
685 * following occurs:
686 * <ul>
687 * <li>A <code>TextListener</code> object is registered
688 * via <code>addTextListener</code>
689 * <li>Text events are enabled via <code>enableEvents</code>
690 * </ul>
691 * <p>Note that if the event parameter is <code>null</code>
692 * the behavior is unspecified and may result in an
693 * exception.
694 *
695 * @param e the text event
696 * @see Component#enableEvents
697 */
698 protected void processTextEvent(TextEvent e) {
699 TextListener listener = textListener;
700 if (listener != null) {
701 int id = e.getID();
702 switch (id) {
703 case TextEvent.TEXT_VALUE_CHANGED:
704 listener.textValueChanged(e);
705 break;
706 }
707 }
708 }
709
710 /**
711 * Returns a string representing the state of this
712 * <code>TextComponent</code>. This
713 * method is intended to be used only for debugging purposes, and the
714 * content and format of the returned string may vary between
715 * implementations. The returned string may be empty but may not be
716 * <code>null</code>.
717 *
718 * @return the parameter string of this text component
719 */
720 protected String paramString() {
721 String str = super.paramString() + ",text=" + getText();
722 if (editable) {
723 str += ",editable";
724 }
725 return str + ",selection=" + getSelectionStart() + "-" + getSelectionEnd();
726 }
727
728 /**
729 * Assigns a valid value to the canAccessClipboard instance variable.
730 */
731 private boolean canAccessClipboard() {
732 SecurityManager sm = System.getSecurityManager();
733 if (sm == null) return true;
734 try {
735 sm.checkPermission(AWTPermissions.ACCESS_CLIPBOARD_PERMISSION);
736 return true;
772 TextComponentPeer peer = (TextComponentPeer)this.peer;
773 if (peer != null) {
774 text = peer.getText();
775 selectionStart = peer.getSelectionStart();
776 selectionEnd = peer.getSelectionEnd();
777 }
778
779 s.defaultWriteObject();
780
781 AWTEventMulticaster.save(s, textListenerK, textListener);
782 s.writeObject(null);
783 }
784
785 /**
786 * Read the ObjectInputStream, and if it isn't null,
787 * add a listener to receive text events fired by the
788 * TextComponent. Unrecognized keys or values will be
789 * ignored.
790 *
791 * @exception HeadlessException if
792 * <code>GraphicsEnvironment.isHeadless()</code> returns
793 * <code>true</code>
794 * @see #removeTextListener
795 * @see #addTextListener
796 * @see java.awt.GraphicsEnvironment#isHeadless
797 */
798 private void readObject(ObjectInputStream s)
799 throws ClassNotFoundException, IOException, HeadlessException
800 {
801 GraphicsEnvironment.checkHeadless();
802 s.defaultReadObject();
803
804 // Make sure the state we just read in for text,
805 // selectionStart and selectionEnd has legal values
806 this.text = (text != null) ? text : "";
807 select(selectionStart, selectionEnd);
808
809 Object keyOrNull;
810 while(null != (keyOrNull = s.readObject())) {
811 String key = ((String)keyOrNull).intern();
812
813 if (textListenerK == key) {
827
828 /**
829 * Gets the AccessibleContext associated with this TextComponent.
830 * For text components, the AccessibleContext takes the form of an
831 * AccessibleAWTTextComponent.
832 * A new AccessibleAWTTextComponent instance is created if necessary.
833 *
834 * @return an AccessibleAWTTextComponent that serves as the
835 * AccessibleContext of this TextComponent
836 * @since 1.3
837 */
838 public AccessibleContext getAccessibleContext() {
839 if (accessibleContext == null) {
840 accessibleContext = new AccessibleAWTTextComponent();
841 }
842 return accessibleContext;
843 }
844
845 /**
846 * This class implements accessibility support for the
847 * <code>TextComponent</code> class. It provides an implementation of the
848 * Java Accessibility API appropriate to text component user-interface
849 * elements.
850 * @since 1.3
851 */
852 protected class AccessibleAWTTextComponent extends AccessibleAWTComponent
853 implements AccessibleText, TextListener
854 {
855 /*
856 * JDK 1.3 serialVersionUID
857 */
858 private static final long serialVersionUID = 3631432373506317811L;
859
860 /**
861 * Constructs an AccessibleAWTTextComponent. Adds a listener to track
862 * caret change.
863 */
864 public AccessibleAWTTextComponent() {
865 TextComponent.this.addTextListener(this);
866 }
867
|
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 */
133 TextComponent(String text) throws HeadlessException {
134 GraphicsEnvironment.checkHeadless();
135 this.text = (text != null) ? text : "";
136 setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
137 }
138
139 private void enableInputMethodsIfNecessary() {
140 if (checkForEnableIM) {
141 checkForEnableIM = false;
142 try {
143 Toolkit toolkit = Toolkit.getDefaultToolkit();
144 boolean shouldEnable = false;
145 if (toolkit instanceof InputMethodSupport) {
146 shouldEnable = ((InputMethodSupport)toolkit)
147 .enableInputMethodsForTextComponent();
148 }
186 TextComponentPeer peer = (TextComponentPeer)this.peer;
187 if (peer != null) return peer.getInputMethodRequests();
188 else return null;
189 }
190
191
192
193 /**
194 * Makes this Component displayable by connecting it to a
195 * native screen resource.
196 * This method is called internally by the toolkit and should
197 * not be called directly by programs.
198 * @see java.awt.TextComponent#removeNotify
199 */
200 public void addNotify() {
201 super.addNotify();
202 enableInputMethodsIfNecessary();
203 }
204
205 /**
206 * Removes the {@code TextComponent}'s peer.
207 * The peer allows us to modify the appearance of the
208 * {@code TextComponent} without changing its
209 * functionality.
210 */
211 public void removeNotify() {
212 synchronized (getTreeLock()) {
213 TextComponentPeer peer = (TextComponentPeer)this.peer;
214 if (peer != null) {
215 text = peer.getText();
216 selectionStart = peer.getSelectionStart();
217 selectionEnd = peer.getSelectionEnd();
218 }
219 super.removeNotify();
220 }
221 }
222
223 /**
224 * Sets the text that is presented by this
225 * text component to be the specified text.
226 * @param t the new text;
227 * if this parameter is {@code null} then
228 * the text is set to the empty string ""
229 * @see java.awt.TextComponent#getText
230 */
231 public synchronized void setText(String t) {
232 boolean skipTextEvent = (text == null || text.isEmpty())
233 && (t == null || t.isEmpty());
234 text = (t != null) ? t : "";
235 TextComponentPeer peer = (TextComponentPeer)this.peer;
236 // Please note that we do not want to post an event
237 // if TextArea.setText() or TextField.setText() replaces an empty text
238 // by an empty text, that is, if component's text remains unchanged.
239 if (peer != null && !skipTextEvent) {
240 peer.setText(text);
241 }
242 }
243
244 /**
245 * Returns the text that is presented by this text component.
246 * By default, this is an empty string.
247 *
248 * @return the value of this {@code TextComponent}
249 * @see java.awt.TextComponent#setText
250 */
251 public synchronized String getText() {
252 TextComponentPeer peer = (TextComponentPeer)this.peer;
253 if (peer != null) {
254 text = peer.getText();
255 }
256 return text;
257 }
258
259 /**
260 * Returns the selected text from the text that is
261 * presented by this text component.
262 * @return the selected text of this text component
263 * @see java.awt.TextComponent#select
264 */
265 public synchronized String getSelectedText() {
266 return getText().substring(getSelectionStart(), getSelectionEnd());
267 }
268
269 /**
270 * Indicates whether or not this text component is editable.
271 * @return {@code true} if this text component is
272 * editable; {@code false} otherwise.
273 * @see java.awt.TextComponent#setEditable
274 * @since 1.0
275 */
276 public boolean isEditable() {
277 return editable;
278 }
279
280 /**
281 * Sets the flag that determines whether or not this
282 * text component is editable.
283 * <p>
284 * If the flag is set to {@code true}, this text component
285 * becomes user editable. If the flag is set to {@code false},
286 * the user cannot change the text of this text component.
287 * By default, non-editable text components have a background color
288 * of SystemColor.control. This default can be overridden by
289 * calling setBackground.
290 *
291 * @param b a flag indicating whether this text component
292 * is user editable.
293 * @see java.awt.TextComponent#isEditable
294 * @since 1.0
295 */
296 public synchronized void setEditable(boolean b) {
297 if (editable == b) {
298 return;
299 }
300
301 editable = b;
302 TextComponentPeer peer = (TextComponentPeer)this.peer;
303 if (peer != null) {
304 peer.setEditable(b);
305 }
344 * Gets the start position of the selected text in
345 * this text component.
346 * @return the start position of the selected text
347 * @see java.awt.TextComponent#setSelectionStart
348 * @see java.awt.TextComponent#getSelectionEnd
349 */
350 public synchronized int getSelectionStart() {
351 TextComponentPeer peer = (TextComponentPeer)this.peer;
352 if (peer != null) {
353 selectionStart = peer.getSelectionStart();
354 }
355 return selectionStart;
356 }
357
358 /**
359 * Sets the selection start for this text component to
360 * the specified position. The new start point is constrained
361 * to be at or before the current selection end. It also
362 * cannot be set to less than zero, the beginning of the
363 * component's text.
364 * If the caller supplies a value for {@code selectionStart}
365 * that is out of bounds, the method enforces these constraints
366 * silently, and without failure.
367 * @param selectionStart the start position of the
368 * selected text
369 * @see java.awt.TextComponent#getSelectionStart
370 * @see java.awt.TextComponent#setSelectionEnd
371 * @since 1.1
372 */
373 public synchronized void setSelectionStart(int selectionStart) {
374 /* Route through select method to enforce consistent policy
375 * between selectionStart and selectionEnd.
376 */
377 select(selectionStart, getSelectionEnd());
378 }
379
380 /**
381 * Gets the end position of the selected text in
382 * this text component.
383 * @return the end position of the selected text
384 * @see java.awt.TextComponent#setSelectionEnd
385 * @see java.awt.TextComponent#getSelectionStart
386 */
387 public synchronized int getSelectionEnd() {
388 TextComponentPeer peer = (TextComponentPeer)this.peer;
389 if (peer != null) {
390 selectionEnd = peer.getSelectionEnd();
391 }
392 return selectionEnd;
393 }
394
395 /**
396 * Sets the selection end for this text component to
397 * the specified position. The new end point is constrained
398 * to be at or after the current selection start. It also
399 * cannot be set beyond the end of the component's text.
400 * If the caller supplies a value for {@code selectionEnd}
401 * that is out of bounds, the method enforces these constraints
402 * silently, and without failure.
403 * @param selectionEnd the end position of the
404 * selected text
405 * @see java.awt.TextComponent#getSelectionEnd
406 * @see java.awt.TextComponent#setSelectionStart
407 * @since 1.1
408 */
409 public synchronized void setSelectionEnd(int selectionEnd) {
410 /* Route through select method to enforce consistent policy
411 * between selectionStart and selectionEnd.
412 */
413 select(getSelectionStart(), selectionEnd);
414 }
415
416 /**
417 * Selects the text between the specified start and end positions.
418 * <p>
419 * This method sets the start and end positions of the
420 * selected text, enforcing the restriction that the start position
421 * must be greater than or equal to zero. The end position must be
422 * greater than or equal to the start position, and less than or
423 * equal to the length of the text component's text. The
424 * character positions are indexed starting with zero.
425 * The length of the selection is
426 * {@code endPosition} - {@code startPosition}, so the
427 * character at {@code endPosition} is not selected.
428 * If the start and end positions of the selected text are equal,
429 * all text is deselected.
430 * <p>
431 * If the caller supplies values that are inconsistent or out of
432 * bounds, the method enforces these constraints silently, and
433 * without failure. Specifically, if the start position or end
434 * position is greater than the length of the text, it is reset to
435 * equal the text length. If the start position is less than zero,
436 * it is reset to zero, and if the end position is less than the
437 * start position, it is reset to the start position.
438 *
439 * @param selectionStart the zero-based index of the first
440 * character ({@code char} value) to be selected
441 * @param selectionEnd the zero-based end position of the
442 * text to be selected; the character ({@code char} value) at
443 * {@code selectionEnd} is not selected
444 * @see java.awt.TextComponent#setSelectionStart
445 * @see java.awt.TextComponent#setSelectionEnd
446 * @see java.awt.TextComponent#selectAll
447 */
448 public synchronized void select(int selectionStart, int selectionEnd) {
449 String text = getText();
450 if (selectionStart < 0) {
451 selectionStart = 0;
452 }
453 if (selectionStart > text.length()) {
454 selectionStart = text.length();
455 }
456 if (selectionEnd > text.length()) {
457 selectionEnd = text.length();
458 }
459 if (selectionEnd < selectionStart) {
460 selectionEnd = selectionStart;
461 }
462
463 this.selectionStart = selectionStart;
472 /**
473 * Selects all the text in this text component.
474 * @see java.awt.TextComponent#select
475 */
476 public synchronized void selectAll() {
477 this.selectionStart = 0;
478 this.selectionEnd = getText().length();
479
480 TextComponentPeer peer = (TextComponentPeer)this.peer;
481 if (peer != null) {
482 peer.select(selectionStart, selectionEnd);
483 }
484 }
485
486 /**
487 * Sets the position of the text insertion caret.
488 * The caret position is constrained to be between 0
489 * and the last character of the text, inclusive.
490 * If the passed-in value is greater than this range,
491 * the value is set to the last character (or 0 if
492 * the {@code TextComponent} contains no text)
493 * and no error is returned. If the passed-in value is
494 * less than 0, an {@code IllegalArgumentException}
495 * is thrown.
496 *
497 * @param position the position of the text insertion caret
498 * @exception IllegalArgumentException if {@code position}
499 * is less than zero
500 * @since 1.1
501 */
502 public synchronized void setCaretPosition(int position) {
503 if (position < 0) {
504 throw new IllegalArgumentException("position less than zero.");
505 }
506
507 int maxposition = getText().length();
508 if (position > maxposition) {
509 position = maxposition;
510 }
511
512 TextComponentPeer peer = (TextComponentPeer)this.peer;
513 if (peer != null) {
514 peer.setCaretPosition(position);
515 } else {
516 select(position, position);
517 }
518 }
530 */
531 public synchronized int getCaretPosition() {
532 TextComponentPeer peer = (TextComponentPeer)this.peer;
533 int position = 0;
534
535 if (peer != null) {
536 position = peer.getCaretPosition();
537 } else {
538 position = selectionStart;
539 }
540 int maxposition = getText().length();
541 if (position > maxposition) {
542 position = maxposition;
543 }
544 return position;
545 }
546
547 /**
548 * Adds the specified text event listener to receive text events
549 * from this text component.
550 * If {@code l} is {@code null}, no exception is
551 * thrown and no action is performed.
552 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
553 * >AWT Threading Issues</a> for details on AWT's threading model.
554 *
555 * @param l the text event listener
556 * @see #removeTextListener
557 * @see #getTextListeners
558 * @see java.awt.event.TextListener
559 */
560 public synchronized void addTextListener(TextListener l) {
561 if (l == null) {
562 return;
563 }
564 textListener = AWTEventMulticaster.add(textListener, l);
565 newEventsOnly = true;
566 }
567
568 /**
569 * Removes the specified text event listener so that it no longer
570 * receives text events from this text component
571 * If {@code l} is {@code null}, no exception is
572 * thrown and no action is performed.
573 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
574 * >AWT Threading Issues</a> for details on AWT's threading model.
575 *
576 * @param l the text listener
577 * @see #addTextListener
578 * @see #getTextListeners
579 * @see java.awt.event.TextListener
580 * @since 1.1
581 */
582 public synchronized void removeTextListener(TextListener l) {
583 if (l == null) {
584 return;
585 }
586 textListener = AWTEventMulticaster.remove(textListener, l);
587 }
588
589 /**
590 * Returns an array of all the text listeners
591 * registered on this text component.
592 *
593 * @return all of this text component's {@code TextListener}s
594 * or an empty array if no text
595 * listeners are currently registered
596 *
597 *
598 * @see #addTextListener
599 * @see #removeTextListener
600 * @since 1.4
601 */
602 public synchronized TextListener[] getTextListeners() {
603 return getListeners(TextListener.class);
604 }
605
606 /**
607 * Returns an array of all the objects currently registered
608 * as <code><em>Foo</em>Listener</code>s
609 * upon this {@code TextComponent}.
610 * <code><em>Foo</em>Listener</code>s are registered using the
611 * <code>add<em>Foo</em>Listener</code> method.
612 *
613 * <p>
614 * You can specify the {@code listenerType} argument
615 * with a class literal, such as
616 * <code><em>Foo</em>Listener.class</code>.
617 * For example, you can query a
618 * {@code TextComponent t}
619 * for its text listeners with the following code:
620 *
621 * <pre>TextListener[] tls = (TextListener[])(t.getListeners(TextListener.class));</pre>
622 *
623 * If no such listeners exist, this method returns an empty array.
624 *
625 * @param listenerType the type of listeners requested; this parameter
626 * should specify an interface that descends from
627 * {@code java.util.EventListener}
628 * @return an array of all objects registered as
629 * <code><em>Foo</em>Listener</code>s on this text component,
630 * or an empty array if no such
631 * listeners have been added
632 * @exception ClassCastException if {@code listenerType}
633 * doesn't specify a class or interface that implements
634 * {@code java.util.EventListener}
635 *
636 * @see #getTextListeners
637 * @since 1.3
638 */
639 public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
640 EventListener l = null;
641 if (listenerType == TextListener.class) {
642 l = textListener;
643 } else {
644 return super.getListeners(listenerType);
645 }
646 return AWTEventMulticaster.getListeners(l, listenerType);
647 }
648
649 // REMIND: remove when filtering is done at lower level
650 boolean eventEnabled(AWTEvent e) {
651 if (e.id == TextEvent.TEXT_VALUE_CHANGED) {
652 if ((eventMask & AWTEvent.TEXT_EVENT_MASK) != 0 ||
653 textListener != null) {
654 return true;
655 }
656 return false;
657 }
658 return super.eventEnabled(e);
659 }
660
661 /**
662 * Processes events on this text component. If the event is a
663 * {@code TextEvent}, it invokes the {@code processTextEvent}
664 * method else it invokes its superclass's {@code processEvent}.
665 * <p>Note that if the event parameter is {@code null}
666 * the behavior is unspecified and may result in an
667 * exception.
668 *
669 * @param e the event
670 */
671 protected void processEvent(AWTEvent e) {
672 if (e instanceof TextEvent) {
673 processTextEvent((TextEvent)e);
674 return;
675 }
676 super.processEvent(e);
677 }
678
679 /**
680 * Processes text events occurring on this text component by
681 * dispatching them to any registered {@code TextListener} objects.
682 * <p>
683 * NOTE: This method will not be called unless text events
684 * are enabled for this component. This happens when one of the
685 * following occurs:
686 * <ul>
687 * <li>A {@code TextListener} object is registered
688 * via {@code addTextListener}
689 * <li>Text events are enabled via {@code enableEvents}
690 * </ul>
691 * <p>Note that if the event parameter is {@code null}
692 * the behavior is unspecified and may result in an
693 * exception.
694 *
695 * @param e the text event
696 * @see Component#enableEvents
697 */
698 protected void processTextEvent(TextEvent e) {
699 TextListener listener = textListener;
700 if (listener != null) {
701 int id = e.getID();
702 switch (id) {
703 case TextEvent.TEXT_VALUE_CHANGED:
704 listener.textValueChanged(e);
705 break;
706 }
707 }
708 }
709
710 /**
711 * Returns a string representing the state of this
712 * {@code TextComponent}. This
713 * method is intended to be used only for debugging purposes, and the
714 * content and format of the returned string may vary between
715 * implementations. The returned string may be empty but may not be
716 * {@code null}.
717 *
718 * @return the parameter string of this text component
719 */
720 protected String paramString() {
721 String str = super.paramString() + ",text=" + getText();
722 if (editable) {
723 str += ",editable";
724 }
725 return str + ",selection=" + getSelectionStart() + "-" + getSelectionEnd();
726 }
727
728 /**
729 * Assigns a valid value to the canAccessClipboard instance variable.
730 */
731 private boolean canAccessClipboard() {
732 SecurityManager sm = System.getSecurityManager();
733 if (sm == null) return true;
734 try {
735 sm.checkPermission(AWTPermissions.ACCESS_CLIPBOARD_PERMISSION);
736 return true;
772 TextComponentPeer peer = (TextComponentPeer)this.peer;
773 if (peer != null) {
774 text = peer.getText();
775 selectionStart = peer.getSelectionStart();
776 selectionEnd = peer.getSelectionEnd();
777 }
778
779 s.defaultWriteObject();
780
781 AWTEventMulticaster.save(s, textListenerK, textListener);
782 s.writeObject(null);
783 }
784
785 /**
786 * Read the ObjectInputStream, and if it isn't null,
787 * add a listener to receive text events fired by the
788 * TextComponent. Unrecognized keys or values will be
789 * ignored.
790 *
791 * @exception HeadlessException if
792 * {@code GraphicsEnvironment.isHeadless()} returns
793 * {@code true}
794 * @see #removeTextListener
795 * @see #addTextListener
796 * @see java.awt.GraphicsEnvironment#isHeadless
797 */
798 private void readObject(ObjectInputStream s)
799 throws ClassNotFoundException, IOException, HeadlessException
800 {
801 GraphicsEnvironment.checkHeadless();
802 s.defaultReadObject();
803
804 // Make sure the state we just read in for text,
805 // selectionStart and selectionEnd has legal values
806 this.text = (text != null) ? text : "";
807 select(selectionStart, selectionEnd);
808
809 Object keyOrNull;
810 while(null != (keyOrNull = s.readObject())) {
811 String key = ((String)keyOrNull).intern();
812
813 if (textListenerK == key) {
827
828 /**
829 * Gets the AccessibleContext associated with this TextComponent.
830 * For text components, the AccessibleContext takes the form of an
831 * AccessibleAWTTextComponent.
832 * A new AccessibleAWTTextComponent instance is created if necessary.
833 *
834 * @return an AccessibleAWTTextComponent that serves as the
835 * AccessibleContext of this TextComponent
836 * @since 1.3
837 */
838 public AccessibleContext getAccessibleContext() {
839 if (accessibleContext == null) {
840 accessibleContext = new AccessibleAWTTextComponent();
841 }
842 return accessibleContext;
843 }
844
845 /**
846 * This class implements accessibility support for the
847 * {@code TextComponent} class. It provides an implementation of the
848 * Java Accessibility API appropriate to text component user-interface
849 * elements.
850 * @since 1.3
851 */
852 protected class AccessibleAWTTextComponent extends AccessibleAWTComponent
853 implements AccessibleText, TextListener
854 {
855 /*
856 * JDK 1.3 serialVersionUID
857 */
858 private static final long serialVersionUID = 3631432373506317811L;
859
860 /**
861 * Constructs an AccessibleAWTTextComponent. Adds a listener to track
862 * caret change.
863 */
864 public AccessibleAWTTextComponent() {
865 TextComponent.this.addTextListener(this);
866 }
867
|