1. /*
  2. * @(#)TextArea.java 1.78 04/05/18
  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.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.78, 05/18/04
  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. @Deprecated
  278. public synchronized void insertText(String str, int pos) {
  279. TextAreaPeer peer = (TextAreaPeer)this.peer;
  280. if (peer != null) {
  281. peer.insertText(str, pos);
  282. } else {
  283. text = text.substring(0, pos) + str + text.substring(pos);
  284. }
  285. }
  286. /**
  287. * Appends the given text to the text area's current text.
  288. * <p>Note that passing <code>null</code> or inconsistent
  289. * parameters is invalid and will result in unspecified
  290. * behavior.
  291. *
  292. * @param str the non-<code>null</code> text to append
  293. * @see java.awt.TextArea#insert
  294. * @since JDK1.1
  295. */
  296. public void append(String str) {
  297. appendText(str);
  298. }
  299. /**
  300. * @deprecated As of JDK version 1.1,
  301. * replaced by <code>append(String)</code>.
  302. */
  303. @Deprecated
  304. public synchronized void appendText(String str) {
  305. if (peer != null) {
  306. insertText(str, getText().length());
  307. } else {
  308. text = text + str;
  309. }
  310. }
  311. /**
  312. * Replaces text between the indicated start and end positions
  313. * with the specified replacement text. The text at the end
  314. * position will not be replaced. The text at the start
  315. * position will be replaced (unless the start position is the
  316. * same as the end position).
  317. * The text position is zero-based. The inserted substring may be
  318. * of a different length than the text it replaces.
  319. * <p>Note that passing <code>null</code> or inconsistent
  320. * parameters is invalid and will result in unspecified
  321. * behavior.
  322. *
  323. * @param str the non-<code>null</code> text to use as
  324. * the replacement
  325. * @param start the start position
  326. * @param end the end position
  327. * @see java.awt.TextArea#insert
  328. * @since JDK1.1
  329. */
  330. public void replaceRange(String str, int start, int end) {
  331. replaceText(str, start, end);
  332. }
  333. /**
  334. * @deprecated As of JDK version 1.1,
  335. * replaced by <code>replaceRange(String, int, int)</code>.
  336. */
  337. @Deprecated
  338. public synchronized void replaceText(String str, int start, int end) {
  339. TextAreaPeer peer = (TextAreaPeer)this.peer;
  340. if (peer != null) {
  341. peer.replaceText(str, start, end);
  342. } else {
  343. text = text.substring(0, start) + str + text.substring(end);
  344. }
  345. }
  346. /**
  347. * Returns the number of rows in the text area.
  348. * @return the number of rows in the text area
  349. * @see #setRows(int)
  350. * @see #getColumns()
  351. * @since JDK1
  352. */
  353. public int getRows() {
  354. return rows;
  355. }
  356. /**
  357. * Sets the number of rows for this text area.
  358. * @param rows the number of rows
  359. * @see #getRows()
  360. * @see #setColumns(int)
  361. * @exception IllegalArgumentException if the value
  362. * supplied for <code>rows</code>
  363. * is less than <code>0</code>
  364. * @since JDK1.1
  365. */
  366. public void setRows(int rows) {
  367. int oldVal = this.rows;
  368. if (rows < 0) {
  369. throw new IllegalArgumentException("rows less than zero.");
  370. }
  371. if (rows != oldVal) {
  372. this.rows = rows;
  373. invalidate();
  374. }
  375. }
  376. /**
  377. * Returns the number of columns in this text area.
  378. * @return the number of columns in the text area
  379. * @see #setColumns(int)
  380. * @see #getRows()
  381. */
  382. public int getColumns() {
  383. return columns;
  384. }
  385. /**
  386. * Sets the number of columns for this text area.
  387. * @param columns the number of columns
  388. * @see #getColumns()
  389. * @see #setRows(int)
  390. * @exception IllegalArgumentException if the value
  391. * supplied for <code>columns</code>
  392. * is less than <code>0</code>
  393. * @since JDK1.1
  394. */
  395. public void setColumns(int columns) {
  396. int oldVal = this.columns;
  397. if (columns < 0) {
  398. throw new IllegalArgumentException("columns less than zero.");
  399. }
  400. if (columns != oldVal) {
  401. this.columns = columns;
  402. invalidate();
  403. }
  404. }
  405. /**
  406. * Returns an enumerated value that indicates which scroll bars
  407. * the text area uses.
  408. * <p>
  409. * The <code>TextArea</code> class defines four integer constants
  410. * that are used to specify which scroll bars are available.
  411. * <code>TextArea</code> has one constructor that gives the
  412. * application discretion over scroll bars.
  413. *
  414. * @return an integer that indicates which scroll bars are used
  415. * @see java.awt.TextArea#SCROLLBARS_BOTH
  416. * @see java.awt.TextArea#SCROLLBARS_VERTICAL_ONLY
  417. * @see java.awt.TextArea#SCROLLBARS_HORIZONTAL_ONLY
  418. * @see java.awt.TextArea#SCROLLBARS_NONE
  419. * @see java.awt.TextArea#TextArea(java.lang.String, int, int, int)
  420. * @since JDK1.1
  421. */
  422. public int getScrollbarVisibility() {
  423. return scrollbarVisibility;
  424. }
  425. /**
  426. * Determines the preferred size of a text area with the specified
  427. * number of rows and columns.
  428. * @param rows the number of rows
  429. * @param columns the number of columns
  430. * @return the preferred dimensions required to display
  431. * the text area with the specified
  432. * number of rows and columns
  433. * @see java.awt.Component#getPreferredSize
  434. * @since JDK1.1
  435. */
  436. public Dimension getPreferredSize(int rows, int columns) {
  437. return preferredSize(rows, columns);
  438. }
  439. /**
  440. * @deprecated As of JDK version 1.1,
  441. * replaced by <code>getPreferredSize(int, int)</code>.
  442. */
  443. @Deprecated
  444. public Dimension preferredSize(int rows, int columns) {
  445. synchronized (getTreeLock()) {
  446. TextAreaPeer peer = (TextAreaPeer)this.peer;
  447. return (peer != null) ?
  448. peer.preferredSize(rows, columns) :
  449. super.preferredSize();
  450. }
  451. }
  452. /**
  453. * Determines the preferred size of this text area.
  454. * @return the preferred dimensions needed for this text area
  455. * @see java.awt.Component#getPreferredSize
  456. * @since JDK1.1
  457. */
  458. public Dimension getPreferredSize() {
  459. return preferredSize();
  460. }
  461. /**
  462. * @deprecated As of JDK version 1.1,
  463. * replaced by <code>getPreferredSize()</code>.
  464. */
  465. @Deprecated
  466. public Dimension preferredSize() {
  467. synchronized (getTreeLock()) {
  468. return ((rows > 0) && (columns > 0)) ?
  469. preferredSize(rows, columns) :
  470. super.preferredSize();
  471. }
  472. }
  473. /**
  474. * Determines the minimum size of a text area with the specified
  475. * number of rows and columns.
  476. * @param rows the number of rows
  477. * @param columns the number of columns
  478. * @return the minimum dimensions required to display
  479. * the text area with the specified
  480. * number of rows and columns
  481. * @see java.awt.Component#getMinimumSize
  482. * @since JDK1.1
  483. */
  484. public Dimension getMinimumSize(int rows, int columns) {
  485. return minimumSize(rows, columns);
  486. }
  487. /**
  488. * @deprecated As of JDK version 1.1,
  489. * replaced by <code>getMinimumSize(int, int)</code>.
  490. */
  491. @Deprecated
  492. public Dimension minimumSize(int rows, int columns) {
  493. synchronized (getTreeLock()) {
  494. TextAreaPeer peer = (TextAreaPeer)this.peer;
  495. return (peer != null) ?
  496. peer.minimumSize(rows, columns) :
  497. super.minimumSize();
  498. }
  499. }
  500. /**
  501. * Determines the minimum size of this text area.
  502. * @return the preferred dimensions needed for this text area
  503. * @see java.awt.Component#getPreferredSize
  504. * @since JDK1.1
  505. */
  506. public Dimension getMinimumSize() {
  507. return minimumSize();
  508. }
  509. /**
  510. * @deprecated As of JDK version 1.1,
  511. * replaced by <code>getMinimumSize()</code>.
  512. */
  513. @Deprecated
  514. public Dimension minimumSize() {
  515. synchronized (getTreeLock()) {
  516. return ((rows > 0) && (columns > 0)) ?
  517. minimumSize(rows, columns) :
  518. super.minimumSize();
  519. }
  520. }
  521. /**
  522. * Returns a string representing the state of this <code>TextArea</code>.
  523. * This method is intended to be used only for debugging purposes, and the
  524. * content and format of the returned string may vary between
  525. * implementations. The returned string may be empty but may not be
  526. * <code>null</code>.
  527. *
  528. * @return the parameter string of this text area
  529. */
  530. protected String paramString() {
  531. String sbVisStr;
  532. switch (scrollbarVisibility) {
  533. case SCROLLBARS_BOTH:
  534. sbVisStr = "both";
  535. break;
  536. case SCROLLBARS_VERTICAL_ONLY:
  537. sbVisStr = "vertical-only";
  538. break;
  539. case SCROLLBARS_HORIZONTAL_ONLY:
  540. sbVisStr = "horizontal-only";
  541. break;
  542. case SCROLLBARS_NONE:
  543. sbVisStr = "none";
  544. break;
  545. default:
  546. sbVisStr = "invalid display policy";
  547. }
  548. return super.paramString() + ",rows=" + rows +
  549. ",columns=" + columns +
  550. ",scrollbarVisibility=" + sbVisStr;
  551. }
  552. /*
  553. * Serialization support.
  554. */
  555. /**
  556. * The textArea Serialized Data Version.
  557. *
  558. * @serial
  559. */
  560. private int textAreaSerializedDataVersion = 2;
  561. /**
  562. * Read the ObjectInputStream.
  563. * @exception HeadlessException if
  564. * <code>GraphicsEnvironment.isHeadless()</code> returns
  565. * <code>true</code>
  566. * @see java.awt.GraphicsEnvironment#isHeadless
  567. */
  568. private void readObject(ObjectInputStream s)
  569. throws ClassNotFoundException, IOException, HeadlessException
  570. {
  571. // HeadlessException will be thrown by TextComponent's readObject
  572. s.defaultReadObject();
  573. // Make sure the state we just read in for columns, rows,
  574. // and scrollbarVisibility has legal values
  575. if (columns < 0) {
  576. columns = 0;
  577. }
  578. if (rows < 0) {
  579. rows = 0;
  580. }
  581. if ((scrollbarVisibility < SCROLLBARS_BOTH) ||
  582. (scrollbarVisibility > SCROLLBARS_NONE)) {
  583. this.scrollbarVisibility = SCROLLBARS_BOTH;
  584. }
  585. if (textAreaSerializedDataVersion < 2) {
  586. setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
  587. forwardTraversalKeys);
  588. setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
  589. backwardTraversalKeys);
  590. }
  591. }
  592. /////////////////
  593. // Accessibility support
  594. ////////////////
  595. /**
  596. * Returns the <code>AccessibleContext</code> associated with
  597. * this <code>TextArea</code>. For text areas, the
  598. * <code>AccessibleContext</code> takes the form of an
  599. * <code>AccessibleAWTTextArea</code>.
  600. * A new <code>AccessibleAWTTextArea</code> instance is created if necessary.
  601. *
  602. * @return an <code>AccessibleAWTTextArea</code> that serves as the
  603. * <code>AccessibleContext</code> of this <code>TextArea</code>
  604. */
  605. public AccessibleContext getAccessibleContext() {
  606. if (accessibleContext == null) {
  607. accessibleContext = new AccessibleAWTTextArea();
  608. }
  609. return accessibleContext;
  610. }
  611. /**
  612. * This class implements accessibility support for the
  613. * <code>TextArea</code> class. It provides an implementation of the
  614. * Java Accessibility API appropriate to text area user-interface elements.
  615. */
  616. protected class AccessibleAWTTextArea extends AccessibleAWTTextComponent
  617. {
  618. /*
  619. * JDK 1.3 serialVersionUID
  620. */
  621. private static final long serialVersionUID = 3472827823632144419L;
  622. /**
  623. * Gets the state set of this object.
  624. *
  625. * @return an instance of AccessibleStateSet describing the states
  626. * of the object
  627. * @see AccessibleStateSet
  628. */
  629. public AccessibleStateSet getAccessibleStateSet() {
  630. AccessibleStateSet states = super.getAccessibleStateSet();
  631. states.add(AccessibleState.MULTI_LINE);
  632. return states;
  633. }
  634. }
  635. }