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