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