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