1. /*
  2. * @(#)JTextArea.java 1.92 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.awt.*;
  9. import java.awt.event.*;
  10. import javax.swing.text.*;
  11. import javax.swing.plaf.*;
  12. import javax.accessibility.*;
  13. import java.util.Collections;
  14. import java.util.Set;
  15. import java.util.StringTokenizer;
  16. import java.util.TreeSet;
  17. import java.io.ObjectOutputStream;
  18. import java.io.ObjectInputStream;
  19. import java.io.IOException;
  20. /**
  21. * A <code>JTextArea</code> is a multi-line area that displays plain text.
  22. * It is intended to be a lightweight component that provides source
  23. * compatibility with the <code>java.awt.TextArea</code> class where it can
  24. * reasonably do so.
  25. * You can find information and examples of using all the text components in
  26. * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/text.html">Using Text Components</a>,
  27. * a section in <em>The Java Tutorial.</em>
  28. *
  29. * <p>
  30. * This component has capabilities not found in the
  31. * <code>java.awt.TextArea</code> class. The superclass should be
  32. * consulted for additional capabilities.
  33. * Alternative multi-line text classes with
  34. * more capabilities are <code>JTextPane</code> and <code>JEditorPane</code>.
  35. * <p>
  36. * The <code>java.awt.TextArea</code> internally handles scrolling.
  37. * <code>JTextArea</code> is different in that it doesn't manage scrolling,
  38. * but implements the swing <code>Scrollable</code> interface. This allows it
  39. * to be placed inside a <code>JScrollPane</code> if scrolling
  40. * behavior is desired, and used directly if scrolling is not desired.
  41. * <p>
  42. * The <code>java.awt.TextArea</code> has the ability to do line wrapping.
  43. * This was controlled by the horizontal scrolling policy. Since
  44. * scrolling is not done by <code>JTextArea</code> directly, backward
  45. * compatibility must be provided another way. <code>JTextArea</code> has
  46. * a bound property for line wrapping that controls whether or
  47. * not it will wrap lines. By default, the line wrapping property
  48. * is set to false (not wrapped).
  49. * <p>
  50. * <code>java.awt.TextArea</code> has two properties <code>rows</code>
  51. * and <code>columns</code> that are used to determine the preferred size.
  52. * <code>JTextArea</code> uses these properties to indicate the
  53. * preferred size of the viewport when placed inside a <code>JScrollPane</code>
  54. * to match the functionality provided by <code>java.awt.TextArea</code>.
  55. * <code>JTextArea</code> has a preferred size of what is needed to
  56. * display all of the text, so that it functions properly inside of
  57. * a <code>JScrollPane</code>. If the value for <code>rows</code>
  58. * or <code>columns</code> is equal to zero,
  59. * the preferred size along that axis is used for
  60. * the viewport preferred size along the same axis.
  61. * <p>
  62. * The <code>java.awt.TextArea</code> could be monitored for changes by adding
  63. * a <code>TextListener</code> for <code>TextEvent</code>s.
  64. * In the <code>JTextComponent</code> based
  65. * components, changes are broadcasted from the model via a
  66. * <code>DocumentEvent</code> to <code>DocumentListeners</code>.
  67. * The <code>DocumentEvent</code> gives
  68. * the location of the change and the kind of change if desired.
  69. * The code fragment might look something like:
  70. * <pre>
  71. * DocumentListener myListener = ??;
  72. * JTextArea myArea = ??;
  73. * myArea.getDocument().addDocumentListener(myListener);
  74. * </pre>
  75. * <p>
  76. * <dt><b><font size=+1>Newlines</font></b>
  77. * <dd>
  78. * For a discussion on how newlines are handled, see
  79. * <a href="text/DefaultEditorKit.html">DefaultEditorKit</a>.
  80. * </dl>
  81. *
  82. * <p>
  83. * <strong>Warning:</strong>
  84. * Serialized objects of this class will not be compatible with
  85. * future Swing releases. The current serialization support is
  86. * appropriate for short term storage or RMI between applications running
  87. * the same version of Swing. As of 1.4, support for long term storage
  88. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  89. * has been added to the <code>java.beans</code> package.
  90. * Please see {@link java.beans.XMLEncoder}.
  91. *
  92. * @beaninfo
  93. * attribute: isContainer false
  94. * description: A multi-line area that displays plain text.
  95. *
  96. * @author Timothy Prinzing
  97. * @version 1.92 12/19/03
  98. * @see JTextPane
  99. * @see JEditorPane
  100. */
  101. public class JTextArea extends JTextComponent {
  102. /**
  103. * @see #getUIClassID
  104. * @see #readObject
  105. */
  106. private static final String uiClassID = "TextAreaUI";
  107. /**
  108. * Constructs a new TextArea. A default model is set, the initial string
  109. * is null, and rows/columns are set to 0.
  110. */
  111. public JTextArea() {
  112. this(null, null, 0, 0);
  113. }
  114. /**
  115. * Constructs a new TextArea with the specified text displayed.
  116. * A default model is created and rows/columns are set to 0.
  117. *
  118. * @param text the text to be displayed, or null
  119. */
  120. public JTextArea(String text) {
  121. this(null, text, 0, 0);
  122. }
  123. /**
  124. * Constructs a new empty TextArea with the specified number of
  125. * rows and columns. A default model is created, and the initial
  126. * string is null.
  127. *
  128. * @param rows the number of rows >= 0
  129. * @param columns the number of columns >= 0
  130. * @exception IllegalArgumentException if the rows or columns
  131. * arguments are negative.
  132. */
  133. public JTextArea(int rows, int columns) {
  134. this(null, null, rows, columns);
  135. }
  136. /**
  137. * Constructs a new TextArea with the specified text and number
  138. * of rows and columns. A default model is created.
  139. *
  140. * @param text the text to be displayed, or null
  141. * @param rows the number of rows >= 0
  142. * @param columns the number of columns >= 0
  143. * @exception IllegalArgumentException if the rows or columns
  144. * arguments are negative.
  145. */
  146. public JTextArea(String text, int rows, int columns) {
  147. this(null, text, rows, columns);
  148. }
  149. /**
  150. * Constructs a new JTextArea with the given document model, and defaults
  151. * for all of the other arguments (null, 0, 0).
  152. *
  153. * @param doc the model to use
  154. */
  155. public JTextArea(Document doc) {
  156. this(doc, null, 0, 0);
  157. }
  158. /**
  159. * Constructs a new JTextArea with the specified number of rows
  160. * and columns, and the given model. All of the constructors
  161. * feed through this constructor.
  162. *
  163. * @param doc the model to use, or create a default one if null
  164. * @param text the text to be displayed, null if none
  165. * @param rows the number of rows >= 0
  166. * @param columns the number of columns >= 0
  167. * @exception IllegalArgumentException if the rows or columns
  168. * arguments are negative.
  169. */
  170. public JTextArea(Document doc, String text, int rows, int columns) {
  171. super();
  172. this.rows = rows;
  173. this.columns = columns;
  174. if (doc == null) {
  175. doc = createDefaultModel();
  176. }
  177. setDocument(doc);
  178. if (text != null) {
  179. setText(text);
  180. select(0, 0);
  181. }
  182. if (rows < 0) {
  183. throw new IllegalArgumentException("rows: " + rows);
  184. }
  185. if (columns < 0) {
  186. throw new IllegalArgumentException("columns: " + columns);
  187. }
  188. LookAndFeel.installProperty(this,
  189. "focusTraversalKeysForward",
  190. JComponent.
  191. getManagingFocusForwardTraversalKeys());
  192. LookAndFeel.installProperty(this,
  193. "focusTraversalKeysBackward",
  194. JComponent.
  195. getManagingFocusBackwardTraversalKeys());
  196. }
  197. /**
  198. * Returns the class ID for the UI.
  199. *
  200. * @return the ID ("TextAreaUI")
  201. * @see JComponent#getUIClassID
  202. * @see UIDefaults#getUI
  203. */
  204. public String getUIClassID() {
  205. return uiClassID;
  206. }
  207. /**
  208. * Creates the default implementation of the model
  209. * to be used at construction if one isn't explicitly
  210. * given. A new instance of PlainDocument is returned.
  211. *
  212. * @return the default document model
  213. */
  214. protected Document createDefaultModel() {
  215. return new PlainDocument();
  216. }
  217. /**
  218. * Sets the number of characters to expand tabs to.
  219. * This will be multiplied by the maximum advance for
  220. * variable width fonts. A PropertyChange event ("tabSize") is fired
  221. * when the tab size changes.
  222. *
  223. * @param size number of characters to expand to
  224. * @see #getTabSize
  225. * @beaninfo
  226. * preferred: true
  227. * bound: true
  228. * description: the number of characters to expand tabs to
  229. */
  230. public void setTabSize(int size) {
  231. Document doc = getDocument();
  232. if (doc != null) {
  233. int old = getTabSize();
  234. doc.putProperty(PlainDocument.tabSizeAttribute, new Integer(size));
  235. firePropertyChange("tabSize", old, size);
  236. }
  237. }
  238. /**
  239. * Gets the number of characters used to expand tabs. If the document is
  240. * null or doesn't have a tab setting, return a default of 8.
  241. *
  242. * @return the number of characters
  243. */
  244. public int getTabSize() {
  245. int size = 8;
  246. Document doc = getDocument();
  247. if (doc != null) {
  248. Integer i = (Integer) doc.getProperty(PlainDocument.tabSizeAttribute);
  249. if (i != null) {
  250. size = i.intValue();
  251. }
  252. }
  253. return size;
  254. }
  255. /**
  256. * Sets the line-wrapping policy of the text area. If set
  257. * to true the lines will be wrapped if they are too long
  258. * to fit within the allocated width. If set to false,
  259. * the lines will always be unwrapped. A <code>PropertyChange</code>
  260. * event ("lineWrap") is fired when the policy is changed.
  261. * By default this property is false.
  262. *
  263. * @param wrap indicates if lines should be wrapped
  264. * @see #getLineWrap
  265. * @beaninfo
  266. * preferred: true
  267. * bound: true
  268. * description: should lines be wrapped
  269. */
  270. public void setLineWrap(boolean wrap) {
  271. boolean old = this.wrap;
  272. this.wrap = wrap;
  273. firePropertyChange("lineWrap", old, wrap);
  274. }
  275. /**
  276. * Gets the line-wrapping policy of the text area. If set
  277. * to true the lines will be wrapped if they are too long
  278. * to fit within the allocated width. If set to false,
  279. * the lines will always be unwrapped.
  280. *
  281. * @return if lines will be wrapped
  282. */
  283. public boolean getLineWrap() {
  284. return wrap;
  285. }
  286. /**
  287. * Sets the style of wrapping used if the text area is wrapping
  288. * lines. If set to true the lines will be wrapped at word
  289. * boundaries (whitespace) if they are too long
  290. * to fit within the allocated width. If set to false,
  291. * the lines will be wrapped at character boundaries.
  292. * By default this property is false.
  293. *
  294. * @param word indicates if word boundaries should be used
  295. * for line wrapping
  296. * @see #getWrapStyleWord
  297. * @beaninfo
  298. * preferred: false
  299. * bound: true
  300. * description: should wrapping occur at word boundaries
  301. */
  302. public void setWrapStyleWord(boolean word) {
  303. boolean old = this.word;
  304. this.word = word;
  305. firePropertyChange("wrapStyleWord", old, word);
  306. }
  307. /**
  308. * Gets the style of wrapping used if the text area is wrapping
  309. * lines. If set to true the lines will be wrapped at word
  310. * boundaries (ie whitespace) if they are too long
  311. * to fit within the allocated width. If set to false,
  312. * the lines will be wrapped at character boundaries.
  313. *
  314. * @return if the wrap style should be word boundaries
  315. * instead of character boundaries
  316. * @see #setWrapStyleWord
  317. */
  318. public boolean getWrapStyleWord() {
  319. return word;
  320. }
  321. /**
  322. * Translates an offset into the components text to a
  323. * line number.
  324. *
  325. * @param offset the offset >= 0
  326. * @return the line number >= 0
  327. * @exception BadLocationException thrown if the offset is
  328. * less than zero or greater than the document length.
  329. */
  330. public int getLineOfOffset(int offset) throws BadLocationException {
  331. Document doc = getDocument();
  332. if (offset < 0) {
  333. throw new BadLocationException("Can't translate offset to line", -1);
  334. } else if (offset > doc.getLength()) {
  335. throw new BadLocationException("Can't translate offset to line", doc.getLength()+1);
  336. } else {
  337. Element map = getDocument().getDefaultRootElement();
  338. return map.getElementIndex(offset);
  339. }
  340. }
  341. /**
  342. * Determines the number of lines contained in the area.
  343. *
  344. * @return the number of lines > 0
  345. */
  346. public int getLineCount() {
  347. Element map = getDocument().getDefaultRootElement();
  348. return map.getElementCount();
  349. }
  350. /**
  351. * Determines the offset of the start of the given line.
  352. *
  353. * @param line the line number to translate >= 0
  354. * @return the offset >= 0
  355. * @exception BadLocationException thrown if the line is
  356. * less than zero or greater or equal to the number of
  357. * lines contained in the document (as reported by
  358. * getLineCount).
  359. */
  360. public int getLineStartOffset(int line) throws BadLocationException {
  361. int lineCount = getLineCount();
  362. if (line < 0) {
  363. throw new BadLocationException("Negative line", -1);
  364. } else if (line >= lineCount) {
  365. throw new BadLocationException("No such line", getDocument().getLength()+1);
  366. } else {
  367. Element map = getDocument().getDefaultRootElement();
  368. Element lineElem = map.getElement(line);
  369. return lineElem.getStartOffset();
  370. }
  371. }
  372. /**
  373. * Determines the offset of the end of the given line.
  374. *
  375. * @param line the line >= 0
  376. * @return the offset >= 0
  377. * @exception BadLocationException Thrown if the line is
  378. * less than zero or greater or equal to the number of
  379. * lines contained in the document (as reported by
  380. * getLineCount).
  381. */
  382. public int getLineEndOffset(int line) throws BadLocationException {
  383. int lineCount = getLineCount();
  384. if (line < 0) {
  385. throw new BadLocationException("Negative line", -1);
  386. } else if (line >= lineCount) {
  387. throw new BadLocationException("No such line", getDocument().getLength()+1);
  388. } else {
  389. Element map = getDocument().getDefaultRootElement();
  390. Element lineElem = map.getElement(line);
  391. int endOffset = lineElem.getEndOffset();
  392. // hide the implicit break at the end of the document
  393. return ((line == lineCount - 1) ? (endOffset - 1) : endOffset);
  394. }
  395. }
  396. // --- java.awt.TextArea methods ---------------------------------
  397. /**
  398. * Inserts the specified text at the specified position. Does nothing
  399. * if the model is null or if the text is null or empty.
  400. * <p>
  401. * This method is thread safe, although most Swing methods
  402. * are not. Please see
  403. * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
  404. * and Swing</A> for more information.
  405. *
  406. * @param str the text to insert
  407. * @param pos the position at which to insert >= 0
  408. * @exception IllegalArgumentException if pos is an
  409. * invalid position in the model
  410. * @see TextComponent#setText
  411. * @see #replaceRange
  412. */
  413. public void insert(String str, int pos) {
  414. Document doc = getDocument();
  415. if (doc != null) {
  416. try {
  417. doc.insertString(pos, str, null);
  418. } catch (BadLocationException e) {
  419. throw new IllegalArgumentException(e.getMessage());
  420. }
  421. }
  422. }
  423. /**
  424. * Appends the given text to the end of the document. Does nothing if
  425. * the model is null or the string is null or empty.
  426. * <p>
  427. * This method is thread safe, although most Swing methods
  428. * are not. Please see
  429. * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
  430. * and Swing</A> for more information.
  431. *
  432. * @param str the text to insert
  433. * @see #insert
  434. */
  435. public void append(String str) {
  436. Document doc = getDocument();
  437. if (doc != null) {
  438. try {
  439. doc.insertString(doc.getLength(), str, null);
  440. } catch (BadLocationException e) {
  441. }
  442. }
  443. }
  444. /**
  445. * Replaces text from the indicated start to end position with the
  446. * new text specified. Does nothing if the model is null. Simply
  447. * does a delete if the new string is null or empty.
  448. * <p>
  449. * This method is thread safe, although most Swing methods
  450. * are not. Please see
  451. * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
  452. * and Swing</A> for more information.
  453. *
  454. * @param str the text to use as the replacement
  455. * @param start the start position >= 0
  456. * @param end the end position >= start
  457. * @exception IllegalArgumentException if part of the range is an
  458. * invalid position in the model
  459. * @see #insert
  460. * @see #replaceRange
  461. */
  462. public void replaceRange(String str, int start, int end) {
  463. if (end < start) {
  464. throw new IllegalArgumentException("end before start");
  465. }
  466. Document doc = getDocument();
  467. if (doc != null) {
  468. try {
  469. if (doc instanceof AbstractDocument) {
  470. ((AbstractDocument)doc).replace(start, end - start, str,
  471. null);
  472. }
  473. else {
  474. doc.remove(start, end - start);
  475. doc.insertString(start, str, null);
  476. }
  477. } catch (BadLocationException e) {
  478. throw new IllegalArgumentException(e.getMessage());
  479. }
  480. }
  481. }
  482. /**
  483. * Returns the number of rows in the TextArea.
  484. *
  485. * @return the number of rows >= 0
  486. */
  487. public int getRows() {
  488. return rows;
  489. }
  490. /**
  491. * Sets the number of rows for this TextArea. Calls invalidate() after
  492. * setting the new value.
  493. *
  494. * @param rows the number of rows >= 0
  495. * @exception IllegalArgumentException if rows is less than 0
  496. * @see #getRows
  497. * @beaninfo
  498. * description: the number of rows preferred for display
  499. */
  500. public void setRows(int rows) {
  501. int oldVal = this.rows;
  502. if (rows < 0) {
  503. throw new IllegalArgumentException("rows less than zero.");
  504. }
  505. if (rows != oldVal) {
  506. this.rows = rows;
  507. invalidate();
  508. }
  509. }
  510. /**
  511. * Defines the meaning of the height of a row. This defaults to
  512. * the height of the font.
  513. *
  514. * @return the height >= 1
  515. */
  516. protected int getRowHeight() {
  517. if (rowHeight == 0) {
  518. FontMetrics metrics = getFontMetrics(getFont());
  519. rowHeight = metrics.getHeight();
  520. }
  521. return rowHeight;
  522. }
  523. /**
  524. * Returns the number of columns in the TextArea.
  525. *
  526. * @return number of columns >= 0
  527. */
  528. public int getColumns() {
  529. return columns;
  530. }
  531. /**
  532. * Sets the number of columns for this TextArea. Does an invalidate()
  533. * after setting the new value.
  534. *
  535. * @param columns the number of columns >= 0
  536. * @exception IllegalArgumentException if columns is less than 0
  537. * @see #getColumns
  538. * @beaninfo
  539. * description: the number of columns preferred for display
  540. */
  541. public void setColumns(int columns) {
  542. int oldVal = this.columns;
  543. if (columns < 0) {
  544. throw new IllegalArgumentException("columns less than zero.");
  545. }
  546. if (columns != oldVal) {
  547. this.columns = columns;
  548. invalidate();
  549. }
  550. }
  551. /**
  552. * Gets column width.
  553. * The meaning of what a column is can be considered a fairly weak
  554. * notion for some fonts. This method is used to define the width
  555. * of a column. By default this is defined to be the width of the
  556. * character <em>m</em> for the font used. This method can be
  557. * redefined to be some alternative amount.
  558. *
  559. * @return the column width >= 1
  560. */
  561. protected int getColumnWidth() {
  562. if (columnWidth == 0) {
  563. FontMetrics metrics = getFontMetrics(getFont());
  564. columnWidth = metrics.charWidth('m');
  565. }
  566. return columnWidth;
  567. }
  568. // --- Component methods -----------------------------------------
  569. /**
  570. * Returns the preferred size of the TextArea. This is the
  571. * maximum of the size needed to display the text and the
  572. * size requested for the viewport.
  573. *
  574. * @return the size
  575. */
  576. public Dimension getPreferredSize() {
  577. Dimension d = super.getPreferredSize();
  578. d = (d == null) ? new Dimension(400,400) : d;
  579. Insets insets = getInsets();
  580. if (columns != 0) {
  581. d.width = Math.max(d.width, columns * getColumnWidth() +
  582. insets.left + insets.right);
  583. }
  584. if (rows != 0) {
  585. d.height = Math.max(d.height, rows * getRowHeight() +
  586. insets.top + insets.bottom);
  587. }
  588. return d;
  589. }
  590. /**
  591. * Sets the current font. This removes cached row height and column
  592. * width so the new font will be reflected, and calls revalidate().
  593. *
  594. * @param f the font to use as the current font
  595. */
  596. public void setFont(Font f) {
  597. super.setFont(f);
  598. rowHeight = 0;
  599. columnWidth = 0;
  600. }
  601. /**
  602. * Returns a string representation of this JTextArea. This method
  603. * is intended to be used only for debugging purposes, and the
  604. * content and format of the returned string may vary between
  605. * implementations. The returned string may be empty but may not
  606. * be <code>null</code>.
  607. *
  608. * @return a string representation of this JTextArea.
  609. */
  610. protected String paramString() {
  611. String wrapString = (wrap ?
  612. "true" : "false");
  613. String wordString = (word ?
  614. "true" : "false");
  615. return super.paramString() +
  616. ",colums=" + columns +
  617. ",columWidth=" + columnWidth +
  618. ",rows=" + rows +
  619. ",rowHeight=" + rowHeight +
  620. ",word=" + wordString +
  621. ",wrap=" + wrapString;
  622. }
  623. // --- Scrollable methods ----------------------------------------
  624. /**
  625. * Returns true if a viewport should always force the width of this
  626. * Scrollable to match the width of the viewport. This is implemented
  627. * to return true if the line wrapping policy is true, and false
  628. * if lines are not being wrapped.
  629. *
  630. * @return true if a viewport should force the Scrollables width
  631. * to match its own.
  632. */
  633. public boolean getScrollableTracksViewportWidth() {
  634. return (wrap) ? true : super.getScrollableTracksViewportWidth();
  635. }
  636. /**
  637. * Returns the preferred size of the viewport if this component
  638. * is embedded in a JScrollPane. This uses the desired column
  639. * and row settings if they have been set, otherwise the superclass
  640. * behavior is used.
  641. *
  642. * @return The preferredSize of a JViewport whose view is this Scrollable.
  643. * @see JViewport#getPreferredSize
  644. */
  645. public Dimension getPreferredScrollableViewportSize() {
  646. Dimension size = super.getPreferredScrollableViewportSize();
  647. size = (size == null) ? new Dimension(400,400) : size;
  648. size.width = (columns == 0) ? size.width : columns * getColumnWidth();
  649. size.height = (rows == 0) ? size.height : rows * getRowHeight();
  650. return size;
  651. }
  652. /**
  653. * Components that display logical rows or columns should compute
  654. * the scroll increment that will completely expose one new row
  655. * or column, depending on the value of orientation. This is implemented
  656. * to use the values returned by the <code>getRowHeight</code> and
  657. * <code>getColumnWidth</code> methods.
  658. * <p>
  659. * Scrolling containers, like JScrollPane, will use this method
  660. * each time the user requests a unit scroll.
  661. *
  662. * @param visibleRect the view area visible within the viewport
  663. * @param orientation Either SwingConstants.VERTICAL or
  664. * SwingConstants.HORIZONTAL.
  665. * @param direction Less than zero to scroll up/left,
  666. * greater than zero for down/right.
  667. * @return The "unit" increment for scrolling in the specified direction
  668. * @exception IllegalArgumentException for an invalid orientation
  669. * @see JScrollBar#setUnitIncrement
  670. * @see #getRowHeight
  671. * @see #getColumnWidth
  672. */
  673. public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
  674. switch (orientation) {
  675. case SwingConstants.VERTICAL:
  676. return getRowHeight();
  677. case SwingConstants.HORIZONTAL:
  678. return getColumnWidth();
  679. default:
  680. throw new IllegalArgumentException("Invalid orientation: " + orientation);
  681. }
  682. }
  683. /**
  684. * See readObject() and writeObject() in JComponent for more
  685. * information about serialization in Swing.
  686. */
  687. private void writeObject(ObjectOutputStream s) throws IOException {
  688. s.defaultWriteObject();
  689. if (getUIClassID().equals(uiClassID)) {
  690. byte count = JComponent.getWriteObjCounter(this);
  691. JComponent.setWriteObjCounter(this, --count);
  692. if (count == 0 && ui != null) {
  693. ui.installUI(this);
  694. }
  695. }
  696. }
  697. /////////////////
  698. // Accessibility support
  699. ////////////////
  700. /**
  701. * Gets the AccessibleContext associated with this JTextArea.
  702. * For JTextAreas, the AccessibleContext takes the form of an
  703. * AccessibleJTextArea.
  704. * A new AccessibleJTextArea instance is created if necessary.
  705. *
  706. * @return an AccessibleJTextArea that serves as the
  707. * AccessibleContext of this JTextArea
  708. */
  709. public AccessibleContext getAccessibleContext() {
  710. if (accessibleContext == null) {
  711. accessibleContext = new AccessibleJTextArea();
  712. }
  713. return accessibleContext;
  714. }
  715. /**
  716. * This class implements accessibility support for the
  717. * <code>JTextArea</code> class. It provides an implementation of the
  718. * Java Accessibility API appropriate to text area user-interface
  719. * elements.
  720. * <p>
  721. * <strong>Warning:</strong>
  722. * Serialized objects of this class will not be compatible with
  723. * future Swing releases. The current serialization support is
  724. * appropriate for short term storage or RMI between applications running
  725. * the same version of Swing. As of 1.4, support for long term storage
  726. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  727. * has been added to the <code>java.beans</code> package.
  728. * Please see {@link java.beans.XMLEncoder}.
  729. */
  730. protected class AccessibleJTextArea extends AccessibleJTextComponent {
  731. /**
  732. * Gets the state set of this object.
  733. *
  734. * @return an instance of AccessibleStateSet describing the states
  735. * of the object
  736. * @see AccessibleStateSet
  737. */
  738. public AccessibleStateSet getAccessibleStateSet() {
  739. AccessibleStateSet states = super.getAccessibleStateSet();
  740. states.add(AccessibleState.MULTI_LINE);
  741. return states;
  742. }
  743. }
  744. // --- variables -------------------------------------------------
  745. private int rows;
  746. private int columns;
  747. private int columnWidth;
  748. private int rowHeight;
  749. private boolean wrap;
  750. private boolean word;
  751. }