001 /* TextArea.java -- A multi-line text entry component
002 Copyright (C) 1999, 2004 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package java.awt;
040
041 import java.awt.event.KeyEvent;
042 import java.awt.peer.ComponentPeer;
043 import java.awt.peer.TextAreaPeer;
044 import java.util.HashSet;
045 import java.util.Set;
046
047 import javax.accessibility.AccessibleContext;
048 import javax.accessibility.AccessibleStateSet;
049
050
051 /**
052 * A TextArea is a text component capable of displaying multiple lines
053 * of user-editable text. A TextArea handles its own scrolling and
054 * can display vertical and horizontal scrollbars as navigation aids.
055 *
056 * @author Aaron M. Renn (arenn@urbanophile.com)
057 */
058 public class TextArea extends TextComponent implements java.io.Serializable
059 {
060 /**
061 * Display both horiztonal and vertical scroll bars.
062 */
063 public static final int SCROLLBARS_BOTH = 0;
064
065 /**
066 * Display vertical scroll bar only.
067 */
068 public static final int SCROLLBARS_VERTICAL_ONLY = 1;
069
070 /**
071 * Display horizatonal scroll bar only.
072 */
073 public static final int SCROLLBARS_HORIZONTAL_ONLY = 2;
074
075 /**
076 * Do not display scrollbars.
077 */
078 public static final int SCROLLBARS_NONE = 3;
079
080 /**
081 * Serialization constant.
082 */
083 private static final long serialVersionUID = 3692302836626095722L;
084
085 /**
086 * @serial The number of columns used in this text area's preferred
087 * and minimum size calculations.
088 */
089 private int columns;
090
091 /**
092 * @serial The number of rows used in this text area's preferred and
093 * minimum size calculations.
094 */
095 private int rows;
096
097 /**
098 * @serial The scrollbar display policy. One of SCROLLBARS_BOTH,
099 * 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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
423 public int getScrollbarVisibility ()
424 {
425 return scrollbarVisibility;
426 }
427
428 /**
429 * Notify this object that it should create its native peer.
430 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
594 String generateName ()
595 {
596 return "text" + getUniqueLong ();
597 }
598
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
608 protected AccessibleAWTTextArea()
609 {
610 }
611
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 */
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 }