1 /* 2 * Copyright (c) 1997, 2006, 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.*; 30 import javax.swing.text.*; 31 import javax.swing.plaf.*; 32 import javax.swing.event.*; 33 import javax.accessibility.*; 34 35 import java.io.ObjectOutputStream; 36 import java.io.ObjectInputStream; 37 import java.io.IOException; 38 import java.io.Serializable; 39 40 /** 41 * <code>JTextField</code> is a lightweight component that allows the editing 42 * of a single line of text. 43 * For information on and examples of using text fields, 44 * see 45 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/textfield.html">How to Use Text Fields</a> 46 * in <em>The Java Tutorial.</em> 47 * 48 * <p> 49 * <code>JTextField</code> is intended to be source-compatible 50 * with <code>java.awt.TextField</code> where it is reasonable to do so. This 51 * component has capabilities not found in the <code>java.awt.TextField</code> 52 * class. The superclass should be consulted for additional capabilities. 53 * <p> 54 * <code>JTextField</code> has a method to establish the string used as the 55 * command string for the action event that gets fired. The 56 * <code>java.awt.TextField</code> used the text of the field as the command 57 * string for the <code>ActionEvent</code>. 58 * <code>JTextField</code> will use the command 59 * string set with the <code>setActionCommand</code> method if not <code>null</code>, 60 * otherwise it will use the text of the field as a compatibility with 61 * <code>java.awt.TextField</code>. 62 * <p> 63 * The method <code>setEchoChar</code> and <code>getEchoChar</code> 64 * are not provided directly to avoid a new implementation of a 65 * pluggable look-and-feel inadvertently exposing password characters. 66 * To provide password-like services a separate class <code>JPasswordField</code> 67 * extends <code>JTextField</code> to provide this service with an independently 68 * pluggable look-and-feel. 69 * <p> 70 * The <code>java.awt.TextField</code> could be monitored for changes by adding 71 * a <code>TextListener</code> for <code>TextEvent</code>'s. 72 * In the <code>JTextComponent</code> based 73 * components, changes are broadcasted from the model via a 74 * <code>DocumentEvent</code> to <code>DocumentListeners</code>. 75 * The <code>DocumentEvent</code> gives 76 * the location of the change and the kind of change if desired. 77 * The code fragment might look something like: 78 * <pre><code> 79 * DocumentListener myListener = ??; 80 * JTextField myArea = ??; 81 * myArea.getDocument().addDocumentListener(myListener); 82 * </code></pre> 83 * <p> 84 * The horizontal alignment of <code>JTextField</code> can be set to be left 85 * justified, leading justified, centered, right justified or trailing justified. 86 * Right/trailing justification is useful if the required size 87 * of the field text is smaller than the size allocated to it. 88 * This is determined by the <code>setHorizontalAlignment</code> 89 * and <code>getHorizontalAlignment</code> methods. The default 90 * is to be leading justified. 91 * <p> 92 * How the text field consumes VK_ENTER events depends 93 * on whether the text field has any action listeners. 94 * If so, then VK_ENTER results in the listeners 95 * getting an ActionEvent, 96 * and the VK_ENTER event is consumed. 97 * This is compatible with how AWT text fields handle VK_ENTER events. 98 * If the text field has no action listeners, then as of v 1.3 the VK_ENTER 99 * event is not consumed. Instead, the bindings of ancestor components 100 * are processed, which enables the default button feature of 101 * JFC/Swing to work. 102 * <p> 103 * Customized fields can easily be created by extending the model and 104 * changing the default model provided. For example, the following piece 105 * of code will create a field that holds only upper case characters. It 106 * will work even if text is pasted into from the clipboard or it is altered via 107 * programmatic changes. 108 * <pre><code> 109 110 public class UpperCaseField extends JTextField { 111 112 public UpperCaseField(int cols) { 113 super(cols); 114 } 115 116 protected Document createDefaultModel() { 117 return new UpperCaseDocument(); 118 } 119 120 static class UpperCaseDocument extends PlainDocument { 121 122 public void insertString(int offs, String str, AttributeSet a) 123 throws BadLocationException { 124 125 if (str == null) { 126 return; 127 } 128 char[] upper = str.toCharArray(); 129 for (int i = 0; i < upper.length; i++) { 130 upper[i] = Character.toUpperCase(upper[i]); 131 } 132 super.insertString(offs, new String(upper), a); 133 } 134 } 135 } 136 137 * </code></pre> 138 * <p> 139 * <strong>Warning:</strong> Swing is not thread safe. For more 140 * information see <a 141 * href="package-summary.html#threading">Swing's Threading 142 * Policy</a>. 143 * <p> 144 * <strong>Warning:</strong> 145 * Serialized objects of this class will not be compatible with 146 * future Swing releases. The current serialization support is 147 * appropriate for short term storage or RMI between applications running 148 * the same version of Swing. As of 1.4, support for long term storage 149 * of all JavaBeans<sup><font size="-2">TM</font></sup> 150 * has been added to the <code>java.beans</code> package. 151 * Please see {@link java.beans.XMLEncoder}. 152 * 153 * @beaninfo 154 * attribute: isContainer false 155 * description: A component which allows for the editing of a single line of text. 156 * 157 * @author Timothy Prinzing 158 * @see #setActionCommand 159 * @see JPasswordField 160 * @see #addActionListener 161 */ 162 public class JTextField extends JTextComponent implements SwingConstants { 163 164 /** 165 * Constructs a new <code>TextField</code>. A default model is created, 166 * the initial string is <code>null</code>, 167 * and the number of columns is set to 0. 168 */ 169 public JTextField() { 170 this(null, null, 0); 171 } 172 173 /** 174 * Constructs a new <code>TextField</code> initialized with the 175 * specified text. A default model is created and the number of 176 * columns is 0. 177 * 178 * @param text the text to be displayed, or <code>null</code> 179 */ 180 public JTextField(String text) { 181 this(null, text, 0); 182 } 183 184 /** 185 * Constructs a new empty <code>TextField</code> with the specified 186 * number of columns. 187 * A default model is created and the initial string is set to 188 * <code>null</code>. 189 * 190 * @param columns the number of columns to use to calculate 191 * the preferred width; if columns is set to zero, the 192 * preferred width will be whatever naturally results from 193 * the component implementation 194 */ 195 public JTextField(int columns) { 196 this(null, null, columns); 197 } 198 199 /** 200 * Constructs a new <code>TextField</code> initialized with the 201 * specified text and columns. A default model is created. 202 * 203 * @param text the text to be displayed, or <code>null</code> 204 * @param columns the number of columns to use to calculate 205 * the preferred width; if columns is set to zero, the 206 * preferred width will be whatever naturally results from 207 * the component implementation 208 */ 209 public JTextField(String text, int columns) { 210 this(null, text, columns); 211 } 212 213 /** 214 * Constructs a new <code>JTextField</code> that uses the given text 215 * storage model and the given number of columns. 216 * This is the constructor through which the other constructors feed. 217 * If the document is <code>null</code>, a default model is created. 218 * 219 * @param doc the text storage to use; if this is <code>null</code>, 220 * a default will be provided by calling the 221 * <code>createDefaultModel</code> method 222 * @param text the initial string to display, or <code>null</code> 223 * @param columns the number of columns to use to calculate 224 * the preferred width >= 0; if <code>columns</code> 225 * is set to zero, the preferred width will be whatever 226 * naturally results from the component implementation 227 * @exception IllegalArgumentException if <code>columns</code> < 0 228 */ 229 public JTextField(Document doc, String text, int columns) { 230 if (columns < 0) { 231 throw new IllegalArgumentException("columns less than zero."); 232 } 233 visibility = new DefaultBoundedRangeModel(); 234 visibility.addChangeListener(new ScrollRepainter()); 235 this.columns = columns; 236 if (doc == null) { 237 doc = createDefaultModel(); 238 } 239 setDocument(doc); 240 if (text != null) { 241 setText(text); 242 } 243 } 244 245 /** 246 * Gets the class ID for a UI. 247 * 248 * @return the string "TextFieldUI" 249 * @see JComponent#getUIClassID 250 * @see UIDefaults#getUI 251 */ 252 public String getUIClassID() { 253 return uiClassID; 254 } 255 256 257 /** 258 * Associates the editor with a text document. 259 * The currently registered factory is used to build a view for 260 * the document, which gets displayed by the editor after revalidation. 261 * A PropertyChange event ("document") is propagated to each listener. 262 * 263 * @param doc the document to display/edit 264 * @see #getDocument 265 * @beaninfo 266 * description: the text document model 267 * bound: true 268 * expert: true 269 */ 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 */ 290 public boolean isValidateRoot() { 291 Component parent = getParent(); 292 if (parent instanceof JViewport) { 293 return false; 294 } 295 return true; 296 } 297 298 299 /** 300 * Returns the horizontal alignment of the text. 301 * Valid keys are: 302 * <ul> 303 * <li><code>JTextField.LEFT</code> 304 * <li><code>JTextField.CENTER</code> 305 * <li><code>JTextField.RIGHT</code> 306 * <li><code>JTextField.LEADING</code> 307 * <li><code>JTextField.TRAILING</code> 308 * </ul> 309 * 310 * @return the horizontal alignment 311 */ 312 public int getHorizontalAlignment() { 313 return horizontalAlignment; 314 } 315 316 /** 317 * Sets the horizontal alignment of the text. 318 * Valid keys are: 319 * <ul> 320 * <li><code>JTextField.LEFT</code> 321 * <li><code>JTextField.CENTER</code> 322 * <li><code>JTextField.RIGHT</code> 323 * <li><code>JTextField.LEADING</code> 324 * <li><code>JTextField.TRAILING</code> 325 * </ul> 326 * <code>invalidate</code> and <code>repaint</code> are called when the 327 * alignment is set, 328 * and a <code>PropertyChange</code> event ("horizontalAlignment") is fired. 329 * 330 * @param alignment the alignment 331 * @exception IllegalArgumentException if <code>alignment</code> 332 * is not a valid key 333 * @beaninfo 334 * preferred: true 335 * bound: true 336 * description: Set the field alignment to LEFT, CENTER, RIGHT, 337 * LEADING (the default) or TRAILING 338 * enum: LEFT JTextField.LEFT CENTER JTextField.CENTER RIGHT JTextField.RIGHT 339 * LEADING JTextField.LEADING TRAILING JTextField.TRAILING 340 */ 341 public void setHorizontalAlignment(int alignment) { 342 if (alignment == horizontalAlignment) return; 343 int oldValue = horizontalAlignment; 344 if ((alignment == LEFT) || (alignment == CENTER) || 345 (alignment == RIGHT)|| (alignment == LEADING) || 346 (alignment == TRAILING)) { 347 horizontalAlignment = alignment; 348 } else { 349 throw new IllegalArgumentException("horizontalAlignment"); 350 } 351 firePropertyChange("horizontalAlignment", oldValue, horizontalAlignment); 352 invalidate(); 353 repaint(); 354 } 355 356 /** 357 * Creates the default implementation of the model 358 * to be used at construction if one isn't explicitly 359 * given. An instance of <code>PlainDocument</code> is returned. 360 * 361 * @return the default model implementation 362 */ 363 protected Document createDefaultModel() { 364 return new PlainDocument(); 365 } 366 367 /** 368 * Returns the number of columns in this <code>TextField</code>. 369 * 370 * @return the number of columns >= 0 371 */ 372 public int getColumns() { 373 return columns; 374 } 375 376 /** 377 * Sets the number of columns in this <code>TextField</code>, 378 * and then invalidate the layout. 379 * 380 * @param columns the number of columns >= 0 381 * @exception IllegalArgumentException if <code>columns</code> 382 * is less than 0 383 * @beaninfo 384 * description: the number of columns preferred for display 385 */ 386 public void setColumns(int columns) { 387 int oldVal = this.columns; 388 if (columns < 0) { 389 throw new IllegalArgumentException("columns less than zero."); 390 } 391 if (columns != oldVal) { 392 this.columns = columns; 393 invalidate(); 394 } 395 } 396 397 /** 398 * Returns the column width. 399 * The meaning of what a column is can be considered a fairly weak 400 * notion for some fonts. This method is used to define the width 401 * of a column. By default this is defined to be the width of the 402 * character <em>m</em> for the font used. This method can be 403 * redefined to be some alternative amount 404 * 405 * @return the column width >= 1 406 */ 407 protected int getColumnWidth() { 408 if (columnWidth == 0) { 409 FontMetrics metrics = getFontMetrics(getFont()); 410 columnWidth = metrics.charWidth('m'); 411 } 412 return columnWidth; 413 } 414 415 /** 416 * Returns the preferred size <code>Dimensions</code> needed for this 417 * <code>TextField</code>. If a non-zero number of columns has been 418 * set, the width is set to the columns multiplied by 419 * the column width. 420 * 421 * @return the dimension of this textfield 422 */ 423 public Dimension getPreferredSize() { 424 Dimension size = super.getPreferredSize(); 425 if (columns != 0) { 426 Insets insets = getInsets(); 427 size.width = columns * getColumnWidth() + 428 insets.left + insets.right; 429 } 430 return size; 431 } 432 433 /** 434 * Sets the current font. This removes cached row height and column 435 * width so the new font will be reflected. 436 * <code>revalidate</code> is called after setting the font. 437 * 438 * @param f the new font 439 */ 440 public void setFont(Font f) { 441 super.setFont(f); 442 columnWidth = 0; 443 } 444 445 /** 446 * Adds the specified action listener to receive 447 * action events from this textfield. 448 * 449 * @param l the action listener to be added 450 */ 451 public synchronized void addActionListener(ActionListener l) { 452 listenerList.add(ActionListener.class, l); 453 } 454 455 /** 456 * Removes the specified action listener so that it no longer 457 * receives action events from this textfield. 458 * 459 * @param l the action listener to be removed 460 */ 461 public synchronized void removeActionListener(ActionListener l) { 462 if ((l != null) && (getAction() == l)) { 463 setAction(null); 464 } else { 465 listenerList.remove(ActionListener.class, l); 466 } 467 } 468 469 /** 470 * Returns an array of all the <code>ActionListener</code>s added 471 * to this JTextField with addActionListener(). 472 * 473 * @return all of the <code>ActionListener</code>s added or an empty 474 * array if no listeners have been added 475 * @since 1.4 476 */ 477 public synchronized ActionListener[] getActionListeners() { 478 return (ActionListener[])listenerList.getListeners( 479 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<sup><font size="-2">TM</font></sup> 944 * has been added to the <code>java.beans</code> package. 945 * Please see {@link java.beans.XMLEncoder}. 946 */ 947 protected class AccessibleJTextField extends AccessibleJTextComponent { 948 949 /** 950 * Gets the state set of this object. 951 * 952 * @return an instance of AccessibleStateSet describing the states 953 * of the object 954 * @see AccessibleState 955 */ 956 public AccessibleStateSet getAccessibleStateSet() { 957 AccessibleStateSet states = super.getAccessibleStateSet(); 958 states.add(AccessibleState.SINGLE_LINE); 959 return states; 960 } 961 } 962 }