1 /* 2 * Copyright (c) 1995, 2013, 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.TextComponentPeer; 28 import java.awt.event.*; 29 import java.util.EventListener; 30 import java.io.ObjectOutputStream; 31 import java.io.ObjectInputStream; 32 import java.io.IOException; 33 import java.text.BreakIterator; 34 import javax.swing.text.AttributeSet; 35 import javax.accessibility.*; 36 import java.awt.im.InputMethodRequests; 37 import sun.awt.AWTPermissions; 38 import sun.awt.InputMethodSupport; 39 40 /** 41 * The <code>TextComponent</code> class is the superclass of 42 * any component that allows the editing of some text. 43 * <p> 44 * A text component embodies a string of text. The 45 * <code>TextComponent</code> class defines a set of methods 46 * that determine whether or not this text is editable. If the 47 * component is editable, it defines another set of methods 48 * that supports a text insertion caret. 49 * <p> 50 * In addition, the class defines methods that are used 51 * to maintain a current <em>selection</em> from the text. 52 * The text selection, a substring of the component's text, 53 * is the target of editing operations. It is also referred 54 * to as the <em>selected text</em>. 55 * 56 * @author Sami Shaio 57 * @author Arthur van Hoff 58 * @since JDK1.0 59 */ 60 public class TextComponent extends Component implements Accessible { 61 62 /** 63 * The value of the text. 64 * A <code>null</code> value is the same as "". 65 * 66 * @serial 67 * @see #setText(String) 68 * @see #getText() 69 */ 70 String text; 71 72 /** 73 * A boolean indicating whether or not this 74 * <code>TextComponent</code> is editable. 75 * It will be <code>true</code> if the text component 76 * is editable and <code>false</code> if not. 77 * 78 * @serial 79 * @see #isEditable() 80 */ 81 boolean editable = true; 82 83 /** 84 * The selection refers to the selected text, and the 85 * <code>selectionStart</code> is the start position 86 * of the selected text. 87 * 88 * @serial 89 * @see #getSelectionStart() 90 * @see #setSelectionStart(int) 91 */ 92 int selectionStart; 93 94 /** 95 * The selection refers to the selected text, and the 96 * <code>selectionEnd</code> 97 * is the end position of the selected text. 98 * 99 * @serial 100 * @see #getSelectionEnd() 101 * @see #setSelectionEnd(int) 102 */ 103 int selectionEnd; 104 105 // A flag used to tell whether the background has been set by 106 // developer code (as opposed to AWT code). Used to determine 107 // the background color of non-editable TextComponents. 108 boolean backgroundSetByClientCode = false; 109 110 transient protected TextListener textListener; 111 112 /* 113 * JDK 1.1 serialVersionUID 114 */ 115 private static final long serialVersionUID = -2214773872412987419L; 116 117 /** 118 * Constructs a new text component initialized with the 119 * specified text. Sets the value of the cursor to 120 * <code>Cursor.TEXT_CURSOR</code>. 121 * @param text the text to be displayed; if 122 * <code>text</code> is <code>null</code>, the empty 123 * string <code>""</code> will be displayed 124 * @exception HeadlessException if 125 * <code>GraphicsEnvironment.isHeadless</code> 126 * returns true 127 * @see java.awt.GraphicsEnvironment#isHeadless 128 * @see java.awt.Cursor 129 */ 130 TextComponent(String text) throws HeadlessException { 131 GraphicsEnvironment.checkHeadless(); 132 this.text = (text != null) ? text : ""; 133 setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); 134 } 135 136 private void enableInputMethodsIfNecessary() { 137 if (checkForEnableIM) { 138 checkForEnableIM = false; 139 try { 140 Toolkit toolkit = Toolkit.getDefaultToolkit(); 141 boolean shouldEnable = false; 142 if (toolkit instanceof InputMethodSupport) { 143 shouldEnable = ((InputMethodSupport)toolkit) 144 .enableInputMethodsForTextComponent(); 145 } 146 enableInputMethods(shouldEnable); 147 } catch (Exception e) { 148 // if something bad happens, just don't enable input methods 149 } 150 } 151 } 152 153 /** 154 * Enables or disables input method support for this text component. If input 155 * method support is enabled and the text component also processes key events, 156 * incoming events are offered to the current input method and will only be 157 * processed by the component or dispatched to its listeners if the input method 158 * does not consume them. Whether and how input method support for this text 159 * component is enabled or disabled by default is implementation dependent. 160 * 161 * @param enable true to enable, false to disable 162 * @see #processKeyEvent 163 * @since 1.2 164 */ 165 public void enableInputMethods(boolean enable) { 166 checkForEnableIM = false; 167 super.enableInputMethods(enable); 168 } 169 170 boolean areInputMethodsEnabled() { 171 // moved from the constructor above to here and addNotify below, 172 // this call will initialize the toolkit if not already initialized. 173 if (checkForEnableIM) { 174 enableInputMethodsIfNecessary(); 175 } 176 177 // TextComponent handles key events without touching the eventMask or 178 // having a key listener, so just check whether the flag is set 179 return (eventMask & AWTEvent.INPUT_METHODS_ENABLED_MASK) != 0; 180 } 181 182 public InputMethodRequests getInputMethodRequests() { 183 TextComponentPeer peer = (TextComponentPeer)this.peer; 184 if (peer != null) return peer.getInputMethodRequests(); 185 else return null; 186 } 187 188 189 190 /** 191 * Makes this Component displayable by connecting it to a 192 * native screen resource. 193 * This method is called internally by the toolkit and should 194 * not be called directly by programs. 195 * @see java.awt.TextComponent#removeNotify 196 */ 197 public void addNotify() { 198 super.addNotify(); 199 enableInputMethodsIfNecessary(); 200 } 201 202 /** 203 * Removes the <code>TextComponent</code>'s peer. 204 * The peer allows us to modify the appearance of the 205 * <code>TextComponent</code> without changing its 206 * functionality. 207 */ 208 public void removeNotify() { 209 synchronized (getTreeLock()) { 210 TextComponentPeer peer = (TextComponentPeer)this.peer; 211 if (peer != null) { 212 text = peer.getText(); 213 selectionStart = peer.getSelectionStart(); 214 selectionEnd = peer.getSelectionEnd(); 215 } 216 super.removeNotify(); 217 } 218 } 219 220 /** 221 * Sets the text that is presented by this 222 * text component to be the specified text. 223 * @param t the new text; 224 * if this parameter is <code>null</code> then 225 * the text is set to the empty string "" 226 * @see java.awt.TextComponent#getText 227 */ 228 public synchronized void setText(String t) { 229 boolean skipTextEvent = (text == null || text.isEmpty()) 230 && (t == null || t.isEmpty()); 231 text = (t != null) ? t : ""; 232 TextComponentPeer peer = (TextComponentPeer)this.peer; 233 // Please note that we do not want to post an event 234 // if TextArea.setText() or TextField.setText() replaces an empty text 235 // by an empty text, that is, if component's text remains unchanged. 236 if (peer != null && !skipTextEvent) { 237 peer.setText(text); 238 } 239 } 240 241 /** 242 * Returns the text that is presented by this text component. 243 * By default, this is an empty string. 244 * 245 * @return the value of this <code>TextComponent</code> 246 * @see java.awt.TextComponent#setText 247 */ 248 public synchronized String getText() { 249 TextComponentPeer peer = (TextComponentPeer)this.peer; 250 if (peer != null) { 251 text = peer.getText(); 252 } 253 return text; 254 } 255 256 /** 257 * Returns the selected text from the text that is 258 * presented by this text component. 259 * @return the selected text of this text component 260 * @see java.awt.TextComponent#select 261 */ 262 public synchronized String getSelectedText() { 263 return getText().substring(getSelectionStart(), getSelectionEnd()); 264 } 265 266 /** 267 * Indicates whether or not this text component is editable. 268 * @return <code>true</code> if this text component is 269 * editable; <code>false</code> otherwise. 270 * @see java.awt.TextComponent#setEditable 271 * @since JDK1.0 272 */ 273 public boolean isEditable() { 274 return editable; 275 } 276 277 /** 278 * Sets the flag that determines whether or not this 279 * text component is editable. 280 * <p> 281 * If the flag is set to <code>true</code>, this text component 282 * becomes user editable. If the flag is set to <code>false</code>, 283 * the user cannot change the text of this text component. 284 * By default, non-editable text components have a background color 285 * of SystemColor.control. This default can be overridden by 286 * calling setBackground. 287 * 288 * @param b a flag indicating whether this text component 289 * is user editable. 290 * @see java.awt.TextComponent#isEditable 291 * @since JDK1.0 292 */ 293 public synchronized void setEditable(boolean b) { 294 if (editable == b) { 295 return; 296 } 297 298 editable = b; 299 TextComponentPeer peer = (TextComponentPeer)this.peer; 300 if (peer != null) { 301 peer.setEditable(b); 302 } 303 } 304 305 /** 306 * Gets the background color of this text component. 307 * 308 * By default, non-editable text components have a background color 309 * of SystemColor.control. This default can be overridden by 310 * calling setBackground. 311 * 312 * @return This text component's background color. 313 * If this text component does not have a background color, 314 * the background color of its parent is returned. 315 * @see #setBackground(Color) 316 * @since JDK1.0 317 */ 318 public Color getBackground() { 319 if (!editable && !backgroundSetByClientCode) { 320 return SystemColor.control; 321 } 322 323 return super.getBackground(); 324 } 325 326 /** 327 * Sets the background color of this text component. 328 * 329 * @param c The color to become this text component's color. 330 * If this parameter is null then this text component 331 * will inherit the background color of its parent. 332 * @see #getBackground() 333 * @since JDK1.0 334 */ 335 public void setBackground(Color c) { 336 backgroundSetByClientCode = true; 337 super.setBackground(c); 338 } 339 340 /** 341 * Gets the start position of the selected text in 342 * this text component. 343 * @return the start position of the selected text 344 * @see java.awt.TextComponent#setSelectionStart 345 * @see java.awt.TextComponent#getSelectionEnd 346 */ 347 public synchronized int getSelectionStart() { 348 TextComponentPeer peer = (TextComponentPeer)this.peer; 349 if (peer != null) { 350 selectionStart = peer.getSelectionStart(); 351 } 352 return selectionStart; 353 } 354 355 /** 356 * Sets the selection start for this text component to 357 * the specified position. The new start point is constrained 358 * to be at or before the current selection end. It also 359 * cannot be set to less than zero, the beginning of the 360 * component's text. 361 * If the caller supplies a value for <code>selectionStart</code> 362 * that is out of bounds, the method enforces these constraints 363 * silently, and without failure. 364 * @param selectionStart the start position of the 365 * selected text 366 * @see java.awt.TextComponent#getSelectionStart 367 * @see java.awt.TextComponent#setSelectionEnd 368 * @since JDK1.1 369 */ 370 public synchronized void setSelectionStart(int selectionStart) { 371 /* Route through select method to enforce consistent policy 372 * between selectionStart and selectionEnd. 373 */ 374 select(selectionStart, getSelectionEnd()); 375 } 376 377 /** 378 * Gets the end position of the selected text in 379 * this text component. 380 * @return the end position of the selected text 381 * @see java.awt.TextComponent#setSelectionEnd 382 * @see java.awt.TextComponent#getSelectionStart 383 */ 384 public synchronized int getSelectionEnd() { 385 TextComponentPeer peer = (TextComponentPeer)this.peer; 386 if (peer != null) { 387 selectionEnd = peer.getSelectionEnd(); 388 } 389 return selectionEnd; 390 } 391 392 /** 393 * Sets the selection end for this text component to 394 * the specified position. The new end point is constrained 395 * to be at or after the current selection start. It also 396 * cannot be set beyond the end of the component's text. 397 * If the caller supplies a value for <code>selectionEnd</code> 398 * that is out of bounds, the method enforces these constraints 399 * silently, and without failure. 400 * @param selectionEnd the end position of the 401 * selected text 402 * @see java.awt.TextComponent#getSelectionEnd 403 * @see java.awt.TextComponent#setSelectionStart 404 * @since JDK1.1 405 */ 406 public synchronized void setSelectionEnd(int selectionEnd) { 407 /* Route through select method to enforce consistent policy 408 * between selectionStart and selectionEnd. 409 */ 410 select(getSelectionStart(), selectionEnd); 411 } 412 413 /** 414 * Selects the text between the specified start and end positions. 415 * <p> 416 * This method sets the start and end positions of the 417 * selected text, enforcing the restriction that the start position 418 * must be greater than or equal to zero. The end position must be 419 * greater than or equal to the start position, and less than or 420 * equal to the length of the text component's text. The 421 * character positions are indexed starting with zero. 422 * The length of the selection is 423 * <code>endPosition</code> - <code>startPosition</code>, so the 424 * character at <code>endPosition</code> is not selected. 425 * If the start and end positions of the selected text are equal, 426 * all text is deselected. 427 * <p> 428 * If the caller supplies values that are inconsistent or out of 429 * bounds, the method enforces these constraints silently, and 430 * without failure. Specifically, if the start position or end 431 * position is greater than the length of the text, it is reset to 432 * equal the text length. If the start position is less than zero, 433 * it is reset to zero, and if the end position is less than the 434 * start position, it is reset to the start position. 435 * 436 * @param selectionStart the zero-based index of the first 437 character (<code>char</code> value) to be selected 438 * @param selectionEnd the zero-based end position of the 439 text to be selected; the character (<code>char</code> value) at 440 <code>selectionEnd</code> is not selected 441 * @see java.awt.TextComponent#setSelectionStart 442 * @see java.awt.TextComponent#setSelectionEnd 443 * @see java.awt.TextComponent#selectAll 444 */ 445 public synchronized void select(int selectionStart, int selectionEnd) { 446 String text = getText(); 447 if (selectionStart < 0) { 448 selectionStart = 0; 449 } 450 if (selectionStart > text.length()) { 451 selectionStart = text.length(); 452 } 453 if (selectionEnd > text.length()) { 454 selectionEnd = text.length(); 455 } 456 if (selectionEnd < selectionStart) { 457 selectionEnd = selectionStart; 458 } 459 460 this.selectionStart = selectionStart; 461 this.selectionEnd = selectionEnd; 462 463 TextComponentPeer peer = (TextComponentPeer)this.peer; 464 if (peer != null) { 465 peer.select(selectionStart, selectionEnd); 466 } 467 } 468 469 /** 470 * Selects all the text in this text component. 471 * @see java.awt.TextComponent#select 472 */ 473 public synchronized void selectAll() { 474 this.selectionStart = 0; 475 this.selectionEnd = getText().length(); 476 477 TextComponentPeer peer = (TextComponentPeer)this.peer; 478 if (peer != null) { 479 peer.select(selectionStart, selectionEnd); 480 } 481 } 482 483 /** 484 * Sets the position of the text insertion caret. 485 * The caret position is constrained to be between 0 486 * and the last character of the text, inclusive. 487 * If the passed-in value is greater than this range, 488 * the value is set to the last character (or 0 if 489 * the <code>TextComponent</code> contains no text) 490 * and no error is returned. If the passed-in value is 491 * less than 0, an <code>IllegalArgumentException</code> 492 * is thrown. 493 * 494 * @param position the position of the text insertion caret 495 * @exception IllegalArgumentException if <code>position</code> 496 * is less than zero 497 * @since JDK1.1 498 */ 499 public synchronized void setCaretPosition(int position) { 500 if (position < 0) { 501 throw new IllegalArgumentException("position less than zero."); 502 } 503 504 int maxposition = getText().length(); 505 if (position > maxposition) { 506 position = maxposition; 507 } 508 509 TextComponentPeer peer = (TextComponentPeer)this.peer; 510 if (peer != null) { 511 peer.setCaretPosition(position); 512 } else { 513 select(position, position); 514 } 515 } 516 517 /** 518 * Returns the position of the text insertion caret. 519 * The caret position is constrained to be between 0 520 * and the last character of the text, inclusive. 521 * If the text or caret have not been set, the default 522 * caret position is 0. 523 * 524 * @return the position of the text insertion caret 525 * @see #setCaretPosition(int) 526 * @since JDK1.1 527 */ 528 public synchronized int getCaretPosition() { 529 TextComponentPeer peer = (TextComponentPeer)this.peer; 530 int position = 0; 531 532 if (peer != null) { 533 position = peer.getCaretPosition(); 534 } else { 535 position = selectionStart; 536 } 537 int maxposition = getText().length(); 538 if (position > maxposition) { 539 position = maxposition; 540 } 541 return position; 542 } 543 544 /** 545 * Adds the specified text event listener to receive text events 546 * from this text component. 547 * If <code>l</code> is <code>null</code>, no exception is 548 * thrown and no action is performed. 549 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads" 550 * >AWT Threading Issues</a> for details on AWT's threading model. 551 * 552 * @param l the text event listener 553 * @see #removeTextListener 554 * @see #getTextListeners 555 * @see java.awt.event.TextListener 556 */ 557 public synchronized void addTextListener(TextListener l) { 558 if (l == null) { 559 return; 560 } 561 textListener = AWTEventMulticaster.add(textListener, l); 562 newEventsOnly = true; 563 } 564 565 /** 566 * Removes the specified text event listener so that it no longer 567 * receives text events from this text component 568 * If <code>l</code> is <code>null</code>, no exception is 569 * thrown and no action is performed. 570 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads" 571 * >AWT Threading Issues</a> for details on AWT's threading model. 572 * 573 * @param l the text listener 574 * @see #addTextListener 575 * @see #getTextListeners 576 * @see java.awt.event.TextListener 577 * @since JDK1.1 578 */ 579 public synchronized void removeTextListener(TextListener l) { 580 if (l == null) { 581 return; 582 } 583 textListener = AWTEventMulticaster.remove(textListener, l); 584 } 585 586 /** 587 * Returns an array of all the text listeners 588 * registered on this text component. 589 * 590 * @return all of this text component's <code>TextListener</code>s 591 * or an empty array if no text 592 * listeners are currently registered 593 * 594 * 595 * @see #addTextListener 596 * @see #removeTextListener 597 * @since 1.4 598 */ 599 public synchronized TextListener[] getTextListeners() { 600 return getListeners(TextListener.class); 601 } 602 603 /** 604 * Returns an array of all the objects currently registered 605 * as <code><em>Foo</em>Listener</code>s 606 * upon this <code>TextComponent</code>. 607 * <code><em>Foo</em>Listener</code>s are registered using the 608 * <code>add<em>Foo</em>Listener</code> method. 609 * 610 * <p> 611 * You can specify the <code>listenerType</code> argument 612 * with a class literal, such as 613 * <code><em>Foo</em>Listener.class</code>. 614 * For example, you can query a 615 * <code>TextComponent</code> <code>t</code> 616 * for its text listeners with the following code: 617 * 618 * <pre>TextListener[] tls = (TextListener[])(t.getListeners(TextListener.class));</pre> 619 * 620 * If no such listeners exist, this method returns an empty array. 621 * 622 * @param listenerType the type of listeners requested; this parameter 623 * should specify an interface that descends from 624 * <code>java.util.EventListener</code> 625 * @return an array of all objects registered as 626 * <code><em>Foo</em>Listener</code>s on this text component, 627 * or an empty array if no such 628 * listeners have been added 629 * @exception ClassCastException if <code>listenerType</code> 630 * doesn't specify a class or interface that implements 631 * <code>java.util.EventListener</code> 632 * 633 * @see #getTextListeners 634 * @since 1.3 635 */ 636 public <T extends EventListener> T[] getListeners(Class<T> listenerType) { 637 EventListener l = null; 638 if (listenerType == TextListener.class) { 639 l = textListener; 640 } else { 641 return super.getListeners(listenerType); 642 } 643 return AWTEventMulticaster.getListeners(l, listenerType); 644 } 645 646 // REMIND: remove when filtering is done at lower level 647 boolean eventEnabled(AWTEvent e) { 648 if (e.id == TextEvent.TEXT_VALUE_CHANGED) { 649 if ((eventMask & AWTEvent.TEXT_EVENT_MASK) != 0 || 650 textListener != null) { 651 return true; 652 } 653 return false; 654 } 655 return super.eventEnabled(e); 656 } 657 658 /** 659 * Processes events on this text component. If the event is a 660 * <code>TextEvent</code>, it invokes the <code>processTextEvent</code> 661 * method else it invokes its superclass's <code>processEvent</code>. 662 * <p>Note that if the event parameter is <code>null</code> 663 * the behavior is unspecified and may result in an 664 * exception. 665 * 666 * @param e the event 667 */ 668 protected void processEvent(AWTEvent e) { 669 if (e instanceof TextEvent) { 670 processTextEvent((TextEvent)e); 671 return; 672 } 673 super.processEvent(e); 674 } 675 676 /** 677 * Processes text events occurring on this text component by 678 * dispatching them to any registered <code>TextListener</code> objects. 679 * <p> 680 * NOTE: This method will not be called unless text events 681 * are enabled for this component. This happens when one of the 682 * following occurs: 683 * <ul> 684 * <li>A <code>TextListener</code> object is registered 685 * via <code>addTextListener</code> 686 * <li>Text events are enabled via <code>enableEvents</code> 687 * </ul> 688 * <p>Note that if the event parameter is <code>null</code> 689 * the behavior is unspecified and may result in an 690 * exception. 691 * 692 * @param e the text event 693 * @see Component#enableEvents 694 */ 695 protected void processTextEvent(TextEvent e) { 696 TextListener listener = textListener; 697 if (listener != null) { 698 int id = e.getID(); 699 switch (id) { 700 case TextEvent.TEXT_VALUE_CHANGED: 701 listener.textValueChanged(e); 702 break; 703 } 704 } 705 } 706 707 /** 708 * Returns a string representing the state of this 709 * <code>TextComponent</code>. This 710 * method is intended to be used only for debugging purposes, and the 711 * content and format of the returned string may vary between 712 * implementations. The returned string may be empty but may not be 713 * <code>null</code>. 714 * 715 * @return the parameter string of this text component 716 */ 717 protected String paramString() { 718 String str = super.paramString() + ",text=" + getText(); 719 if (editable) { 720 str += ",editable"; 721 } 722 return str + ",selection=" + getSelectionStart() + "-" + getSelectionEnd(); 723 } 724 725 /** 726 * Assigns a valid value to the canAccessClipboard instance variable. 727 */ 728 private boolean canAccessClipboard() { 729 SecurityManager sm = System.getSecurityManager(); 730 if (sm == null) return true; 731 try { 732 sm.checkPermission(AWTPermissions.ACCESS_CLIPBOARD_PERMISSION); 733 return true; 734 } catch (SecurityException e) {} 735 return false; 736 } 737 738 /* 739 * Serialization support. 740 */ 741 /** 742 * The textComponent SerializedDataVersion. 743 * 744 * @serial 745 */ 746 private int textComponentSerializedDataVersion = 1; 747 748 /** 749 * Writes default serializable fields to stream. Writes 750 * a list of serializable TextListener(s) as optional data. 751 * The non-serializable TextListener(s) are detected and 752 * no attempt is made to serialize them. 753 * 754 * @serialData Null terminated sequence of zero or more pairs. 755 * A pair consists of a String and Object. 756 * The String indicates the type of object and 757 * is one of the following : 758 * textListenerK indicating and TextListener object. 759 * 760 * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener) 761 * @see java.awt.Component#textListenerK 762 */ 763 private void writeObject(java.io.ObjectOutputStream s) 764 throws IOException 765 { 766 // Serialization support. Since the value of the fields 767 // selectionStart, selectionEnd, and text aren't necessarily 768 // up to date, we sync them up with the peer before serializing. 769 TextComponentPeer peer = (TextComponentPeer)this.peer; 770 if (peer != null) { 771 text = peer.getText(); 772 selectionStart = peer.getSelectionStart(); 773 selectionEnd = peer.getSelectionEnd(); 774 } 775 776 s.defaultWriteObject(); 777 778 AWTEventMulticaster.save(s, textListenerK, textListener); 779 s.writeObject(null); 780 } 781 782 /** 783 * Read the ObjectInputStream, and if it isn't null, 784 * add a listener to receive text events fired by the 785 * TextComponent. Unrecognized keys or values will be 786 * ignored. 787 * 788 * @exception HeadlessException if 789 * <code>GraphicsEnvironment.isHeadless()</code> returns 790 * <code>true</code> 791 * @see #removeTextListener 792 * @see #addTextListener 793 * @see java.awt.GraphicsEnvironment#isHeadless 794 */ 795 private void readObject(ObjectInputStream s) 796 throws ClassNotFoundException, IOException, HeadlessException 797 { 798 GraphicsEnvironment.checkHeadless(); 799 s.defaultReadObject(); 800 801 // Make sure the state we just read in for text, 802 // selectionStart and selectionEnd has legal values 803 this.text = (text != null) ? text : ""; 804 select(selectionStart, selectionEnd); 805 806 Object keyOrNull; 807 while(null != (keyOrNull = s.readObject())) { 808 String key = ((String)keyOrNull).intern(); 809 810 if (textListenerK == key) { 811 addTextListener((TextListener)(s.readObject())); 812 } else { 813 // skip value for unrecognized key 814 s.readObject(); 815 } 816 } 817 enableInputMethodsIfNecessary(); 818 } 819 820 821 ///////////////// 822 // Accessibility support 823 //////////////// 824 825 /** 826 * Gets the AccessibleContext associated with this TextComponent. 827 * For text components, the AccessibleContext takes the form of an 828 * AccessibleAWTTextComponent. 829 * A new AccessibleAWTTextComponent instance is created if necessary. 830 * 831 * @return an AccessibleAWTTextComponent that serves as the 832 * AccessibleContext of this TextComponent 833 * @since 1.3 834 */ 835 public AccessibleContext getAccessibleContext() { 836 if (accessibleContext == null) { 837 accessibleContext = new AccessibleAWTTextComponent(); 838 } 839 return accessibleContext; 840 } 841 842 /** 843 * This class implements accessibility support for the 844 * <code>TextComponent</code> class. It provides an implementation of the 845 * Java Accessibility API appropriate to text component user-interface 846 * elements. 847 * @since 1.3 848 */ 849 protected class AccessibleAWTTextComponent extends AccessibleAWTComponent 850 implements AccessibleText, TextListener 851 { 852 /* 853 * JDK 1.3 serialVersionUID 854 */ 855 private static final long serialVersionUID = 3631432373506317811L; 856 857 /** 858 * Constructs an AccessibleAWTTextComponent. Adds a listener to track 859 * caret change. 860 */ 861 public AccessibleAWTTextComponent() { 862 TextComponent.this.addTextListener(this); 863 } 864 865 /** 866 * TextListener notification of a text value change. 867 */ 868 public void textValueChanged(TextEvent textEvent) { 869 Integer cpos = Integer.valueOf(TextComponent.this.getCaretPosition()); 870 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, cpos); 871 } 872 873 /** 874 * Gets the state set of the TextComponent. 875 * The AccessibleStateSet of an object is composed of a set of 876 * unique AccessibleStates. A change in the AccessibleStateSet 877 * of an object will cause a PropertyChangeEvent to be fired 878 * for the AccessibleContext.ACCESSIBLE_STATE_PROPERTY property. 879 * 880 * @return an instance of AccessibleStateSet containing the 881 * current state set of the object 882 * @see AccessibleStateSet 883 * @see AccessibleState 884 * @see #addPropertyChangeListener 885 */ 886 public AccessibleStateSet getAccessibleStateSet() { 887 AccessibleStateSet states = super.getAccessibleStateSet(); 888 if (TextComponent.this.isEditable()) { 889 states.add(AccessibleState.EDITABLE); 890 } 891 return states; 892 } 893 894 895 /** 896 * Gets the role of this object. 897 * 898 * @return an instance of AccessibleRole describing the role of the 899 * object (AccessibleRole.TEXT) 900 * @see AccessibleRole 901 */ 902 public AccessibleRole getAccessibleRole() { 903 return AccessibleRole.TEXT; 904 } 905 906 /** 907 * Get the AccessibleText associated with this object. In the 908 * implementation of the Java Accessibility API for this class, 909 * return this object, which is responsible for implementing the 910 * AccessibleText interface on behalf of itself. 911 * 912 * @return this object 913 */ 914 public AccessibleText getAccessibleText() { 915 return this; 916 } 917 918 919 // --- interface AccessibleText methods ------------------------ 920 921 /** 922 * Many of these methods are just convenience methods; they 923 * just call the equivalent on the parent 924 */ 925 926 /** 927 * Given a point in local coordinates, return the zero-based index 928 * of the character under that Point. If the point is invalid, 929 * this method returns -1. 930 * 931 * @param p the Point in local coordinates 932 * @return the zero-based index of the character under Point p. 933 */ 934 public int getIndexAtPoint(Point p) { 935 return -1; 936 } 937 938 /** 939 * Determines the bounding box of the character at the given 940 * index into the string. The bounds are returned in local 941 * coordinates. If the index is invalid a null rectangle 942 * is returned. 943 * 944 * @param i the index into the String >= 0 945 * @return the screen coordinates of the character's bounding box 946 */ 947 public Rectangle getCharacterBounds(int i) { 948 return null; 949 } 950 951 /** 952 * Returns the number of characters (valid indicies) 953 * 954 * @return the number of characters >= 0 955 */ 956 public int getCharCount() { 957 return TextComponent.this.getText().length(); 958 } 959 960 /** 961 * Returns the zero-based offset of the caret. 962 * 963 * Note: The character to the right of the caret will have the 964 * same index value as the offset (the caret is between 965 * two characters). 966 * 967 * @return the zero-based offset of the caret. 968 */ 969 public int getCaretPosition() { 970 return TextComponent.this.getCaretPosition(); 971 } 972 973 /** 974 * Returns the AttributeSet for a given character (at a given index). 975 * 976 * @param i the zero-based index into the text 977 * @return the AttributeSet of the character 978 */ 979 public AttributeSet getCharacterAttribute(int i) { 980 return null; // No attributes in TextComponent 981 } 982 983 /** 984 * Returns the start offset within the selected text. 985 * If there is no selection, but there is 986 * a caret, the start and end offsets will be the same. 987 * Return 0 if the text is empty, or the caret position 988 * if no selection. 989 * 990 * @return the index into the text of the start of the selection >= 0 991 */ 992 public int getSelectionStart() { 993 return TextComponent.this.getSelectionStart(); 994 } 995 996 /** 997 * Returns the end offset within the selected text. 998 * If there is no selection, but there is 999 * a caret, the start and end offsets will be the same. 1000 * Return 0 if the text is empty, or the caret position 1001 * if no selection. 1002 * 1003 * @return the index into the text of the end of the selection >= 0 1004 */ 1005 public int getSelectionEnd() { 1006 return TextComponent.this.getSelectionEnd(); 1007 } 1008 1009 /** 1010 * Returns the portion of the text that is selected. 1011 * 1012 * @return the text, null if no selection 1013 */ 1014 public String getSelectedText() { 1015 String selText = TextComponent.this.getSelectedText(); 1016 // Fix for 4256662 1017 if (selText == null || selText.equals("")) { 1018 return null; 1019 } 1020 return selText; 1021 } 1022 1023 /** 1024 * Returns the String at a given index. 1025 * 1026 * @param part the AccessibleText.CHARACTER, AccessibleText.WORD, 1027 * or AccessibleText.SENTENCE to retrieve 1028 * @param index an index within the text >= 0 1029 * @return the letter, word, or sentence, 1030 * null for an invalid index or part 1031 */ 1032 public String getAtIndex(int part, int index) { 1033 if (index < 0 || index >= TextComponent.this.getText().length()) { 1034 return null; 1035 } 1036 switch (part) { 1037 case AccessibleText.CHARACTER: 1038 return TextComponent.this.getText().substring(index, index+1); 1039 case AccessibleText.WORD: { 1040 String s = TextComponent.this.getText(); 1041 BreakIterator words = BreakIterator.getWordInstance(); 1042 words.setText(s); 1043 int end = words.following(index); 1044 return s.substring(words.previous(), end); 1045 } 1046 case AccessibleText.SENTENCE: { 1047 String s = TextComponent.this.getText(); 1048 BreakIterator sentence = BreakIterator.getSentenceInstance(); 1049 sentence.setText(s); 1050 int end = sentence.following(index); 1051 return s.substring(sentence.previous(), end); 1052 } 1053 default: 1054 return null; 1055 } 1056 } 1057 1058 private static final boolean NEXT = true; 1059 private static final boolean PREVIOUS = false; 1060 1061 /** 1062 * Needed to unify forward and backward searching. 1063 * The method assumes that s is the text assigned to words. 1064 */ 1065 private int findWordLimit(int index, BreakIterator words, boolean direction, 1066 String s) { 1067 // Fix for 4256660 and 4256661. 1068 // Words iterator is different from character and sentence iterators 1069 // in that end of one word is not necessarily start of another word. 1070 // Please see java.text.BreakIterator JavaDoc. The code below is 1071 // based on nextWordStartAfter example from BreakIterator.java. 1072 int last = (direction == NEXT) ? words.following(index) 1073 : words.preceding(index); 1074 int current = (direction == NEXT) ? words.next() 1075 : words.previous(); 1076 while (current != BreakIterator.DONE) { 1077 for (int p = Math.min(last, current); p < Math.max(last, current); p++) { 1078 if (Character.isLetter(s.charAt(p))) { 1079 return last; 1080 } 1081 } 1082 last = current; 1083 current = (direction == NEXT) ? words.next() 1084 : words.previous(); 1085 } 1086 return BreakIterator.DONE; 1087 } 1088 1089 /** 1090 * Returns the String after a given index. 1091 * 1092 * @param part the AccessibleText.CHARACTER, AccessibleText.WORD, 1093 * or AccessibleText.SENTENCE to retrieve 1094 * @param index an index within the text >= 0 1095 * @return the letter, word, or sentence, null for an invalid 1096 * index or part 1097 */ 1098 public String getAfterIndex(int part, int index) { 1099 if (index < 0 || index >= TextComponent.this.getText().length()) { 1100 return null; 1101 } 1102 switch (part) { 1103 case AccessibleText.CHARACTER: 1104 if (index+1 >= TextComponent.this.getText().length()) { 1105 return null; 1106 } 1107 return TextComponent.this.getText().substring(index+1, index+2); 1108 case AccessibleText.WORD: { 1109 String s = TextComponent.this.getText(); 1110 BreakIterator words = BreakIterator.getWordInstance(); 1111 words.setText(s); 1112 int start = findWordLimit(index, words, NEXT, s); 1113 if (start == BreakIterator.DONE || start >= s.length()) { 1114 return null; 1115 } 1116 int end = words.following(start); 1117 if (end == BreakIterator.DONE || end >= s.length()) { 1118 return null; 1119 } 1120 return s.substring(start, end); 1121 } 1122 case AccessibleText.SENTENCE: { 1123 String s = TextComponent.this.getText(); 1124 BreakIterator sentence = BreakIterator.getSentenceInstance(); 1125 sentence.setText(s); 1126 int start = sentence.following(index); 1127 if (start == BreakIterator.DONE || start >= s.length()) { 1128 return null; 1129 } 1130 int end = sentence.following(start); 1131 if (end == BreakIterator.DONE || end >= s.length()) { 1132 return null; 1133 } 1134 return s.substring(start, end); 1135 } 1136 default: 1137 return null; 1138 } 1139 } 1140 1141 1142 /** 1143 * Returns the String before a given index. 1144 * 1145 * @param part the AccessibleText.CHARACTER, AccessibleText.WORD, 1146 * or AccessibleText.SENTENCE to retrieve 1147 * @param index an index within the text >= 0 1148 * @return the letter, word, or sentence, null for an invalid index 1149 * or part 1150 */ 1151 public String getBeforeIndex(int part, int index) { 1152 if (index < 0 || index > TextComponent.this.getText().length()-1) { 1153 return null; 1154 } 1155 switch (part) { 1156 case AccessibleText.CHARACTER: 1157 if (index == 0) { 1158 return null; 1159 } 1160 return TextComponent.this.getText().substring(index-1, index); 1161 case AccessibleText.WORD: { 1162 String s = TextComponent.this.getText(); 1163 BreakIterator words = BreakIterator.getWordInstance(); 1164 words.setText(s); 1165 int end = findWordLimit(index, words, PREVIOUS, s); 1166 if (end == BreakIterator.DONE) { 1167 return null; 1168 } 1169 int start = words.preceding(end); 1170 if (start == BreakIterator.DONE) { 1171 return null; 1172 } 1173 return s.substring(start, end); 1174 } 1175 case AccessibleText.SENTENCE: { 1176 String s = TextComponent.this.getText(); 1177 BreakIterator sentence = BreakIterator.getSentenceInstance(); 1178 sentence.setText(s); 1179 int end = sentence.following(index); 1180 end = sentence.previous(); 1181 int start = sentence.previous(); 1182 if (start == BreakIterator.DONE) { 1183 return null; 1184 } 1185 return s.substring(start, end); 1186 } 1187 default: 1188 return null; 1189 } 1190 } 1191 } // end of AccessibleAWTTextComponent 1192 1193 private boolean checkForEnableIM = true; 1194 }