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 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="http://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 protected void fireActionPerformed() { 489 // Guaranteed to return a non-null array 490 Object[] listeners = listenerList.getListenerList(); 491 int modifiers = 0; 492 AWTEvent currentEvent = EventQueue.getCurrentEvent(); 493 if (currentEvent instanceof InputEvent) { 494 modifiers = ((InputEvent)currentEvent).getModifiers(); 495 } else if (currentEvent instanceof ActionEvent) { 496 modifiers = ((ActionEvent)currentEvent).getModifiers(); 497 } 498 ActionEvent e = 499 new ActionEvent(this, ActionEvent.ACTION_PERFORMED, 500 (command != null) ? command : getText(), 501 EventQueue.getMostRecentEventTime(), modifiers); 502 503 // Process the listeners last to first, notifying 504 // those that are interested in this event 505 for (int i = listeners.length-2; i>=0; i-=2) { 506 if (listeners[i]==ActionListener.class) { 507 ((ActionListener)listeners[i+1]).actionPerformed(e); 508 } 509 } 510 } 511 512 /** 513 * Sets the command string used for action events. 514 * 515 * @param command the command string 516 */ 517 public void setActionCommand(String command) { 518 this.command = command; 519 } 520 521 private Action action; 522 private PropertyChangeListener actionPropertyChangeListener; 523 524 /** 525 * Sets the <code>Action</code> for the <code>ActionEvent</code> source. 526 * The new <code>Action</code> replaces 527 * any previously set <code>Action</code> but does not affect 528 * <code>ActionListeners</code> independently 529 * added with <code>addActionListener</code>. 530 * If the <code>Action</code> is already a registered 531 * <code>ActionListener</code> 532 * for the <code>ActionEvent</code> source, it is not re-registered. 533 * <p> 534 * Setting the <code>Action</code> results in immediately changing 535 * all the properties described in <a href="Action.html#buttonActions"> 536 * Swing Components Supporting <code>Action</code></a>. 537 * Subsequently, the textfield's properties are automatically updated 538 * as the <code>Action</code>'s properties change. 539 * <p> 540 * This method uses three other methods to set 541 * and help track the <code>Action</code>'s property values. 542 * It uses the <code>configurePropertiesFromAction</code> method 543 * to immediately change the textfield's properties. 544 * To track changes in the <code>Action</code>'s property values, 545 * this method registers the <code>PropertyChangeListener</code> 546 * returned by <code>createActionPropertyChangeListener</code>. The 547 * default {@code PropertyChangeListener} invokes the 548 * {@code actionPropertyChanged} method when a property in the 549 * {@code Action} changes. 550 * 551 * @param a the <code>Action</code> for the <code>JTextField</code>, 552 * or <code>null</code> 553 * @since 1.3 554 * @see Action 555 * @see #getAction 556 * @see #configurePropertiesFromAction 557 * @see #createActionPropertyChangeListener 558 * @see #actionPropertyChanged 559 */ 560 @BeanProperty(visualUpdate = true, description 561 = "the Action instance connected with this ActionEvent source") 562 public void setAction(Action a) { 563 Action oldValue = getAction(); 564 if (action==null || !action.equals(a)) { 565 action = a; 566 if (oldValue!=null) { 567 removeActionListener(oldValue); 568 oldValue.removePropertyChangeListener(actionPropertyChangeListener); 569 actionPropertyChangeListener = null; 570 } 571 configurePropertiesFromAction(action); 572 if (action!=null) { 573 // Don't add if it is already a listener 574 if (!isListener(ActionListener.class, action)) { 575 addActionListener(action); 576 } 577 // Reverse linkage: 578 actionPropertyChangeListener = createActionPropertyChangeListener(action); 579 action.addPropertyChangeListener(actionPropertyChangeListener); 580 } 581 firePropertyChange("action", oldValue, action); 582 } 583 } 584 585 private boolean isListener(Class<?> c, ActionListener a) { 586 boolean isListener = false; 587 Object[] listeners = listenerList.getListenerList(); 588 for (int i = listeners.length-2; i>=0; i-=2) { 589 if (listeners[i]==c && listeners[i+1]==a) { 590 isListener=true; 591 } 592 } 593 return isListener; 594 } 595 596 /** 597 * Returns the currently set <code>Action</code> for this 598 * <code>ActionEvent</code> source, or <code>null</code> 599 * if no <code>Action</code> is set. 600 * 601 * @return the <code>Action</code> for this <code>ActionEvent</code> source, 602 * or <code>null</code> 603 * @since 1.3 604 * @see Action 605 * @see #setAction 606 */ 607 public Action getAction() { 608 return action; 609 } 610 611 /** 612 * Sets the properties on this textfield to match those in the specified 613 * <code>Action</code>. Refer to <a href="Action.html#buttonActions"> 614 * Swing Components Supporting <code>Action</code></a> for more 615 * details as to which properties this sets. 616 * 617 * @param a the <code>Action</code> from which to get the properties, 618 * or <code>null</code> 619 * @since 1.3 620 * @see Action 621 * @see #setAction 622 */ 623 protected void configurePropertiesFromAction(Action a) { 624 AbstractAction.setEnabledFromAction(this, a); 625 AbstractAction.setToolTipTextFromAction(this, a); 626 setActionCommandFromAction(a); 627 } 628 629 /** 630 * Updates the textfield's state in response to property changes in 631 * associated action. This method is invoked from the 632 * {@code PropertyChangeListener} returned from 633 * {@code createActionPropertyChangeListener}. Subclasses do not normally 634 * need to invoke this. Subclasses that support additional {@code Action} 635 * properties should override this and 636 * {@code configurePropertiesFromAction}. 637 * <p> 638 * Refer to the table at <a href="Action.html#buttonActions"> 639 * Swing Components Supporting <code>Action</code></a> for a list of 640 * the properties this method sets. 641 * 642 * @param action the <code>Action</code> associated with this textfield 643 * @param propertyName the name of the property that changed 644 * @since 1.6 645 * @see Action 646 * @see #configurePropertiesFromAction 647 */ 648 protected void actionPropertyChanged(Action action, String propertyName) { 649 if (propertyName == Action.ACTION_COMMAND_KEY) { 650 setActionCommandFromAction(action); 651 } else if (propertyName == "enabled") { 652 AbstractAction.setEnabledFromAction(this, action); 653 } else if (propertyName == Action.SHORT_DESCRIPTION) { 654 AbstractAction.setToolTipTextFromAction(this, action); 655 } 656 } 657 658 private void setActionCommandFromAction(Action action) { 659 setActionCommand((action == null) ? null : 660 (String)action.getValue(Action.ACTION_COMMAND_KEY)); 661 } 662 663 /** 664 * Creates and returns a <code>PropertyChangeListener</code> that is 665 * responsible for listening for changes from the specified 666 * <code>Action</code> and updating the appropriate properties. 667 * <p> 668 * <b>Warning:</b> If you subclass this do not create an anonymous 669 * inner class. If you do the lifetime of the textfield will be tied to 670 * that of the <code>Action</code>. 671 * 672 * @param a the textfield's action 673 * @return a {@code PropertyChangeListener} that is responsible for 674 * listening for changes from the specified {@code Action} and 675 * updating the appropriate properties 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 @BeanProperty(bound = false) 711 public Action[] getActions() { 712 return TextAction.augmentList(super.getActions(), defaultActions); 713 } 714 715 /** 716 * Processes action events occurring on this textfield by 717 * dispatching them to any registered <code>ActionListener</code> objects. 718 * This is normally called by the controller registered with 719 * textfield. 720 */ 721 public void postActionEvent() { 722 fireActionPerformed(); 723 } 724 725 // --- Scrolling support ----------------------------------- 726 727 /** 728 * Gets the visibility of the text field. This can 729 * be adjusted to change the location of the visible 730 * area if the size of the field is greater than 731 * the area that was allocated to the field. 732 * 733 * <p> 734 * The fields look-and-feel implementation manages 735 * the values of the minimum, maximum, and extent 736 * properties on the <code>BoundedRangeModel</code>. 737 * 738 * @return the visibility 739 * @see BoundedRangeModel 740 */ 741 @BeanProperty(bound = false) 742 public BoundedRangeModel getHorizontalVisibility() { 743 return visibility; 744 } 745 746 /** 747 * Gets the scroll offset, in pixels. 748 * 749 * @return the offset >= 0 750 */ 751 public int getScrollOffset() { 752 return visibility.getValue(); 753 } 754 755 /** 756 * Sets the scroll offset, in pixels. 757 * 758 * @param scrollOffset the offset >= 0 759 */ 760 public void setScrollOffset(int scrollOffset) { 761 visibility.setValue(scrollOffset); 762 } 763 764 /** 765 * Scrolls the field left or right. 766 * 767 * @param r the region to scroll 768 */ 769 public void scrollRectToVisible(Rectangle r) { 770 // convert to coordinate system of the bounded range 771 Insets i = getInsets(); 772 int x0 = r.x + visibility.getValue() - i.left; 773 int x1 = x0 + r.width; 774 if (x0 < visibility.getValue()) { 775 // Scroll to the left 776 visibility.setValue(x0); 777 } else if(x1 > visibility.getValue() + visibility.getExtent()) { 778 // Scroll to the right 779 visibility.setValue(x1 - visibility.getExtent()); 780 } 781 } 782 783 /** 784 * Returns true if the receiver has an <code>ActionListener</code> 785 * installed. 786 */ 787 boolean hasActionListener() { 788 // Guaranteed to return a non-null array 789 Object[] listeners = listenerList.getListenerList(); 790 // Process the listeners last to first, notifying 791 // those that are interested in this event 792 for (int i = listeners.length-2; i>=0; i-=2) { 793 if (listeners[i]==ActionListener.class) { 794 return true; 795 } 796 } 797 return false; 798 } 799 800 // --- variables ------------------------------------------- 801 802 /** 803 * Name of the action to send notification that the 804 * contents of the field have been accepted. Typically 805 * this is bound to a carriage-return. 806 */ 807 public static final String notifyAction = "notify-field-accept"; 808 809 private BoundedRangeModel visibility; 810 private int horizontalAlignment = LEADING; 811 private int columns; 812 private int columnWidth; 813 private String command; 814 815 private static final Action[] defaultActions = { 816 new NotifyAction() 817 }; 818 819 /** 820 * @see #getUIClassID 821 * @see #readObject 822 */ 823 private static final String uiClassID = "TextFieldUI"; 824 825 // --- Action implementations ----------------------------------- 826 827 // Note that JFormattedTextField.CommitAction extends this 828 static class NotifyAction extends TextAction { 829 830 NotifyAction() { 831 super(notifyAction); 832 } 833 834 public void actionPerformed(ActionEvent e) { 835 JTextComponent target = getFocusedComponent(); 836 if (target instanceof JTextField) { 837 JTextField field = (JTextField) target; 838 field.postActionEvent(); 839 } 840 } 841 842 public boolean isEnabled() { 843 JTextComponent target = getFocusedComponent(); 844 if (target instanceof JTextField) { 845 return ((JTextField)target).hasActionListener(); 846 } 847 return false; 848 } 849 } 850 851 class ScrollRepainter implements ChangeListener, Serializable { 852 853 public void stateChanged(ChangeEvent e) { 854 repaint(); 855 } 856 857 } 858 859 860 /** 861 * See <code>readObject</code> and <code>writeObject</code> in 862 * <code>JComponent</code> for more 863 * information about serialization in Swing. 864 */ 865 private void writeObject(ObjectOutputStream s) throws IOException { 866 s.defaultWriteObject(); 867 if (getUIClassID().equals(uiClassID)) { 868 byte count = JComponent.getWriteObjCounter(this); 869 JComponent.setWriteObjCounter(this, --count); 870 if (count == 0 && ui != null) { 871 ui.installUI(this); 872 } 873 } 874 } 875 876 877 /** 878 * Returns a string representation of this <code>JTextField</code>. 879 * This method is intended to be used only for debugging purposes, 880 * and the content and format of the returned string may vary between 881 * implementations. The returned string may be empty but may not 882 * be <code>null</code>. 883 * 884 * @return a string representation of this <code>JTextField</code> 885 */ 886 protected String paramString() { 887 String horizontalAlignmentString; 888 if (horizontalAlignment == LEFT) { 889 horizontalAlignmentString = "LEFT"; 890 } else if (horizontalAlignment == CENTER) { 891 horizontalAlignmentString = "CENTER"; 892 } else if (horizontalAlignment == RIGHT) { 893 horizontalAlignmentString = "RIGHT"; 894 } else if (horizontalAlignment == LEADING) { 895 horizontalAlignmentString = "LEADING"; 896 } else if (horizontalAlignment == TRAILING) { 897 horizontalAlignmentString = "TRAILING"; 898 } else horizontalAlignmentString = ""; 899 String commandString = (command != null ? 900 command : ""); 901 902 return super.paramString() + 903 ",columns=" + columns + 904 ",columnWidth=" + columnWidth + 905 ",command=" + commandString + 906 ",horizontalAlignment=" + horizontalAlignmentString; 907 } 908 909 910 ///////////////// 911 // Accessibility support 912 //////////////// 913 914 915 /** 916 * Gets the <code>AccessibleContext</code> associated with this 917 * <code>JTextField</code>. For <code>JTextFields</code>, 918 * the <code>AccessibleContext</code> takes the form of an 919 * <code>AccessibleJTextField</code>. 920 * A new <code>AccessibleJTextField</code> instance is created 921 * if necessary. 922 * 923 * @return an <code>AccessibleJTextField</code> that serves as the 924 * <code>AccessibleContext</code> of this <code>JTextField</code> 925 */ 926 @BeanProperty(bound = false) 927 public AccessibleContext getAccessibleContext() { 928 if (accessibleContext == null) { 929 accessibleContext = new AccessibleJTextField(); 930 } 931 return accessibleContext; 932 } 933 934 /** 935 * This class implements accessibility support for the 936 * <code>JTextField</code> class. It provides an implementation of the 937 * Java Accessibility API appropriate to text field user-interface 938 * elements. 939 * <p> 940 * <strong>Warning:</strong> 941 * Serialized objects of this class will not be compatible with 942 * future Swing releases. The current serialization support is 943 * appropriate for short term storage or RMI between applications running 944 * the same version of Swing. As of 1.4, support for long term storage 945 * of all JavaBeans™ 946 * has been added to the <code>java.beans</code> package. 947 * Please see {@link java.beans.XMLEncoder}. 948 */ 949 @SuppressWarnings("serial") // Same-version serialization only 950 protected class AccessibleJTextField extends AccessibleJTextComponent { 951 952 /** 953 * Gets the state set of this object. 954 * 955 * @return an instance of AccessibleStateSet describing the states 956 * of the object 957 * @see AccessibleState 958 */ 959 public AccessibleStateSet getAccessibleStateSet() { 960 AccessibleStateSet states = super.getAccessibleStateSet(); 961 states.add(AccessibleState.SINGLE_LINE); 962 return states; 963 } 964 } 965 }