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