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