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