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