1 /* 2 * Copyright (c) 1995, 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 java.awt; 26 27 import java.awt.peer.TextAreaPeer; 28 import java.io.IOException; 29 import java.io.ObjectInputStream; 30 import java.util.HashSet; 31 import java.util.Set; 32 33 import javax.accessibility.AccessibleContext; 34 import javax.accessibility.AccessibleState; 35 import javax.accessibility.AccessibleStateSet; 36 37 /** 38 * A {@code TextArea} 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 * 53 * @author Sami Shaio 54 * @since 1.0 55 */ 56 public class TextArea extends TextComponent { 57 58 /** 59 * The number of rows in the {@code TextArea}. 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}. 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 1.1 88 */ 89 public static final int SCROLLBARS_BOTH = 0; 90 91 /** 92 * Create and display vertical scrollbar only. 93 * @since 1.1 94 */ 95 public static final int SCROLLBARS_VERTICAL_ONLY = 1; 96 97 /** 98 * Create and display horizontal scrollbar only. 99 * @since 1.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 1.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} = both scrollbars.<BR> 113 * {@code SCROLLBARS_HORIZONTAL_ONLY} = Horizontal bar only.<BR> 114 * {@code SCROLLBARS_VERTICAL_ONLY} = Vertical bar only.<BR> 115 * {@code SCROLLBARS_NONE} = 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} 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} is {@code null}, the empty 172 * string {@code ""} will be displayed 173 * @exception HeadlessException if 174 * {@code GraphicsEnvironment.isHeadless} 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} 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} is {@code null}, the empty 209 * string {@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} 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} constructors defer to 225 * this one. 226 * <p> 227 * The {@code TextArea} class defines several constants 228 * that can be supplied as values for the 229 * {@code scrollbars} argument: 230 * <ul> 231 * <li>{@code SCROLLBARS_BOTH}, 232 * <li>{@code SCROLLBARS_VERTICAL_ONLY}, 233 * <li>{@code SCROLLBARS_HORIZONTAL_ONLY}, 234 * <li>{@code SCROLLBARS_NONE}. 235 * </ul> 236 * Any other value for the 237 * {@code scrollbars} 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} is {@code null}, the empty 242 * string {@code ""} will be displayed 243 * @param rows the number of rows; if 244 * {@code rows} is less than {@code 0}, 245 * {@code rows} is set to {@code 0} 246 * @param columns the number of columns; if 247 * {@code columns} is less than {@code 0}, 248 * {@code columns} is set to {@code 0} 249 * @param scrollbars a constant that determines what 250 * scrollbars are created to view the text area 251 * @since 1.1 252 * @exception HeadlessException if 253 * {@code GraphicsEnvironment.isHeadless} 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} 277 * when the name is {@code null}. 278 */ 279 String constructComponentName() { 280 synchronized (TextArea.class) { 281 return base + nameCounter++; 282 } 283 } 284 285 /** 286 * Creates the {@code TextArea}'s peer. The peer allows us to modify 287 * the appearance of the {@code TextArea} without changing any of its 288 * functionality. 289 */ 290 public void addNotify() { 291 synchronized (getTreeLock()) { 292 if (peer == null) 293 peer = getComponentFactory().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} or inconsistent 302 * parameters is invalid and will result in unspecified 303 * behavior. 304 * 305 * @param str the non-{@code null} 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 1.1 311 */ 312 public void insert(String str, int pos) { 313 insertText(str, pos); 314 } 315 316 /** 317 * Inserts the specified text at the specified position 318 * in this text area. 319 * 320 * @param str the non-{@code null} text to insert 321 * @param pos the position at which to insert 322 * @deprecated As of JDK version 1.1, 323 * replaced by {@code insert(String, int)}. 324 */ 325 @Deprecated 326 public synchronized void insertText(String str, int pos) { 327 TextAreaPeer peer = (TextAreaPeer)this.peer; 328 if (peer != null) { 329 peer.insert(str, pos); 330 } 331 text = text.substring(0, pos) + str + text.substring(pos); 332 } 333 334 /** 335 * Appends the given text to the text area's current text. 336 * <p>Note that passing {@code null} or inconsistent 337 * parameters is invalid and will result in unspecified 338 * behavior. 339 * 340 * @param str the non-{@code null} text to append 341 * @see java.awt.TextArea#insert 342 * @since 1.1 343 */ 344 public void append(String str) { 345 appendText(str); 346 } 347 348 /** 349 * Appends the given text to the text area's current text. 350 * 351 * @param str the text to append 352 * @deprecated As of JDK version 1.1, 353 * replaced by {@code append(String)}. 354 */ 355 @Deprecated 356 public synchronized void appendText(String str) { 357 insertText(str, getText().length()); 358 } 359 360 /** 361 * Replaces text between the indicated start and end positions 362 * with the specified replacement text. The text at the end 363 * position will not be replaced. The text at the start 364 * position will be replaced (unless the start position is the 365 * same as the end position). 366 * The text position is zero-based. The inserted substring may be 367 * of a different length than the text it replaces. 368 * <p>Note that passing {@code null} or inconsistent 369 * parameters is invalid and will result in unspecified 370 * behavior. 371 * 372 * @param str the non-{@code null} text to use as 373 * the replacement 374 * @param start the start position 375 * @param end the end position 376 * @see java.awt.TextArea#insert 377 * @since 1.1 378 */ 379 public void replaceRange(String str, int start, int end) { 380 replaceText(str, start, end); 381 } 382 383 /** 384 * Replaces a range of characters between 385 * the indicated start and end positions 386 * with the specified replacement text (the text at the end 387 * position will not be replaced). 388 * 389 * @param str the non-{@code null} text to use as 390 * the replacement 391 * @param start the start position 392 * @param end the end position 393 * @deprecated As of JDK version 1.1, 394 * replaced by {@code replaceRange(String, int, int)}. 395 */ 396 @Deprecated 397 public synchronized void replaceText(String str, int start, int end) { 398 TextAreaPeer peer = (TextAreaPeer)this.peer; 399 if (peer != null) { 400 peer.replaceRange(str, start, end); 401 } 402 text = text.substring(0, start) + str + text.substring(end); 403 } 404 405 /** 406 * Returns the number of rows in the text area. 407 * @return the number of rows in the text area 408 * @see #setRows(int) 409 * @see #getColumns() 410 * @since 1.0 411 */ 412 public int getRows() { 413 return rows; 414 } 415 416 /** 417 * Sets the number of rows for this text area. 418 * @param rows the number of rows 419 * @see #getRows() 420 * @see #setColumns(int) 421 * @exception IllegalArgumentException if the value 422 * supplied for {@code rows} 423 * is less than {@code 0} 424 * @since 1.1 425 */ 426 public void setRows(int rows) { 427 int oldVal = this.rows; 428 if (rows < 0) { 429 throw new IllegalArgumentException("rows less than zero."); 430 } 431 if (rows != oldVal) { 432 this.rows = rows; 433 invalidate(); 434 } 435 } 436 437 /** 438 * Returns the number of columns in this text area. 439 * @return the number of columns in the text area 440 * @see #setColumns(int) 441 * @see #getRows() 442 */ 443 public int getColumns() { 444 return columns; 445 } 446 447 /** 448 * Sets the number of columns for this text area. 449 * @param columns the number of columns 450 * @see #getColumns() 451 * @see #setRows(int) 452 * @exception IllegalArgumentException if the value 453 * supplied for {@code columns} 454 * is less than {@code 0} 455 * @since 1.1 456 */ 457 public void setColumns(int columns) { 458 int oldVal = this.columns; 459 if (columns < 0) { 460 throw new IllegalArgumentException("columns less than zero."); 461 } 462 if (columns != oldVal) { 463 this.columns = columns; 464 invalidate(); 465 } 466 } 467 468 /** 469 * Returns an enumerated value that indicates which scroll bars 470 * the text area uses. 471 * <p> 472 * The {@code TextArea} class defines four integer constants 473 * that are used to specify which scroll bars are available. 474 * {@code TextArea} has one constructor that gives the 475 * application discretion over scroll bars. 476 * 477 * @return an integer that indicates which scroll bars are used 478 * @see java.awt.TextArea#SCROLLBARS_BOTH 479 * @see java.awt.TextArea#SCROLLBARS_VERTICAL_ONLY 480 * @see java.awt.TextArea#SCROLLBARS_HORIZONTAL_ONLY 481 * @see java.awt.TextArea#SCROLLBARS_NONE 482 * @see java.awt.TextArea#TextArea(java.lang.String, int, int, int) 483 * @since 1.1 484 */ 485 public int getScrollbarVisibility() { 486 return scrollbarVisibility; 487 } 488 489 490 /** 491 * Determines the preferred size of a text area with the specified 492 * number of rows and columns. 493 * @param rows the number of rows 494 * @param columns the number of columns 495 * @return the preferred dimensions required to display 496 * the text area with the specified 497 * number of rows and columns 498 * @see java.awt.Component#getPreferredSize 499 * @since 1.1 500 */ 501 public Dimension getPreferredSize(int rows, int columns) { 502 return preferredSize(rows, columns); 503 } 504 505 /** 506 * Determines the preferred size of the text area with the specified 507 * number of rows and columns. 508 * 509 * @param rows the number of rows 510 * @param columns the number of columns 511 * @return the preferred dimensions needed for the text area 512 * @deprecated As of JDK version 1.1, 513 * replaced by {@code getPreferredSize(int, int)}. 514 */ 515 @Deprecated 516 public Dimension preferredSize(int rows, int columns) { 517 synchronized (getTreeLock()) { 518 TextAreaPeer peer = (TextAreaPeer)this.peer; 519 return (peer != null) ? 520 peer.getPreferredSize(rows, columns) : 521 super.preferredSize(); 522 } 523 } 524 525 /** 526 * Determines the preferred size of this text area. 527 * @return the preferred dimensions needed for this text area 528 * @see java.awt.Component#getPreferredSize 529 * @since 1.1 530 */ 531 public Dimension getPreferredSize() { 532 return preferredSize(); 533 } 534 535 /** 536 * @deprecated As of JDK version 1.1, 537 * replaced by {@code getPreferredSize()}. 538 */ 539 @Deprecated 540 public Dimension preferredSize() { 541 synchronized (getTreeLock()) { 542 return ((rows > 0) && (columns > 0)) ? 543 preferredSize(rows, columns) : 544 super.preferredSize(); 545 } 546 } 547 548 /** 549 * Determines the minimum size of a text area with the specified 550 * number of rows and columns. 551 * @param rows the number of rows 552 * @param columns the number of columns 553 * @return the minimum dimensions required to display 554 * the text area with the specified 555 * number of rows and columns 556 * @see java.awt.Component#getMinimumSize 557 * @since 1.1 558 */ 559 public Dimension getMinimumSize(int rows, int columns) { 560 return minimumSize(rows, columns); 561 } 562 563 /** 564 * Determines the minimum size of the text area with the specified 565 * number of rows and columns. 566 * 567 * @param rows the number of rows 568 * @param columns the number of columns 569 * @return the minimum size for the text area 570 * @deprecated As of JDK version 1.1, 571 * replaced by {@code getMinimumSize(int, int)}. 572 */ 573 @Deprecated 574 public Dimension minimumSize(int rows, int columns) { 575 synchronized (getTreeLock()) { 576 TextAreaPeer peer = (TextAreaPeer)this.peer; 577 return (peer != null) ? 578 peer.getMinimumSize(rows, columns) : 579 super.minimumSize(); 580 } 581 } 582 583 /** 584 * Determines the minimum size of this text area. 585 * @return the preferred dimensions needed for this text area 586 * @see java.awt.Component#getPreferredSize 587 * @since 1.1 588 */ 589 public Dimension getMinimumSize() { 590 return minimumSize(); 591 } 592 593 /** 594 * @deprecated As of JDK version 1.1, 595 * replaced by {@code getMinimumSize()}. 596 */ 597 @Deprecated 598 public Dimension minimumSize() { 599 synchronized (getTreeLock()) { 600 return ((rows > 0) && (columns > 0)) ? 601 minimumSize(rows, columns) : 602 super.minimumSize(); 603 } 604 } 605 606 /** 607 * Returns a string representing the state of this {@code TextArea}. 608 * This method is intended to be used only for debugging purposes, and the 609 * content and format of the returned string may vary between 610 * implementations. The returned string may be empty but may not be 611 * {@code null}. 612 * 613 * @return the parameter string of this text area 614 */ 615 protected String paramString() { 616 String sbVisStr; 617 switch (scrollbarVisibility) { 618 case SCROLLBARS_BOTH: 619 sbVisStr = "both"; 620 break; 621 case SCROLLBARS_VERTICAL_ONLY: 622 sbVisStr = "vertical-only"; 623 break; 624 case SCROLLBARS_HORIZONTAL_ONLY: 625 sbVisStr = "horizontal-only"; 626 break; 627 case SCROLLBARS_NONE: 628 sbVisStr = "none"; 629 break; 630 default: 631 sbVisStr = "invalid display policy"; 632 } 633 634 return super.paramString() + ",rows=" + rows + 635 ",columns=" + columns + 636 ",scrollbarVisibility=" + sbVisStr; 637 } 638 639 640 /* 641 * Serialization support. 642 */ 643 /** 644 * The textArea Serialized Data Version. 645 * 646 * @serial 647 */ 648 private int textAreaSerializedDataVersion = 2; 649 650 /** 651 * Read the ObjectInputStream. 652 * @exception HeadlessException if 653 * {@code GraphicsEnvironment.isHeadless()} returns 654 * {@code true} 655 * @see java.awt.GraphicsEnvironment#isHeadless 656 */ 657 private void readObject(ObjectInputStream s) 658 throws ClassNotFoundException, IOException, HeadlessException 659 { 660 // HeadlessException will be thrown by TextComponent's readObject 661 s.defaultReadObject(); 662 663 // Make sure the state we just read in for columns, rows, 664 // and scrollbarVisibility has legal values 665 if (columns < 0) { 666 columns = 0; 667 } 668 if (rows < 0) { 669 rows = 0; 670 } 671 672 if ((scrollbarVisibility < SCROLLBARS_BOTH) || 673 (scrollbarVisibility > SCROLLBARS_NONE)) { 674 this.scrollbarVisibility = SCROLLBARS_BOTH; 675 } 676 677 if (textAreaSerializedDataVersion < 2) { 678 setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 679 forwardTraversalKeys); 680 setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 681 backwardTraversalKeys); 682 } 683 } 684 685 686 ///////////////// 687 // Accessibility support 688 //////////////// 689 690 691 /** 692 * Returns the {@code AccessibleContext} associated with 693 * this {@code TextArea}. For text areas, the 694 * {@code AccessibleContext} takes the form of an 695 * {@code AccessibleAWTTextArea}. 696 * A new {@code AccessibleAWTTextArea} instance is created if necessary. 697 * 698 * @return an {@code AccessibleAWTTextArea} that serves as the 699 * {@code AccessibleContext} of this {@code TextArea} 700 * @since 1.3 701 */ 702 public AccessibleContext getAccessibleContext() { 703 if (accessibleContext == null) { 704 accessibleContext = new AccessibleAWTTextArea(); 705 } 706 return accessibleContext; 707 } 708 709 /** 710 * This class implements accessibility support for the 711 * {@code TextArea} class. It provides an implementation of the 712 * Java Accessibility API appropriate to text area user-interface elements. 713 * @since 1.3 714 */ 715 protected class AccessibleAWTTextArea extends AccessibleAWTTextComponent 716 { 717 /* 718 * JDK 1.3 serialVersionUID 719 */ 720 private static final long serialVersionUID = 3472827823632144419L; 721 722 /** 723 * Gets the state set of this object. 724 * 725 * @return an instance of AccessibleStateSet describing the states 726 * of the object 727 * @see AccessibleStateSet 728 */ 729 public AccessibleStateSet getAccessibleStateSet() { 730 AccessibleStateSet states = super.getAccessibleStateSet(); 731 states.add(AccessibleState.MULTI_LINE); 732 return states; 733 } 734 } 735 736 737 }