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