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