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