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