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