1 /* TextArea.java -- A multi-line text entry component
2    Copyright (C) 1999, 2004 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package java.awt;
40 
41 import java.awt.event.KeyEvent;
42 import java.awt.peer.ComponentPeer;
43 import java.awt.peer.TextAreaPeer;
44 import java.util.HashSet;
45 import java.util.Set;
46 
47 import javax.accessibility.AccessibleContext;
48 import javax.accessibility.AccessibleStateSet;
49 
50 
51 /**
52  * A TextArea is a text component capable of displaying multiple lines
53  * of user-editable text.  A TextArea handles its own scrolling and
54  * can display vertical and horizontal scrollbars as navigation aids.
55  *
56  * @author Aaron M. Renn (arenn@urbanophile.com)
57  */
58 public class TextArea extends TextComponent implements java.io.Serializable
59 {
60   /**
61    * Display both horiztonal and vertical scroll bars.
62    */
63   public static final int SCROLLBARS_BOTH = 0;
64 
65   /**
66    * Display vertical scroll bar only.
67    */
68   public static final int SCROLLBARS_VERTICAL_ONLY = 1;
69 
70   /**
71    * Display horizatonal scroll bar only.
72    */
73   public static final int SCROLLBARS_HORIZONTAL_ONLY = 2;
74 
75   /**
76    * Do not display scrollbars.
77    */
78   public static final int SCROLLBARS_NONE = 3;
79 
80   /**
81    * Serialization constant.
82    */
83   private static final long serialVersionUID = 3692302836626095722L;
84 
85   /**
86    * @serial The number of columns used in this text area's preferred
87    * and minimum size calculations.
88    */
89   private int columns;
90 
91   /**
92    * @serial The number of rows used in this text area's preferred and
93    * minimum size calculations.
94    */
95   private int rows;
96 
97   /**
98    * @serial The scrollbar display policy.  One of SCROLLBARS_BOTH,
99    * SCROLLBARS_VERTICAL_ONLY, SCROLLBARS_HORIZONTAL_ONLY,
100    * SCROLLBARS_NONE.
101    */
102   private int scrollbarVisibility;
103 
104   /*
105    * The number used to generate the name returned by getName.
106    */
107   private static transient long next_text_number;
108 
109   /**
110    * Initialize a new instance of <code>TextArea</code> that is empty.
111    * Conceptually the <code>TextArea</code> has 0 rows and 0 columns
112    * but its initial bounds are defined by its peer or by the
113    * container in which it is packed.  Both horizontal and vertical
114    * scrollbars will be displayed.
115    *
116    * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true
117    */
TextArea()118   public TextArea ()
119   {
120     this ("", 0, 0, SCROLLBARS_BOTH);
121   }
122 
123   /**
124    * Initialize a new instance of <code>TextArea</code> that contains
125    * the specified text.  Conceptually the <code>TextArea</code> has 0
126    * rows and 0 columns but its initial bounds are defined by its peer
127    * or by the container in which it is packed.  Both horizontal and
128    * veritcal scrollbars will be displayed.  The TextArea initially contains
129    * the specified text.  If text specified as <code>null<code>, it will
130    * be set to "".
131    *
132    * @param text The text to display in this text area (<code>null</code> permitted).
133    *
134    * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true
135    */
TextArea(String text)136   public TextArea (String text)
137   {
138     this (text, 0, 0, SCROLLBARS_BOTH);
139   }
140 
141   /**
142    * Initialize a new instance of <code>TextArea</code> that is empty
143    * and can display the specified number of rows and columns of text,
144    * without the need to scroll.  Both horizontal and vertical
145    * scrollbars will be displayed.
146    *
147    * @param rows The number of rows in this text area.
148    * @param columns The number of columns in this text area.
149    *
150    * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true
151    */
TextArea(int rows, int columns)152   public TextArea (int rows, int columns)
153   {
154     this ("", rows, columns, SCROLLBARS_BOTH);
155   }
156 
157   /**
158    * Initialize a new instance of <code>TextArea</code> that can
159    * display the specified number of rows and columns of text, without
160    * the need to scroll.  The TextArea initially contains the
161    * specified text.  If text specified as <code>null<code>, it will
162    * be set to "".
163    *
164    * @param text The text to display in this text area (<code>null</code> permitted).
165    * @param rows The number of rows in this text area.
166    * @param columns The number of columns in this text area.
167    *
168    * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true
169    */
TextArea(String text, int rows, int columns)170   public TextArea (String text, int rows, int columns)
171   {
172     this (text, rows, columns, SCROLLBARS_BOTH);
173   }
174 
175   /**
176    * Initialize a new instance of <code>TextArea</code> that initially
177    * contains the specified text.  The TextArea can display the
178    * specified number of rows and columns of text, without the need to
179    * scroll.  This constructor allows specification of the scroll bar
180    * display policy.  The TextArea initially contains the specified text.
181    * If text specified as <code>null<code>, it will be set to "".
182    *
183    * @param text The text to display in this text area (<code>null</code> permitted).
184    * @param rows The number of rows in this text area.
185    * @param columns The number of columns in this text area.
186    * @param scrollbarVisibility The scroll bar display policy. One of
187    * SCROLLBARS_BOTH, SCROLLBARS_VERTICAL_ONLY,
188    * SCROLLBARS_HORIZONTAL_ONLY, SCROLLBARS_NONE.
189    *
190    * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true
191    */
TextArea(String text, int rows, int columns, int scrollbarVisibility)192   public TextArea (String text, int rows, int columns, int scrollbarVisibility)
193   {
194     super (text);
195 
196     if (GraphicsEnvironment.isHeadless ())
197       throw new HeadlessException ();
198 
199     if (rows < 0)
200       this.rows = 0;
201     else
202       this.rows = rows;
203 
204     if (columns < 0)
205       this.columns = 0;
206     else
207       this.columns = columns;
208 
209     if (scrollbarVisibility < 0 || scrollbarVisibility > 4)
210       this.scrollbarVisibility = SCROLLBARS_BOTH;
211     else
212       this.scrollbarVisibility = scrollbarVisibility;
213 
214     // TextAreas need to receive tab key events so we override the
215     // default forward and backward traversal key sets.
216     Set s = new HashSet ();
217     s.add (AWTKeyStroke.getAWTKeyStroke (KeyEvent.VK_TAB,
218                                          KeyEvent.CTRL_DOWN_MASK));
219     setFocusTraversalKeys (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, s);
220     s = new HashSet ();
221     s.add (AWTKeyStroke.getAWTKeyStroke (KeyEvent.VK_TAB,
222                                          KeyEvent.SHIFT_DOWN_MASK
223                                          | KeyEvent.CTRL_DOWN_MASK));
224     setFocusTraversalKeys (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, s);
225   }
226 
227   /**
228    * Retrieve the number of columns that this text area would prefer
229    * to display.  This value may or may not correspond to the number
230    * of columns that are actually displayed.
231    *
232    * @return The preferred number of columns.
233    */
getColumns()234   public int getColumns ()
235   {
236     return columns;
237   }
238 
239   /**
240    * Set the preferred number of columns for this text area.  This
241    * method does not cause the number of columns displayed by the text
242    * area to be updated, if the text area is currently visible.
243    *
244    * @param columns The preferred number of columns.
245    *
246    * @exception IllegalArgumentException If columns is less than zero.
247    */
setColumns(int columns)248   public synchronized void setColumns (int columns)
249   {
250     if (columns < 0)
251       throw new IllegalArgumentException ("Value is less than zero: "
252                                           + columns);
253 
254     this.columns = columns;
255   }
256 
257   /**
258    * Retrieve the number of rows that this text area would prefer to
259    * display.  This value may or may not correspond to the number of
260    * rows that are actually displayed.
261    *
262    * @return The preferred number of rows.
263    */
getRows()264   public int getRows ()
265   {
266     return rows;
267   }
268 
269   /**
270    * Set the preferred number of rows for this text area.  This method
271    * does not cause the number of columns displayed by the text area
272    * to be updated, if the text area is currently visible.
273    *
274    * @param rows The preferred number of rows.
275    *
276    * @exception IllegalArgumentException If rows is less than zero.
277    */
setRows(int rows)278   public synchronized void setRows (int rows)
279   {
280     if (rows < 1)
281       throw new IllegalArgumentException ("Value is less than one: " + rows);
282 
283     this.rows = rows;
284   }
285 
286   /**
287    * Retrieve the minimum size for this text area.
288    *
289    * @return The minimum size for this text field.
290    */
getMinimumSize()291   public Dimension getMinimumSize ()
292   {
293     return getMinimumSize (getRows (), getColumns ());
294   }
295 
296   /**
297    * Retrieve the minimum size for this text area.  If the minimum
298    * size has been set, then rows and columns are used in the calculation.
299    *
300    * @param rows The number of rows to use in the minimum size
301    * calculation.
302    * @param columns The number of columns to use in the minimum size
303    * calculation.
304    *
305    * @return The minimum size for this text area.
306    */
getMinimumSize(int rows, int columns)307   public Dimension getMinimumSize (int rows, int columns)
308   {
309     return minimumSize (rows, columns);
310   }
311 
312   /**
313    * Retrieve the minimum size for this text area.
314    *
315    * @return The minimum size for this text area.
316    *
317    * @deprecated This method is deprecated in favor of
318    * <code>getMinimumSize ()</code>.
319    */
minimumSize()320   public Dimension minimumSize ()
321   {
322     return minimumSize (getRows (), getColumns ());
323   }
324 
325   /**
326    * Retrieve the minimum size for this text area.  If the minimum
327    * size has been set, then rows and columns are used in the calculation.
328    *
329    * @param rows The number of rows to use in the minimum size
330    * calculation.
331    * @param columns The number of columns to use in the minimum size
332    * calculation.
333    *
334    * @return The minimum size for this text area.
335    *
336    * @deprecated This method is deprecated in favor of
337    * <code>getMinimumSize (int, int)</code>.
338    */
minimumSize(int rows, int columns)339   public Dimension minimumSize (int rows, int columns)
340   {
341     if (isMinimumSizeSet())
342       return new Dimension(minSize);
343 
344     TextAreaPeer peer = (TextAreaPeer) getPeer ();
345     if (peer == null)
346       return new Dimension (getWidth(), getHeight());
347 
348     return peer.getMinimumSize (rows, columns);
349   }
350 
351   /**
352    * Retrieve the preferred size for this text area.
353    *
354    * @return The preferred size for this text field.
355    */
getPreferredSize()356   public Dimension getPreferredSize ()
357   {
358     return getPreferredSize (getRows (), getColumns ());
359   }
360 
361   /**
362    * Retrieve the preferred size for this text area.  If the preferred
363    * size has been set, then rows and columns are used in the calculation.
364    *
365    * @param rows The number of rows to use in the preferred size
366    * calculation.
367    * @param columns The number of columns to use in the preferred size
368    * calculation.
369    *
370    * @return The preferred size for this text area.
371    */
getPreferredSize(int rows, int columns)372   public Dimension getPreferredSize (int rows, int columns)
373   {
374     return preferredSize (rows, columns);
375   }
376 
377   /**
378    * Retrieve the preferred size for this text area.
379    *
380    * @return The preferred size for this text field.
381    *
382    * @deprecated This method is deprecated in favor of
383    * <code>getPreferredSize ()</code>.
384    */
preferredSize()385   public Dimension preferredSize ()
386   {
387     return preferredSize (getRows (), getColumns ());
388   }
389 
390   /**
391    * Retrieve the preferred size for this text area.  If the preferred
392    * size has been set, then rows and columns are used in the calculation.
393    *
394    * @param rows The number of rows to use in the preferred size
395    * calculation.
396    * @param columns The number of columns to use in the preferred size
397    * calculation.
398    *
399    * @return The preferred size for this text area.
400    *
401    * @deprecated This method is deprecated in favor of
402    * <code>getPreferredSize (int, int)</code>.
403    */
preferredSize(int rows, int columns)404   public Dimension preferredSize (int rows, int columns)
405   {
406     if (isPreferredSizeSet())
407       return new Dimension(prefSize);
408 
409     TextAreaPeer peer = (TextAreaPeer) getPeer ();
410     if (peer == null)
411       return new Dimension (getWidth(), getHeight());
412 
413     return peer.getPreferredSize (rows, columns);
414   }
415 
416   /**
417    * Retrieve the scroll bar display policy -- one of SCROLLBARS_BOTH,
418    * SCROLLBARS_VERTICAL_ONLY, SCROLLBARS_HORIZONTAL_ONLY,
419    * SCROLLBARS_NONE.
420    *
421    * @return The current scroll bar display policy.
422    */
getScrollbarVisibility()423   public int getScrollbarVisibility ()
424   {
425     return scrollbarVisibility;
426   }
427 
428   /**
429    * Notify this object that it should create its native peer.
430    */
addNotify()431   public void addNotify ()
432   {
433     if (getPeer () == null)
434       setPeer ((ComponentPeer) getToolkit().createTextArea (this));
435   }
436 
437   /**
438    * Append the specified text to the end of the current text.
439    *
440    * @param str The text to append.
441    */
append(String str)442   public void append (String str)
443   {
444     appendText (str);
445   }
446 
447   /**
448    * Append the specified text to the end of the current text.
449    *
450    * @param str The text to append.
451    *
452    * @deprecated This method is deprecated in favor of
453    * <code>append ()</code>.
454    */
appendText(String str)455   public void appendText (String str)
456   {
457     TextAreaPeer peer = (TextAreaPeer) getPeer ();
458 
459     if (peer != null)
460       peer.insert (str, peer.getText().length ());
461     else
462       setText(getText() + str);
463   }
464 
465   /**
466    * Insert the specified text at the specified position.  The first
467    * character in the text area is at position zero.
468    *
469    * @param str The text to insert.
470    * @param pos The position at which to insert text.
471    */
insert(String str, int pos)472   public void insert (String str, int pos)
473   {
474     insertText (str, pos);
475   }
476 
477   /**
478    * Insert the specified text at the specified position.  The first
479    * character in the text area is at position zero.
480    *
481    * @param str The text to insert.
482    * @param pos The position at which to insert text.
483    *
484    * @deprecated This method is deprecated in favor of
485    * <code>insert ()</code>.
486    */
insertText(String str, int pos)487   public void insertText (String str, int pos)
488   {
489     String tmp1 = null;
490     String tmp2 = null;
491 
492     TextAreaPeer peer = (TextAreaPeer) getPeer ();
493 
494     if (peer != null)
495       peer.insert (str, pos);
496     else
497       {
498         tmp1 = getText().substring(0, pos);
499         tmp2 = getText().substring(pos, getText().length());
500         setText(tmp1 + str + tmp2);
501       }
502   }
503 
504   /**
505    * Replace a range of characters with the specified text.  The
506    * character at the start position will be replaced, unless start ==
507    * end.  The character at the end posistion will not be replaced.
508    * The first character in the text area is at position zero.  The
509    * length of the replacement text may differ from the length of the
510    * text that is replaced.
511    *
512    * @param str The new text for the range.
513    * @param start The start position of the replacement range.
514    * @param end The end position of the replacement range.
515    */
replaceRange(String str, int start, int end)516   public void replaceRange (String str, int start, int end)
517   {
518     replaceText (str, start, end);
519   }
520 
521   /**
522    * Replace a range of characters with the specified text.  The
523    * character at the start position will be replaced, unless start ==
524    * end.  The character at the end posistion will not be replaced.
525    * The first character in the text area is at position zero.  The
526    * length of the replacement text may differ from the length of the
527    * text that is replaced.
528    *
529    * @param str The new text for the range.
530    * @param start The start position of the replacement range.
531    * @param end The end position of the replacement range.
532    *
533    * @deprecated This method is deprecated in favor of
534    * <code>replaceRange ()</code>.
535    */
replaceText(String str, int start, int end)536   public void replaceText (String str, int start, int end)
537   {
538     String tmp1 = null;
539     String tmp2 = null;
540 
541     TextAreaPeer peer = (TextAreaPeer) getPeer();
542 
543     if (peer != null)
544       peer.replaceRange(str, start, end);
545     else
546       {
547         tmp1 = getText().substring(0, start);
548         tmp2 = getText().substring(end, getText().length());
549         setText(tmp1 + str + tmp2);
550       }
551   }
552 
553   /**
554    * Retrieve a debugging string for this text area.
555    *
556    * @return A debugging string for this text area.
557    */
paramString()558   protected String paramString ()
559   {
560     String sbVisibility = "";
561 
562     switch (scrollbarVisibility)
563       {
564       case SCROLLBARS_BOTH:
565         sbVisibility = "both";
566         break;
567       case SCROLLBARS_VERTICAL_ONLY:
568         sbVisibility = "vertical-only";
569         break;
570       case SCROLLBARS_HORIZONTAL_ONLY:
571         sbVisibility = "horizontal-only";
572         break;
573       case SCROLLBARS_NONE:
574         sbVisibility = "none";
575         break;
576       }
577 
578     String editable = "";
579     if (isEditable ())
580       editable = "editable,";
581 
582     return getName () + "," + getX () + "," + getY () + "," + getWidth ()
583            + "x" + getHeight () + "," + "text=" + getText () + "," + editable
584            + "selection=" + getSelectionStart () + "-" + getSelectionEnd ()
585            + ",rows=" + rows + ",columns=" + columns + ",scrollbarVisibility="
586            + sbVisibility;
587   }
588 
589   /**
590    * Generate a unique name for this text area.
591    *
592    * @return A unique name for this text area.
593    */
generateName()594   String generateName ()
595   {
596     return "text" + getUniqueLong ();
597   }
598 
getUniqueLong()599   private static synchronized long getUniqueLong ()
600   {
601     return next_text_number++;
602   }
603 
604   protected class AccessibleAWTTextArea extends AccessibleAWTTextComponent
605   {
606     private static final long serialVersionUID = 3472827823632144419L;
607 
AccessibleAWTTextArea()608     protected AccessibleAWTTextArea()
609     {
610     }
611 
getAccessibleStateSet()612     public AccessibleStateSet getAccessibleStateSet()
613     {
614       return super.getAccessibleStateSet();
615     }
616   }
617 
618   /**
619    * Gets the AccessibleContext associated with this <code>TextArea</code>.
620    * The context is created, if necessary.
621    *
622    * @return the associated context
623    */
getAccessibleContext()624   public AccessibleContext getAccessibleContext()
625   {
626     /* Create the context if this is the first request */
627     if (accessibleContext == null)
628       accessibleContext = new AccessibleAWTTextArea();
629     return accessibleContext;
630   }
631 }
632