1. /*
  2. * @(#)TextArea.java 1.75 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.event.InputEvent;
  9. import java.awt.event.KeyEvent;
  10. import java.awt.peer.TextAreaPeer;
  11. import java.io.ObjectOutputStream;
  12. import java.io.ObjectInputStream;
  13. import java.io.IOException;
  14. import java.util.Set;
  15. import java.util.TreeSet;
  16. import javax.accessibility.*;
  17. /**
  18. * A <code>TextArea</code> object is a multi-line region
  19. * that displays text. It can be set to allow editing or
  20. * to be read-only.
  21. * <p>
  22. * The following image shows the appearance of a text area:
  23. * <p>
  24. * <img src="doc-files/TextArea-1.gif" alt="A TextArea showing the word 'Hello!'"
  25. * ALIGN=center HSPACE=10 VSPACE=7>
  26. * <p>
  27. * This text area could be created by the following line of code:
  28. * <p>
  29. * <hr><blockquote><pre>
  30. * new TextArea("Hello", 5, 40);
  31. * </pre></blockquote><hr>
  32. * <p>
  33. * @version 1.75, 01/23/03
  34. * @author Sami Shaio
  35. * @since JDK1.0
  36. */
  37. public class TextArea extends TextComponent {
  38. /**
  39. * The number of rows in the <code>TextArea</code>.
  40. * This parameter will determine the text area's height.
  41. * Guaranteed to be non-negative.
  42. *
  43. * @serial
  44. * @see #getRows()
  45. * @see #setRows(int)
  46. */
  47. int rows;
  48. /**
  49. * The number of columns in the <code>TextArea</code>.
  50. * A column is an approximate average character
  51. * width that is platform-dependent.
  52. * This parameter will determine the text area's width.
  53. * Guaranteed to be non-negative.
  54. *
  55. * @serial
  56. * @see #setColumns(int)
  57. * @see #getColumns()
  58. */
  59. int columns;
  60. private static final String base = "text";
  61. private static int nameCounter = 0;
  62. /**
  63. * Create and display both vertical and horizontal scrollbars.
  64. * @since JDK1.1
  65. */
  66. public static final int SCROLLBARS_BOTH = 0;
  67. /**
  68. * Create and display vertical scrollbar only.
  69. * @since JDK1.1
  70. */
  71. public static final int SCROLLBARS_VERTICAL_ONLY = 1;
  72. /**
  73. * Create and display horizontal scrollbar only.
  74. * @since JDK1.1
  75. */
  76. public static final int SCROLLBARS_HORIZONTAL_ONLY = 2;
  77. /**
  78. * Do not create or display any scrollbars for the text area.
  79. * @since JDK1.1
  80. */
  81. public static final int SCROLLBARS_NONE = 3;
  82. /**
  83. * Determines which scrollbars are created for the
  84. * text area. It can be one of four values :
  85. * <code>SCROLLBARS_BOTH</code> = both scrollbars.<BR>
  86. * <code>SCROLLBARS_HORIZONTAL_ONLY</code> = Horizontal bar only.<BR>
  87. * <code>SCROLLBARS_VERTICAL_ONLY</code> = Vertical bar only.<BR>
  88. * <code>SCROLLBARS_NONE</code> = No scrollbars.<BR>
  89. *
  90. * @serial
  91. * @see #getScrollbarVisibility()
  92. */
  93. private int scrollbarVisibility;
  94. /**
  95. * Cache the Sets of forward and backward traversal keys so we need not
  96. * look them up each time.
  97. */
  98. private static Set forwardTraversalKeys, backwardTraversalKeys;
  99. /*
  100. * JDK 1.1 serialVersionUID
  101. */
  102. private static final long serialVersionUID = 3692302836626095722L;
  103. /**
  104. * Initialize JNI field and method ids
  105. */
  106. private static native void initIDs();
  107. static {
  108. /* ensure that the necessary native libraries are loaded */
  109. Toolkit.loadLibraries();
  110. if (!GraphicsEnvironment.isHeadless()) {
  111. initIDs();
  112. }
  113. forwardTraversalKeys = KeyboardFocusManager.initFocusTraversalKeysSet(
  114. "ctrl TAB",
  115. new TreeSet());
  116. backwardTraversalKeys = KeyboardFocusManager.initFocusTraversalKeysSet(
  117. "ctrl shift TAB",
  118. new TreeSet());
  119. }
  120. /**
  121. * Constructs a new text area with the empty string as text.
  122. * This text area is created with scrollbar visibility equal to
  123. * {@link #SCROLLBARS_BOTH}, so both vertical and horizontal
  124. * scrollbars will be visible for this text area.
  125. * @exception HeadlessException if
  126. * <code>GraphicsEnvironment.isHeadless</code> returns true
  127. * @see java.awt.GraphicsEnvironment#isHeadless()
  128. */
  129. public TextArea() throws HeadlessException {
  130. this("", 0, 0, SCROLLBARS_BOTH);
  131. }
  132. /**
  133. * Constructs a new text area with the specified text.
  134. * This text area is created with scrollbar visibility equal to
  135. * {@link #SCROLLBARS_BOTH}, so both vertical and horizontal
  136. * scrollbars will be visible for this text area.
  137. * @param text the text to be displayed; if
  138. * <code>text</code> is <code>null</code>, the empty
  139. * string <code>""</code> will be displayed
  140. * @exception HeadlessException if
  141. * <code>GraphicsEnvironment.isHeadless</code> returns true
  142. * @see java.awt.GraphicsEnvironment#isHeadless()
  143. */
  144. public TextArea(String text) throws HeadlessException {
  145. this(text, 0, 0, SCROLLBARS_BOTH);
  146. }
  147. /**
  148. * Constructs a new text area with the specified number of
  149. * rows and columns and the empty string as text.
  150. * A column is an approximate average character
  151. * width that is platform-dependent. The text area is created with
  152. * scrollbar visibility equal to {@link #SCROLLBARS_BOTH}, so both
  153. * vertical and horizontal scrollbars will be visible for this
  154. * text area.
  155. * @param rows the number of rows
  156. * @param columns the number of columns
  157. * @exception HeadlessException if
  158. * <code>GraphicsEnvironment.isHeadless</code> returns true
  159. * @see java.awt.GraphicsEnvironment#isHeadless()
  160. */
  161. public TextArea(int rows, int columns) throws HeadlessException {
  162. this("", rows, columns, SCROLLBARS_BOTH);
  163. }
  164. /**
  165. * Constructs a new text area with the specified text,
  166. * and with the specified number of rows and columns.
  167. * A column is an approximate average character
  168. * width that is platform-dependent. The text area is created with
  169. * scrollbar visibility equal to {@link #SCROLLBARS_BOTH}, so both
  170. * vertical and horizontal scrollbars will be visible for this
  171. * text area.
  172. * @param text the text to be displayed; if
  173. * <code>text</code> is <code>null</code>, the empty
  174. * string <code>""</code> will be displayed
  175. * @param rows the number of rows
  176. * @param columns the number of columns
  177. * @exception HeadlessException if
  178. * <code>GraphicsEnvironment.isHeadless</code> returns true
  179. * @see java.awt.GraphicsEnvironment#isHeadless()
  180. */
  181. public TextArea(String text, int rows, int columns)
  182. throws HeadlessException {
  183. this(text, rows, columns, SCROLLBARS_BOTH);
  184. }
  185. /**
  186. * Constructs a new text area with the specified text,
  187. * and with the rows, columns, and scroll bar visibility
  188. * as specified. All <code>TextArea</code> constructors defer to
  189. * this one.
  190. * <p>
  191. * The <code>TextArea</code> class defines several constants
  192. * that can be supplied as values for the
  193. * <code>scrollbars</code> argument:
  194. * <ul>
  195. * <li><code>SCROLLBARS_BOTH</code>,
  196. * <li><code>SCROLLBARS_VERTICAL_ONLY</code>,
  197. * <li><code>SCROLLBARS_HORIZONTAL_ONLY</code>,
  198. * <li><code>SCROLLBARS_NONE</code>.
  199. * </ul>
  200. * Any other value for the
  201. * <code>scrollbars</code> argument is invalid and will result in
  202. * this text area being created with scrollbar visibility equal to
  203. * the default value of {@link #SCROLLBARS_BOTH}.
  204. * @param text the text to be displayed; if
  205. * <code>text</code> is <code>null</code>, the empty
  206. * string <code>""</code> will be displayed
  207. * @param rows the number of rows; if
  208. * <code>rows</code> is less than <code>0</code>,
  209. * <code>rows</code> is set to <code>0</code>
  210. * @param columns the number of columns; if
  211. * <code>columns</code> is less than <code>0</code>,
  212. * <code>columns</code> is set to <code>0</code>
  213. * @param scrollbars a constant that determines what
  214. * scrollbars are created to view the text area
  215. * @since JDK1.1
  216. * @exception HeadlessException if
  217. * <code>GraphicsEnvironment.isHeadless</code> returns true
  218. * @see java.awt.GraphicsEnvironment#isHeadless()
  219. */
  220. public TextArea(String text, int rows, int columns, int scrollbars)
  221. throws HeadlessException {
  222. super(text);
  223. this.rows = (rows >= 0) ? rows : 0;
  224. this.columns = (columns >= 0) ? columns : 0;
  225. if (scrollbars >= SCROLLBARS_BOTH && scrollbars <= SCROLLBARS_NONE) {
  226. this.scrollbarVisibility = scrollbars;
  227. } else {
  228. this.scrollbarVisibility = SCROLLBARS_BOTH;
  229. }
  230. setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
  231. forwardTraversalKeys);
  232. setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
  233. backwardTraversalKeys);
  234. }
  235. /**
  236. * Construct a name for this component. Called by <code>getName</code>
  237. * when the name is <code>null</code>.
  238. */
  239. String constructComponentName() {
  240. synchronized (getClass()) {
  241. return base + nameCounter++;
  242. }
  243. }
  244. /**
  245. * Creates the <code>TextArea</code>'s peer. The peer allows us to modify
  246. * the appearance of the <code>TextArea</code> without changing any of its
  247. * functionality.
  248. */
  249. public void addNotify() {
  250. synchronized (getTreeLock()) {
  251. if (peer == null)
  252. peer = getToolkit().createTextArea(this);
  253. super.addNotify();
  254. }
  255. }
  256. /**
  257. * Inserts the specified text at the specified position
  258. * in this text area.
  259. * <p>Note that passing <code>null</code> or inconsistent
  260. * parameters is invalid and will result in unspecified
  261. * behavior.
  262. *
  263. * @param str the non-<code>null</code> text to insert
  264. * @param pos the position at which to insert
  265. * @see java.awt.TextComponent#setText
  266. * @see java.awt.TextArea#replaceRange
  267. * @see java.awt.TextArea#append
  268. * @since JDK1.1
  269. */
  270. public void insert(String str, int pos) {
  271. insertText(str, pos);
  272. }
  273. /**
  274. * @deprecated As of JDK version 1.1,
  275. * replaced by <code>insert(String, int)</code>.
  276. */
  277. public synchronized void insertText(String str, int pos) {
  278. TextAreaPeer peer = (TextAreaPeer)this.peer;
  279. if (peer != null) {
  280. peer.insertText(str, pos);
  281. } else {
  282. text = text.substring(0, pos) + str + text.substring(pos);
  283. }
  284. }
  285. /**
  286. * Appends the given text to the text area's current text.
  287. * <p>Note that passing <code>null</code> or inconsistent
  288. * parameters is invalid and will result in unspecified
  289. * behavior.
  290. *
  291. * @param str the non-<code>null</code> text to append
  292. * @see java.awt.TextArea#insert
  293. * @since JDK1.1
  294. */
  295. public void append(String str) {
  296. appendText(str);
  297. }
  298. /**
  299. * @deprecated As of JDK version 1.1,
  300. * replaced by <code>append(String)</code>.
  301. */
  302. public synchronized void appendText(String str) {
  303. if (peer != null) {
  304. insertText(str, getText().length());
  305. } else {
  306. text = text + str;
  307. }
  308. }
  309. /**
  310. * Replaces text between the indicated start and end positions
  311. * with the specified replacement text. The text at the end
  312. * position will not be replaced. The text at the start
  313. * position will be replaced (unless the start position is the
  314. * same as the end position).
  315. * The text position is zero-based. The inserted substring may be
  316. * of a different length than the text it replaces.
  317. * <p>Note that passing <code>null</code> or inconsistent
  318. * parameters is invalid and will result in unspecified
  319. * behavior.
  320. *
  321. * @param str the non-<code>null</code> text to use as
  322. * the replacement
  323. * @param start the start position
  324. * @param end the end position
  325. * @see java.awt.TextArea#insert
  326. * @since JDK1.1
  327. */
  328. public void replaceRange(String str, int start, int end) {
  329. replaceText(str, start, end);
  330. }
  331. /**
  332. * @deprecated As of JDK version 1.1,
  333. * replaced by <code>replaceRange(String, int, int)</code>.
  334. */
  335. public synchronized void replaceText(String str, int start, int end) {
  336. TextAreaPeer peer = (TextAreaPeer)this.peer;
  337. if (peer != null) {
  338. peer.replaceText(str, start, end);
  339. } else {
  340. text = text.substring(0, start) + str + text.substring(end);
  341. }
  342. }
  343. /**
  344. * Returns the number of rows in the text area.
  345. * @return the number of rows in the text area
  346. * @see #setRows(int)
  347. * @see #getColumns()
  348. * @since JDK1
  349. */
  350. public int getRows() {
  351. return rows;
  352. }
  353. /**
  354. * Sets the number of rows for this text area.
  355. * @param rows the number of rows
  356. * @see #getRows()
  357. * @see #setColumns(int)
  358. * @exception IllegalArgumentException if the value
  359. * supplied for <code>rows</code>
  360. * is less than <code>0</code>
  361. * @since JDK1.1
  362. */
  363. public void setRows(int rows) {
  364. int oldVal = this.rows;
  365. if (rows < 0) {
  366. throw new IllegalArgumentException("rows less than zero.");
  367. }
  368. if (rows != oldVal) {
  369. this.rows = rows;
  370. invalidate();
  371. }
  372. }
  373. /**
  374. * Returns the number of columns in this text area.
  375. * @return the number of columns in the text area
  376. * @see #setColumns(int)
  377. * @see #getRows()
  378. */
  379. public int getColumns() {
  380. return columns;
  381. }
  382. /**
  383. * Sets the number of columns for this text area.
  384. * @param columns the number of columns
  385. * @see #getColumns()
  386. * @see #setRows(int)
  387. * @exception IllegalArgumentException if the value
  388. * supplied for <code>columns</code>
  389. * is less than <code>0</code>
  390. * @since JDK1.1
  391. */
  392. public void setColumns(int columns) {
  393. int oldVal = this.columns;
  394. if (columns < 0) {
  395. throw new IllegalArgumentException("columns less than zero.");
  396. }
  397. if (columns != oldVal) {
  398. this.columns = columns;
  399. invalidate();
  400. }
  401. }
  402. /**
  403. * Returns an enumerated value that indicates which scroll bars
  404. * the text area uses.
  405. * <p>
  406. * The <code>TextArea</code> class defines four integer constants
  407. * that are used to specify which scroll bars are available.
  408. * <code>TextArea</code> has one constructor that gives the
  409. * application discretion over scroll bars.
  410. *
  411. * @return an integer that indicates which scroll bars are used
  412. * @see java.awt.TextArea#SCROLLBARS_BOTH
  413. * @see java.awt.TextArea#SCROLLBARS_VERTICAL_ONLY
  414. * @see java.awt.TextArea#SCROLLBARS_HORIZONTAL_ONLY
  415. * @see java.awt.TextArea#SCROLLBARS_NONE
  416. * @see java.awt.TextArea#TextArea(java.lang.String, int, int, int)
  417. * @since JDK1.1
  418. */
  419. public int getScrollbarVisibility() {
  420. return scrollbarVisibility;
  421. }
  422. /**
  423. * Determines the preferred size of a text area with the specified
  424. * number of rows and columns.
  425. * @param rows the number of rows
  426. * @param columns the number of columns
  427. * @return the preferred dimensions required to display
  428. * the text area with the specified
  429. * number of rows and columns
  430. * @see java.awt.Component#getPreferredSize
  431. * @since JDK1.1
  432. */
  433. public Dimension getPreferredSize(int rows, int columns) {
  434. return preferredSize(rows, columns);
  435. }
  436. /**
  437. * @deprecated As of JDK version 1.1,
  438. * replaced by <code>getPreferredSize(int, int)</code>.
  439. */
  440. public Dimension preferredSize(int rows, int columns) {
  441. synchronized (getTreeLock()) {
  442. TextAreaPeer peer = (TextAreaPeer)this.peer;
  443. return (peer != null) ?
  444. peer.preferredSize(rows, columns) :
  445. super.preferredSize();
  446. }
  447. }
  448. /**
  449. * Determines the preferred size of this text area.
  450. * @return the preferred dimensions needed for this text area
  451. * @see java.awt.Component#getPreferredSize
  452. * @since JDK1.1
  453. */
  454. public Dimension getPreferredSize() {
  455. return preferredSize();
  456. }
  457. /**
  458. * @deprecated As of JDK version 1.1,
  459. * replaced by <code>getPreferredSize()</code>.
  460. */
  461. public Dimension preferredSize() {
  462. synchronized (getTreeLock()) {
  463. return ((rows > 0) && (columns > 0)) ?
  464. preferredSize(rows, columns) :
  465. super.preferredSize();
  466. }
  467. }
  468. /**
  469. * Determines the minimum size of a text area with the specified
  470. * number of rows and columns.
  471. * @param rows the number of rows
  472. * @param columns the number of columns
  473. * @return the minimum dimensions required to display
  474. * the text area with the specified
  475. * number of rows and columns
  476. * @see java.awt.Component#getMinimumSize
  477. * @since JDK1.1
  478. */
  479. public Dimension getMinimumSize(int rows, int columns) {
  480. return minimumSize(rows, columns);
  481. }
  482. /**
  483. * @deprecated As of JDK version 1.1,
  484. * replaced by <code>getMinimumSize(int, int)</code>.
  485. */
  486. public Dimension minimumSize(int rows, int columns) {
  487. synchronized (getTreeLock()) {
  488. TextAreaPeer peer = (TextAreaPeer)this.peer;
  489. return (peer != null) ?
  490. peer.minimumSize(rows, columns) :
  491. super.minimumSize();
  492. }
  493. }
  494. /**
  495. * Determines the minimum size of this text area.
  496. * @return the preferred dimensions needed for this text area
  497. * @see java.awt.Component#getPreferredSize
  498. * @since JDK1.1
  499. */
  500. public Dimension getMinimumSize() {
  501. return minimumSize();
  502. }
  503. /**
  504. * @deprecated As of JDK version 1.1,
  505. * replaced by <code>getMinimumSize()</code>.
  506. */
  507. public Dimension minimumSize() {
  508. synchronized (getTreeLock()) {
  509. return ((rows > 0) && (columns > 0)) ?
  510. minimumSize(rows, columns) :
  511. super.minimumSize();
  512. }
  513. }
  514. /**
  515. * Returns a string representing the state of this <code>TextArea</code>.
  516. * This method is intended to be used only for debugging purposes, and the
  517. * content and format of the returned string may vary between
  518. * implementations. The returned string may be empty but may not be
  519. * <code>null</code>.
  520. *
  521. * @return the parameter string of this text area
  522. */
  523. protected String paramString() {
  524. String sbVisStr;
  525. switch (scrollbarVisibility) {
  526. case SCROLLBARS_BOTH:
  527. sbVisStr = "both";
  528. break;
  529. case SCROLLBARS_VERTICAL_ONLY:
  530. sbVisStr = "vertical-only";
  531. break;
  532. case SCROLLBARS_HORIZONTAL_ONLY:
  533. sbVisStr = "horizontal-only";
  534. break;
  535. case SCROLLBARS_NONE:
  536. sbVisStr = "none";
  537. break;
  538. default:
  539. sbVisStr = "invalid display policy";
  540. }
  541. return super.paramString() + ",rows=" + rows +
  542. ",columns=" + columns +
  543. ",scrollbarVisibility=" + sbVisStr;
  544. }
  545. /*
  546. * Serialization support.
  547. */
  548. /**
  549. * The textArea Serialized Data Version.
  550. *
  551. * @serial
  552. */
  553. private int textAreaSerializedDataVersion = 2;
  554. /**
  555. * Read the ObjectInputStream.
  556. * @exception HeadlessException if
  557. * <code>GraphicsEnvironment.isHeadless()</code> returns
  558. * <code>true</code>
  559. * @see java.awt.GraphicsEnvironment#isHeadless
  560. */
  561. private void readObject(ObjectInputStream s)
  562. throws ClassNotFoundException, IOException, HeadlessException
  563. {
  564. // HeadlessException will be thrown by TextComponent's readObject
  565. s.defaultReadObject();
  566. // Make sure the state we just read in for columns, rows,
  567. // and scrollbarVisibility has legal values
  568. if (columns < 0) {
  569. columns = 0;
  570. }
  571. if (rows < 0) {
  572. rows = 0;
  573. }
  574. if ((scrollbarVisibility < SCROLLBARS_BOTH) ||
  575. (scrollbarVisibility > SCROLLBARS_NONE)) {
  576. this.scrollbarVisibility = SCROLLBARS_BOTH;
  577. }
  578. if (textAreaSerializedDataVersion < 2) {
  579. setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
  580. forwardTraversalKeys);
  581. setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
  582. backwardTraversalKeys);
  583. }
  584. }
  585. /////////////////
  586. // Accessibility support
  587. ////////////////
  588. /**
  589. * Returns the <code>AccessibleContext</code> associated with
  590. * this <code>TextArea</code>. For text areas, the
  591. * <code>AccessibleContext</code> takes the form of an
  592. * <code>AccessibleAWTTextArea</code>.
  593. * A new <code>AccessibleAWTTextArea</code> instance is created if necessary.
  594. *
  595. * @return an <code>AccessibleAWTTextArea</code> that serves as the
  596. * <code>AccessibleContext</code> of this <code>TextArea</code>
  597. */
  598. public AccessibleContext getAccessibleContext() {
  599. if (accessibleContext == null) {
  600. accessibleContext = new AccessibleAWTTextArea();
  601. }
  602. return accessibleContext;
  603. }
  604. /**
  605. * This class implements accessibility support for the
  606. * <code>TextArea</code> class. It provides an implementation of the
  607. * Java Accessibility API appropriate to text area user-interface elements.
  608. */
  609. protected class AccessibleAWTTextArea extends AccessibleAWTTextComponent {
  610. /**
  611. * Gets the state set of this object.
  612. *
  613. * @return an instance of AccessibleStateSet describing the states
  614. * of the object
  615. * @see AccessibleStateSet
  616. */
  617. public AccessibleStateSet getAccessibleStateSet() {
  618. AccessibleStateSet states = super.getAccessibleStateSet();
  619. states.add(AccessibleState.MULTI_LINE);
  620. return states;
  621. }
  622. }
  623. }