1 /* 2 * Copyright 1997-2008 Sun Microsystems, Inc. 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. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any questions. 24 */ 25 package javax.swing; 26 27 import sun.swing.SwingUtilities2; 28 29 import java.awt.*; 30 import java.awt.event.*; 31 import java.beans.*; 32 import javax.swing.text.*; 33 import javax.swing.plaf.*; 34 import javax.swing.event.*; 35 import javax.accessibility.*; 36 37 import java.io.ObjectOutputStream; 38 import java.io.ObjectInputStream; 39 import java.io.IOException; 40 import java.io.Serializable; 41 42 /** 43 * <code>JTextField</code> is a lightweight component that allows the editing 44 * of a single line of text. 45 * For information on and examples of using text fields, 46 * see 47 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/textfield.html">How to Use Text Fields</a> 48 * in <em>The Java Tutorial.</em> 49 * 50 * <p> 51 * <code>JTextField</code> is intended to be source-compatible 52 * with <code>java.awt.TextField</code> where it is reasonable to do so. This 53 * component has capabilities not found in the <code>java.awt.TextField</code> 54 * class. The superclass should be consulted for additional capabilities. 55 * <p> 56 * <code>JTextField</code> has a method to establish the string used as the 57 * command string for the action event that gets fired. The 58 * <code>java.awt.TextField</code> used the text of the field as the command 59 * string for the <code>ActionEvent</code>. 60 * <code>JTextField</code> will use the command 61 * string set with the <code>setActionCommand</code> method if not <code>null</code>, 62 * otherwise it will use the text of the field as a compatibility with 63 * <code>java.awt.TextField</code>. 64 * <p> 65 * The method <code>setEchoChar</code> and <code>getEchoChar</code> 66 * are not provided directly to avoid a new implementation of a 67 * pluggable look-and-feel inadvertently exposing password characters. 68 * To provide password-like services a separate class <code>JPasswordField</code> 69 * extends <code>JTextField</code> to provide this service with an independently 70 * pluggable look-and-feel. 71 * <p> 72 * The <code>java.awt.TextField</code> could be monitored for changes by adding 73 * a <code>TextListener</code> for <code>TextEvent</code>'s. 74 * In the <code>JTextComponent</code> based 75 * components, changes are broadcasted from the model via a 76 * <code>DocumentEvent</code> to <code>DocumentListeners</code>. 77 * The <code>DocumentEvent</code> gives 78 * the location of the change and the kind of change if desired. 79 * The code fragment might look something like: 80 * <pre><code> 81 * DocumentListener myListener = ??; 82 * JTextField myArea = ??; 83 * myArea.getDocument().addDocumentListener(myListener); 84 * </code></pre> 85 * <p> 86 * The horizontal alignment of <code>JTextField</code> can be set to be left 87 * justified, leading justified, centered, right justified or trailing justified. 88 * Right/trailing justification is useful if the required size 89 * of the field text is smaller than the size allocated to it. 90 * This is determined by the <code>setHorizontalAlignment</code> 91 * and <code>getHorizontalAlignment</code> methods. The default 92 * is to be leading justified. 93 * <p> 94 * How the text field consumes VK_ENTER events depends 95 * on whether the text field has any action listeners. 96 * If so, then VK_ENTER results in the listeners 97 * getting an ActionEvent, 98 * and the VK_ENTER event is consumed. 99 * This is compatible with how AWT text fields handle VK_ENTER events. 100 * If the text field has no action listeners, then as of v 1.3 the VK_ENTER 101 * event is not consumed. Instead, the bindings of ancestor components 102 * are processed, which enables the default button feature of 103 * JFC/Swing to work. 104 * <p> 105 * Customized fields can easily be created by extending the model and 106 * changing the default model provided. For example, the following piece 107 * of code will create a field that holds only upper case characters. It 108 * will work even if text is pasted into from the clipboard or it is altered via 109 * programmatic changes. 110 * <pre><code> 111 112 public class UpperCaseField extends JTextField { 113 114 public UpperCaseField(int cols) { 115 super(cols); 116 } 117 118 protected Document createDefaultModel() { 119 return new UpperCaseDocument(); 120 } 121 122 static class UpperCaseDocument extends PlainDocument { 123 124 public void insertString(int offs, String str, AttributeSet a) 125 throws BadLocationException { 126 127 if (str == null) { 128 return; 129 } 130 char[] upper = str.toCharArray(); 131 for (int i = 0; i < upper.length; i++) { 132 upper[i] = Character.toUpperCase(upper[i]); 133 } 134 super.insertString(offs, new String(upper), a); 135 } 136 } 137 } 138 139 * </code></pre> 140 * <p> 141 * <strong>Warning:</strong> Swing is not thread safe. For more 142 * information see <a 143 * href="package-summary.html#threading">Swing's Threading 144 * Policy</a>. 145 * <p> 146 * <strong>Warning:</strong> 147 * Serialized objects of this class will not be compatible with 148 * future Swing releases. The current serialization support is 149 * appropriate for short term storage or RMI between applications running 150 * the same version of Swing. As of 1.4, support for long term storage 151 * of all JavaBeans<sup><font size="-2">TM</font></sup> 152 * has been added to the <code>java.beans</code> package. 153 * Please see {@link java.beans.XMLEncoder}. 154 * 155 * @beaninfo 156 * attribute: isContainer false 157 * description: A component which allows for the editing of a single line of text. 158 * 159 * @author Timothy Prinzing 160 * @see #setActionCommand 161 * @see JPasswordField 162 * @see #addActionListener 163 */ 164 public class JTextField extends JTextComponent implements SwingConstants { 165 166 /** 167 * Constructs a new <code>TextField</code>. A default model is created, 168 * the initial string is <code>null</code>, 169 * and the number of columns is set to 0. 170 */ 171 public JTextField() { 172 this(null, null, 0); 173 } 174 175 /** 176 * Constructs a new <code>TextField</code> initialized with the 177 * specified text. A default model is created and the number of 178 * columns is 0. 179 * 180 * @param text the text to be displayed, or <code>null</code> 181 */ 182 public JTextField(String text) { 183 this(null, text, 0); 184 } 185 186 /** 187 * Constructs a new empty <code>TextField</code> with the specified 188 * number of columns. 189 * A default model is created and the initial string is set to 190 * <code>null</code>. 191 * 192 * @param columns the number of columns to use to calculate 193 * the preferred width; if columns is set to zero, the 194 * preferred width will be whatever naturally results from 195 * the component implementation 196 */ 197 public JTextField(int columns) { 198 this(null, null, columns); 199 } 200 201 /** 202 * Constructs a new <code>TextField</code> initialized with the 203 * specified text and columns. A default model is created. 204 * 205 * @param text the text to be displayed, or <code>null</code> 206 * @param columns the number of columns to use to calculate 207 * the preferred width; if columns is set to zero, the 208 * preferred width will be whatever naturally results from 209 * the component implementation 210 */ 211 public JTextField(String text, int columns) { 212 this(null, text, columns); 213 } 214 215 /** 216 * Constructs a new <code>JTextField</code> that uses the given text 217 * storage model and the given number of columns. 218 * This is the constructor through which the other constructors feed. 219 * If the document is <code>null</code>, a default model is created. 220 * 221 * @param doc the text storage to use; if this is <code>null</code>, 222 * a default will be provided by calling the 223 * <code>createDefaultModel</code> method 224 * @param text the initial string to display, or <code>null</code> 225 * @param columns the number of columns to use to calculate 226 * the preferred width >= 0; if <code>columns</code> 227 * is set to zero, the preferred width will be whatever 228 * naturally results from the component implementation 229 * @exception IllegalArgumentException if <code>columns</code> < 0 230 */ 231 public JTextField(Document doc, String text, int columns) { 232 if (columns < 0) { 233 throw new IllegalArgumentException("columns less than zero."); 234 } 235 visibility = new DefaultBoundedRangeModel(); 236 visibility.addChangeListener(new ScrollRepainter()); 237 this.columns = columns; 238 if (doc == null) { 239 doc = createDefaultModel(); 240 } 241 setDocument(doc); 242 if (text != null) { 243 setText(text); 244 } 245 } 246 247 /** 248 * Gets the class ID for a UI. 249 * 250 * @return the string "TextFieldUI" 251 * @see JComponent#getUIClassID 252 * @see UIDefaults#getUI 253 */ 254 public String getUIClassID() { 255 return uiClassID; 256 } 257 258 259 /** 260 * Associates the editor with a text document. 261 * The currently registered factory is used to build a view for 262 * the document, which gets displayed by the editor after revalidation. 263 * A PropertyChange event ("document") is propagated to each listener. 264 * 265 * @param doc the document to display/edit 266 * @see #getDocument 267 * @beaninfo 268 * description: the text document model 269 * bound: true 270 * expert: true 271 */ 272 public void setDocument(Document doc) { 273 if (doc != null) { 274 doc.putProperty("filterNewlines", Boolean.TRUE); 275 } 276 super.setDocument(doc); 277 } 278 279 /** 280 * Calls to <code>revalidate</code> that come from within the 281 * textfield itself will 282 * be handled by validating the textfield, unless the textfield 283 * is contained within a <code>JViewport</code>, 284 * in which case this returns false. 285 * 286 * @return if the parent of this textfield is a <code>JViewPort</code> 287 * return false, otherwise return true 288 * 289 * @see JComponent#revalidate 290 * @see JComponent#isValidateRoot 291 * @see java.awt.Container#isValidateRoot 292 */ 293 @Override 294 public boolean isValidateRoot() { 295 return SwingUtilities2.getViewport(this) == null; 296 } 297 298 299 /** 300 * Returns the horizontal alignment of the text. 301 * Valid keys are: 302 * <ul> 303 * <li><code>JTextField.LEFT</code> 304 * <li><code>JTextField.CENTER</code> 305 * <li><code>JTextField.RIGHT</code> 306 * <li><code>JTextField.LEADING</code> 307 * <li><code>JTextField.TRAILING</code> 308 * </ul> 309 * 310 * @return the horizontal alignment 311 */ 312 public int getHorizontalAlignment() { 313 return horizontalAlignment; 314 } 315 316 /** 317 * Sets the horizontal alignment of the text. 318 * Valid keys are: 319 * <ul> 320 * <li><code>JTextField.LEFT</code> 321 * <li><code>JTextField.CENTER</code> 322 * <li><code>JTextField.RIGHT</code> 323 * <li><code>JTextField.LEADING</code> 324 * <li><code>JTextField.TRAILING</code> 325 * </ul> 326 * <code>invalidate</code> and <code>repaint</code> are called when the 327 * alignment is set, 328 * and a <code>PropertyChange</code> event ("horizontalAlignment") is fired. 329 * 330 * @param alignment the alignment 331 * @exception IllegalArgumentException if <code>alignment</code> 332 * is not a valid key 333 * @beaninfo 334 * preferred: true 335 * bound: true 336 * description: Set the field alignment to LEFT, CENTER, RIGHT, 337 * LEADING (the default) or TRAILING 338 * enum: LEFT JTextField.LEFT CENTER JTextField.CENTER RIGHT JTextField.RIGHT 339 * LEADING JTextField.LEADING TRAILING JTextField.TRAILING 340 */ 341 public void setHorizontalAlignment(int alignment) { 342 if (alignment == horizontalAlignment) return; 343 int oldValue = horizontalAlignment; 344 if ((alignment == LEFT) || (alignment == CENTER) || 345 (alignment == RIGHT)|| (alignment == LEADING) || 346 (alignment == TRAILING)) { 347 horizontalAlignment = alignment; 348 } else { 349 throw new IllegalArgumentException("horizontalAlignment"); 350 } 351 firePropertyChange("horizontalAlignment", oldValue, horizontalAlignment); 352 invalidate(); 353 repaint(); 354 } 355 356 /** 357 * Creates the default implementation of the model 358 * to be used at construction if one isn't explicitly 359 * given. An instance of <code>PlainDocument</code> is returned. 360 * 361 * @return the default model implementation 362 */ 363 protected Document createDefaultModel() { 364 return new PlainDocument(); 365 } 366 367 /** 368 * Returns the number of columns in this <code>TextField</code>. 369 * 370 * @return the number of columns >= 0 371 */ 372 public int getColumns() { 373 return columns; 374 } 375 376 /** 377 * Sets the number of columns in this <code>TextField</code>, 378 * and then invalidate the layout. 379 * 380 * @param columns the number of columns >= 0 381 * @exception IllegalArgumentException if <code>columns</code> 382 * is less than 0 383 * @beaninfo 384 * description: the number of columns preferred for display 385 */ 386 public void setColumns(int columns) { 387 int oldVal = this.columns; 388 if (columns < 0) { 389 throw new IllegalArgumentException("columns less than zero."); 390 } 391 if (columns != oldVal) { 392 this.columns = columns; 393 invalidate(); 394 } 395 } 396 397 /** 398 * Returns the column width. 399 * The meaning of what a column is can be considered a fairly weak 400 * notion for some fonts. This method is used to define the width 401 * of a column. By default this is defined to be the width of the 402 * character <em>m</em> for the font used. This method can be 403 * redefined to be some alternative amount 404 * 405 * @return the column width >= 1 406 */ 407 protected int getColumnWidth() { 408 if (columnWidth == 0) { 409 FontMetrics metrics = getFontMetrics(getFont()); 410 columnWidth = metrics.charWidth('m'); 411 } 412 return columnWidth; 413 } 414 415 /** 416 * Returns the preferred size <code>Dimensions</code> needed for this 417 * <code>TextField</code>. If a non-zero number of columns has been 418 * set, the width is set to the columns multiplied by 419 * the column width. 420 * 421 * @return the dimension of this textfield 422 */ 423 public Dimension getPreferredSize() { 424 Dimension size = super.getPreferredSize(); 425 if (columns != 0) { 426 Insets insets = getInsets(); 427 size.width = columns * getColumnWidth() + 428 insets.left + insets.right; 429 } 430 return size; 431 } 432 433 /** 434 * Sets the current font. This removes cached row height and column 435 * width so the new font will be reflected. 436 * <code>revalidate</code> is called after setting the font. 437 * 438 * @param f the new font 439 */ 440 public void setFont(Font f) { 441 super.setFont(f); 442 columnWidth = 0; 443 } 444 445 /** 446 * Adds the specified action listener to receive 447 * action events from this textfield. 448 * 449 * @param l the action listener to be added 450 */ 451 public synchronized void addActionListener(ActionListener l) { 452 listenerList.add(ActionListener.class, l); 453 } 454 455 /** 456 * Removes the specified action listener so that it no longer 457 * receives action events from this textfield. 458 * 459 * @param l the action listener to be removed 460 */ 461 public synchronized void removeActionListener(ActionListener l) { 462 if ((l != null) && (getAction() == l)) { 463 setAction(null); 464 } else { 465 listenerList.remove(ActionListener.class, l); 466 } 467 } 468 469 /** 470 * Returns an array of all the <code>ActionListener</code>s added 471 * to this JTextField with addActionListener(). 472 * 473 * @return all of the <code>ActionListener</code>s added or an empty 474 * array if no listeners have been added 475 * @since 1.4 476 */ 477 public synchronized ActionListener[] getActionListeners() { 478 return listenerList.getListeners(ActionListener.class); 479 } 480 481 /** 482 * Notifies all listeners that have registered interest for 483 * notification on this event type. The event instance 484 * is lazily created. 485 * The listener list is processed in last to 486 * first order. 487 * @see EventListenerList 488 */ 489 protected void fireActionPerformed() { 490 // Guaranteed to return a non-null array 491 Object[] listeners = listenerList.getListenerList(); 492 int modifiers = 0; 493 AWTEvent currentEvent = EventQueue.getCurrentEvent(); 494 if (currentEvent instanceof InputEvent) { 495 modifiers = ((InputEvent)currentEvent).getModifiers(); 496 } else if (currentEvent instanceof ActionEvent) { 497 modifiers = ((ActionEvent)currentEvent).getModifiers(); 498 } 499 ActionEvent e = 500 new ActionEvent(this, ActionEvent.ACTION_PERFORMED, 501 (command != null) ? command : getText(), 502 EventQueue.getMostRecentEventTime(), modifiers); 503 504 // Process the listeners last to first, notifying 505 // those that are interested in this event 506 for (int i = listeners.length-2; i>=0; i-=2) { 507 if (listeners[i]==ActionListener.class) { 508 ((ActionListener)listeners[i+1]).actionPerformed(e); 509 } 510 } 511 } 512 513 /** 514 * Sets the command string used for action events. 515 * 516 * @param command the command string 517 */ 518 public void setActionCommand(String command) { 519 this.command = command; 520 } 521 522 private Action action; 523 private PropertyChangeListener actionPropertyChangeListener; 524 525 /** 526 * Sets the <code>Action</code> for the <code>ActionEvent</code> source. 527 * The new <code>Action</code> replaces 528 * any previously set <code>Action</code> but does not affect 529 * <code>ActionListeners</code> independently 530 * added with <code>addActionListener</code>. 531 * If the <code>Action</code> is already a registered 532 * <code>ActionListener</code> 533 * for the <code>ActionEvent</code> source, it is not re-registered. 534 * <p> 535 * Setting the <code>Action</code> results in immediately changing 536 * all the properties described in <a href="Action.html#buttonActions"> 537 * Swing Components Supporting <code>Action</code></a>. 538 * Subsequently, the textfield's properties are automatically updated 539 * as the <code>Action</code>'s properties change. 540 * <p> 541 * This method uses three other methods to set 542 * and help track the <code>Action</code>'s property values. 543 * It uses the <code>configurePropertiesFromAction</code> method 544 * to immediately change the textfield's properties. 545 * To track changes in the <code>Action</code>'s property values, 546 * this method registers the <code>PropertyChangeListener</code> 547 * returned by <code>createActionPropertyChangeListener</code>. The 548 * default {@code PropertyChangeListener} invokes the 549 * {@code actionPropertyChanged} method when a property in the 550 * {@code Action} changes. 551 * 552 * @param a the <code>Action</code> for the <code>JTextField</code>, 553 * or <code>null</code> 554 * @since 1.3 555 * @see Action 556 * @see #getAction 557 * @see #configurePropertiesFromAction 558 * @see #createActionPropertyChangeListener 559 * @see #actionPropertyChanged 560 * @beaninfo 561 * bound: true 562 * attribute: visualUpdate true 563 * description: the Action instance connected with this ActionEvent source 564 */ 565 public void setAction(Action a) { 566 Action oldValue = getAction(); 567 if (action==null || !action.equals(a)) { 568 action = a; 569 if (oldValue!=null) { 570 removeActionListener(oldValue); 571 oldValue.removePropertyChangeListener(actionPropertyChangeListener); 572 actionPropertyChangeListener = null; 573 } 574 configurePropertiesFromAction(action); 575 if (action!=null) { 576 // Don't add if it is already a listener 577 if (!isListener(ActionListener.class, action)) { 578 addActionListener(action); 579 } 580 // Reverse linkage: 581 actionPropertyChangeListener = createActionPropertyChangeListener(action); 582 action.addPropertyChangeListener(actionPropertyChangeListener); 583 } 584 firePropertyChange("action", oldValue, action); 585 } 586 } 587 588 private boolean isListener(Class c, ActionListener a) { 589 boolean isListener = false; 590 Object[] listeners = listenerList.getListenerList(); 591 for (int i = listeners.length-2; i>=0; i-=2) { 592 if (listeners[i]==c && listeners[i+1]==a) { 593 isListener=true; 594 } 595 } 596 return isListener; 597 } 598 599 /** 600 * Returns the currently set <code>Action</code> for this 601 * <code>ActionEvent</code> source, or <code>null</code> 602 * if no <code>Action</code> is set. 603 * 604 * @return the <code>Action</code> for this <code>ActionEvent</code> source, 605 * or <code>null</code> 606 * @since 1.3 607 * @see Action 608 * @see #setAction 609 */ 610 public Action getAction() { 611 return action; 612 } 613 614 /** 615 * Sets the properties on this textfield to match those in the specified 616 * <code>Action</code>. Refer to <a href="Action.html#buttonActions"> 617 * Swing Components Supporting <code>Action</code></a> for more 618 * details as to which properties this sets. 619 * 620 * @param a the <code>Action</code> from which to get the properties, 621 * or <code>null</code> 622 * @since 1.3 623 * @see Action 624 * @see #setAction 625 */ 626 protected void configurePropertiesFromAction(Action a) { 627 AbstractAction.setEnabledFromAction(this, a); 628 AbstractAction.setToolTipTextFromAction(this, a); 629 setActionCommandFromAction(a); 630 } 631 632 /** 633 * Updates the textfield's state in response to property changes in 634 * associated action. This method is invoked from the 635 * {@code PropertyChangeListener} returned from 636 * {@code createActionPropertyChangeListener}. Subclasses do not normally 637 * need to invoke this. Subclasses that support additional {@code Action} 638 * properties should override this and 639 * {@code configurePropertiesFromAction}. 640 * <p> 641 * Refer to the table at <a href="Action.html#buttonActions"> 642 * Swing Components Supporting <code>Action</code></a> for a list of 643 * the properties this method sets. 644 * 645 * @param action the <code>Action</code> associated with this textfield 646 * @param propertyName the name of the property that changed 647 * @since 1.6 648 * @see Action 649 * @see #configurePropertiesFromAction 650 */ 651 protected void actionPropertyChanged(Action action, String propertyName) { 652 if (propertyName == Action.ACTION_COMMAND_KEY) { 653 setActionCommandFromAction(action); 654 } else if (propertyName == "enabled") { 655 AbstractAction.setEnabledFromAction(this, action); 656 } else if (propertyName == Action.SHORT_DESCRIPTION) { 657 AbstractAction.setToolTipTextFromAction(this, action); 658 } 659 } 660 661 private void setActionCommandFromAction(Action action) { 662 setActionCommand((action == null) ? null : 663 (String)action.getValue(Action.ACTION_COMMAND_KEY)); 664 } 665 666 /** 667 * Creates and returns a <code>PropertyChangeListener</code> that is 668 * responsible for listening for changes from the specified 669 * <code>Action</code> and updating the appropriate properties. 670 * <p> 671 * <b>Warning:</b> If you subclass this do not create an anonymous 672 * inner class. If you do the lifetime of the textfield will be tied to 673 * that of the <code>Action</code>. 674 * 675 * @param a the textfield's action 676 * @since 1.3 677 * @see Action 678 * @see #setAction 679 */ 680 protected PropertyChangeListener createActionPropertyChangeListener(Action a) { 681 return new TextFieldActionPropertyChangeListener(this, a); 682 } 683 684 private static class TextFieldActionPropertyChangeListener extends 685 ActionPropertyChangeListener<JTextField> { 686 TextFieldActionPropertyChangeListener(JTextField tf, Action a) { 687 super(tf, a); 688 } 689 690 protected void actionPropertyChanged(JTextField textField, 691 Action action, 692 PropertyChangeEvent e) { 693 if (AbstractAction.shouldReconfigure(e)) { 694 textField.configurePropertiesFromAction(action); 695 } else { 696 textField.actionPropertyChanged(action, e.getPropertyName()); 697 } 698 } 699 } 700 701 /** 702 * Fetches the command list for the editor. This is 703 * the list of commands supported by the plugged-in UI 704 * augmented by the collection of commands that the 705 * editor itself supports. These are useful for binding 706 * to events, such as in a keymap. 707 * 708 * @return the command list 709 */ 710 public Action[] getActions() { 711 return TextAction.augmentList(super.getActions(), defaultActions); 712 } 713 714 /** 715 * Processes action events occurring on this textfield by 716 * dispatching them to any registered <code>ActionListener</code> objects. 717 * This is normally called by the controller registered with 718 * textfield. 719 */ 720 public void postActionEvent() { 721 fireActionPerformed(); 722 } 723 724 // --- Scrolling support ----------------------------------- 725 726 /** 727 * Gets the visibility of the text field. This can 728 * be adjusted to change the location of the visible 729 * area if the size of the field is greater than 730 * the area that was allocated to the field. 731 * 732 * <p> 733 * The fields look-and-feel implementation manages 734 * the values of the minimum, maximum, and extent 735 * properties on the <code>BoundedRangeModel</code>. 736 * 737 * @return the visibility 738 * @see BoundedRangeModel 739 */ 740 public BoundedRangeModel getHorizontalVisibility() { 741 return visibility; 742 } 743 744 /** 745 * Gets the scroll offset, in pixels. 746 * 747 * @return the offset >= 0 748 */ 749 public int getScrollOffset() { 750 return visibility.getValue(); 751 } 752 753 /** 754 * Sets the scroll offset, in pixels. 755 * 756 * @param scrollOffset the offset >= 0 757 */ 758 public void setScrollOffset(int scrollOffset) { 759 visibility.setValue(scrollOffset); 760 } 761 762 /** 763 * Scrolls the field left or right. 764 * 765 * @param r the region to scroll 766 */ 767 public void scrollRectToVisible(Rectangle r) { 768 // convert to coordinate system of the bounded range 769 Insets i = getInsets(); 770 int x0 = r.x + visibility.getValue() - i.left; 771 int x1 = x0 + r.width; 772 if (x0 < visibility.getValue()) { 773 // Scroll to the left 774 visibility.setValue(x0); 775 } else if(x1 > visibility.getValue() + visibility.getExtent()) { 776 // Scroll to the right 777 visibility.setValue(x1 - visibility.getExtent()); 778 } 779 } 780 781 /** 782 * Returns true if the receiver has an <code>ActionListener</code> 783 * installed. 784 */ 785 boolean hasActionListener() { 786 // Guaranteed to return a non-null array 787 Object[] listeners = listenerList.getListenerList(); 788 // Process the listeners last to first, notifying 789 // those that are interested in this event 790 for (int i = listeners.length-2; i>=0; i-=2) { 791 if (listeners[i]==ActionListener.class) { 792 return true; 793 } 794 } 795 return false; 796 } 797 798 // --- variables ------------------------------------------- 799 800 /** 801 * Name of the action to send notification that the 802 * contents of the field have been accepted. Typically 803 * this is bound to a carriage-return. 804 */ 805 public static final String notifyAction = "notify-field-accept"; 806 807 private BoundedRangeModel visibility; 808 private int horizontalAlignment = LEADING; 809 private int columns; 810 private int columnWidth; 811 private String command; 812 813 private static final Action[] defaultActions = { 814 new NotifyAction() 815 }; 816 817 /** 818 * @see #getUIClassID 819 * @see #readObject 820 */ 821 private static final String uiClassID = "TextFieldUI"; 822 823 // --- Action implementations ----------------------------------- 824 825 // Note that JFormattedTextField.CommitAction extends this 826 static class NotifyAction extends TextAction { 827 828 NotifyAction() { 829 super(notifyAction); 830 } 831 832 public void actionPerformed(ActionEvent e) { 833 JTextComponent target = getFocusedComponent(); 834 if (target instanceof JTextField) { 835 JTextField field = (JTextField) target; 836 field.postActionEvent(); 837 } 838 } 839 840 public boolean isEnabled() { 841 JTextComponent target = getFocusedComponent(); 842 if (target instanceof JTextField) { 843 return ((JTextField)target).hasActionListener(); 844 } 845 return false; 846 } 847 } 848 849 class ScrollRepainter implements ChangeListener, Serializable { 850 851 public void stateChanged(ChangeEvent e) { 852 repaint(); 853 } 854 855 } 856 857 858 /** 859 * See <code>readObject</code> and <code>writeObject</code> in 860 * <code>JComponent</code> for more 861 * information about serialization in Swing. 862 */ 863 private void writeObject(ObjectOutputStream s) throws IOException { 864 s.defaultWriteObject(); 865 if (getUIClassID().equals(uiClassID)) { 866 byte count = JComponent.getWriteObjCounter(this); 867 JComponent.setWriteObjCounter(this, --count); 868 if (count == 0 && ui != null) { 869 ui.installUI(this); 870 } 871 } 872 } 873 874 875 /** 876 * Returns a string representation of this <code>JTextField</code>. 877 * This method is intended to be used only for debugging purposes, 878 * and the content and format of the returned string may vary between 879 * implementations. The returned string may be empty but may not 880 * be <code>null</code>. 881 * 882 * @return a string representation of this <code>JTextField</code> 883 */ 884 protected String paramString() { 885 String horizontalAlignmentString; 886 if (horizontalAlignment == LEFT) { 887 horizontalAlignmentString = "LEFT"; 888 } else if (horizontalAlignment == CENTER) { 889 horizontalAlignmentString = "CENTER"; 890 } else if (horizontalAlignment == RIGHT) { 891 horizontalAlignmentString = "RIGHT"; 892 } else if (horizontalAlignment == LEADING) { 893 horizontalAlignmentString = "LEADING"; 894 } else if (horizontalAlignment == TRAILING) { 895 horizontalAlignmentString = "TRAILING"; 896 } else horizontalAlignmentString = ""; 897 String commandString = (command != null ? 898 command : ""); 899 900 return super.paramString() + 901 ",columns=" + columns + 902 ",columnWidth=" + columnWidth + 903 ",command=" + commandString + 904 ",horizontalAlignment=" + horizontalAlignmentString; 905 } 906 907 908 ///////////////// 909 // Accessibility support 910 //////////////// 911 912 913 /** 914 * Gets the <code>AccessibleContext</code> associated with this 915 * <code>JTextField</code>. For <code>JTextFields</code>, 916 * the <code>AccessibleContext</code> takes the form of an 917 * <code>AccessibleJTextField</code>. 918 * A new <code>AccessibleJTextField</code> instance is created 919 * if necessary. 920 * 921 * @return an <code>AccessibleJTextField</code> that serves as the 922 * <code>AccessibleContext</code> of this <code>JTextField</code> 923 */ 924 public AccessibleContext getAccessibleContext() { 925 if (accessibleContext == null) { 926 accessibleContext = new AccessibleJTextField(); 927 } 928 return accessibleContext; 929 } 930 931 /** 932 * This class implements accessibility support for the 933 * <code>JTextField</code> class. It provides an implementation of the 934 * Java Accessibility API appropriate to text field user-interface 935 * elements. 936 * <p> 937 * <strong>Warning:</strong> 938 * Serialized objects of this class will not be compatible with 939 * future Swing releases. The current serialization support is 940 * appropriate for short term storage or RMI between applications running 941 * the same version of Swing. As of 1.4, support for long term storage 942 * of all JavaBeans<sup><font size="-2">TM</font></sup> 943 * has been added to the <code>java.beans</code> package. 944 * Please see {@link java.beans.XMLEncoder}. 945 */ 946 protected class AccessibleJTextField extends AccessibleJTextComponent { 947 948 /** 949 * Gets the state set of this object. 950 * 951 * @return an instance of AccessibleStateSet describing the states 952 * of the object 953 * @see AccessibleState 954 */ 955 public AccessibleStateSet getAccessibleStateSet() { 956 AccessibleStateSet states = super.getAccessibleStateSet(); 957 states.add(AccessibleState.SINGLE_LINE); 958 return states; 959 } 960 } 961 }