1 /* 2 * Copyright (c) 1995, 2006, 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 * ALIGN=center HSPACE=10 VSPACE=7> 46 * <p> 47 * This text area could be created by the following line of code: 48 * <p> 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 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()); 147 backwardTraversalKeys = KeyboardFocusManager.initFocusTraversalKeysSet( 148 "ctrl shift TAB", 149 new HashSet()); 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 }