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.awt.im.InputContext; 30 import java.io.*; 31 import java.text.*; 32 import java.util.*; 33 import javax.swing.event.*; 34 import javax.swing.plaf.UIResource; 35 import javax.swing.text.*; 36 37 /** 38 * <code>JFormattedTextField</code> extends <code>JTextField</code> adding 39 * support for formatting arbitrary values, as well as retrieving a particular 40 * object once the user has edited the text. The following illustrates 41 * configuring a <code>JFormattedTextField</code> to edit dates: 42 * <pre> 43 * JFormattedTextField ftf = new JFormattedTextField(); 44 * ftf.setValue(new Date()); 45 * </pre> 46 * <p> 47 * Once a <code>JFormattedTextField</code> has been created, you can 48 * listen for editing changes by way of adding 49 * a <code>PropertyChangeListener</code> and listening for 50 * <code>PropertyChangeEvent</code>s with the property name <code>value</code>. 51 * <p> 52 * <code>JFormattedTextField</code> allows 53 * configuring what action should be taken when focus is lost. The possible 54 * configurations are: 55 * <table summary="Possible JFormattedTextField configurations and their descriptions"> 56 * <tr><th><p style="text-align:left">Value</p></th><th><p style="text-align:left">Description</p></th></tr> 57 * <tr><td>JFormattedTextField.REVERT 58 * <td>Revert the display to match that of <code>getValue</code>, 59 * possibly losing the current edit. 60 * <tr><td>JFormattedTextField.COMMIT 61 * <td>Commits the current value. If the value being edited 62 * isn't considered a legal value by the 63 * <code>AbstractFormatter</code> that is, a 64 * <code>ParseException</code> is thrown, then the value 65 * will not change, and then edited value will persist. 66 * <tr><td>JFormattedTextField.COMMIT_OR_REVERT 67 * <td>Similar to <code>COMMIT</code>, but if the value isn't 68 * legal, behave like <code>REVERT</code>. 69 * <tr><td>JFormattedTextField.PERSIST 70 * <td>Do nothing, don't obtain a new 71 * <code>AbstractFormatter</code>, and don't update the value. 72 * </table> 73 * The default is <code>JFormattedTextField.COMMIT_OR_REVERT</code>, 74 * refer to {@link #setFocusLostBehavior} for more information on this. 75 * <p> 76 * <code>JFormattedTextField</code> allows the focus to leave, even if 77 * the currently edited value is invalid. To lock the focus down while the 78 * <code>JFormattedTextField</code> is an invalid edit state 79 * you can attach an <code>InputVerifier</code>. The following code snippet 80 * shows a potential implementation of such an <code>InputVerifier</code>: 81 * <pre> 82 * public class FormattedTextFieldVerifier extends InputVerifier { 83 * public boolean verify(JComponent input) { 84 * if (input instanceof JFormattedTextField) { 85 * JFormattedTextField ftf = (JFormattedTextField)input; 86 * AbstractFormatter formatter = ftf.getFormatter(); 87 * if (formatter != null) { 88 * String text = ftf.getText(); 89 * try { 90 * formatter.stringToValue(text); 91 * return true; 92 * } catch (ParseException pe) { 93 * return false; 94 * } 95 * } 96 * } 97 * return true; 98 * } 99 * public boolean shouldYieldFocus(JComponent input) { 100 * return verify(input); 101 * } 102 * } 103 * </pre> 104 * <p> 105 * Alternatively, you could invoke <code>commitEdit</code>, which would also 106 * commit the value. 107 * <p> 108 * <code>JFormattedTextField</code> does not do the formatting it self, 109 * rather formatting is done through an instance of 110 * <code>JFormattedTextField.AbstractFormatter</code> which is obtained from 111 * an instance of <code>JFormattedTextField.AbstractFormatterFactory</code>. 112 * Instances of <code>JFormattedTextField.AbstractFormatter</code> are 113 * notified when they become active by way of the 114 * <code>install</code> method, at which point the 115 * <code>JFormattedTextField.AbstractFormatter</code> can install whatever 116 * it needs to, typically a <code>DocumentFilter</code>. Similarly when 117 * <code>JFormattedTextField</code> no longer 118 * needs the <code>AbstractFormatter</code>, it will invoke 119 * <code>uninstall</code>. 120 * <p> 121 * <code>JFormattedTextField</code> typically 122 * queries the <code>AbstractFormatterFactory</code> for an 123 * <code>AbstractFormat</code> when it gains or loses focus. Although this 124 * can change based on the focus lost policy. If the focus lost 125 * policy is <code>JFormattedTextField.PERSIST</code> 126 * and the <code>JFormattedTextField</code> has been edited, the 127 * <code>AbstractFormatterFactory</code> will not be queried until the 128 * value has been committed. Similarly if the focus lost policy is 129 * <code>JFormattedTextField.COMMIT</code> and an exception 130 * is thrown from <code>stringToValue</code>, the 131 * <code>AbstractFormatterFactory</code> will not be queried when focus is 132 * lost or gained. 133 * <p> 134 * <code>JFormattedTextField.AbstractFormatter</code> 135 * is also responsible for determining when values are committed to 136 * the <code>JFormattedTextField</code>. Some 137 * <code>JFormattedTextField.AbstractFormatter</code>s will make new values 138 * available on every edit, and others will never commit the value. You can 139 * force the current value to be obtained 140 * from the current <code>JFormattedTextField.AbstractFormatter</code> 141 * by way of invoking <code>commitEdit</code>. <code>commitEdit</code> will 142 * be invoked whenever return is pressed in the 143 * <code>JFormattedTextField</code>. 144 * <p> 145 * If an <code>AbstractFormatterFactory</code> has not been explicitly 146 * set, one will be set based on the <code>Class</code> of the value type after 147 * <code>setValue</code> has been invoked (assuming value is non-null). 148 * For example, in the following code an appropriate 149 * <code>AbstractFormatterFactory</code> and <code>AbstractFormatter</code> 150 * will be created to handle formatting of numbers: 151 * <pre> 152 * JFormattedTextField tf = new JFormattedTextField(); 153 * tf.setValue(100); 154 * </pre> 155 * <p> 156 * <strong>Warning:</strong> As the <code>AbstractFormatter</code> will 157 * typically install a <code>DocumentFilter</code> on the 158 * <code>Document</code>, and a <code>NavigationFilter</code> on the 159 * <code>JFormattedTextField</code> you should not install your own. If you do, 160 * you are likely to see odd behavior in that the editing policy of the 161 * <code>AbstractFormatter</code> will not be enforced. 162 * <p> 163 * <strong>Warning:</strong> Swing is not thread safe. For more 164 * information see <a 165 * href="package-summary.html#threading">Swing's Threading 166 * Policy</a>. 167 * <p> 168 * <strong>Warning:</strong> 169 * Serialized objects of this class will not be compatible with 170 * future Swing releases. The current serialization support is 171 * appropriate for short term storage or RMI between applications running 172 * the same version of Swing. As of 1.4, support for long term storage 173 * of all JavaBeans™ 174 * has been added to the <code>java.beans</code> package. 175 * Please see {@link java.beans.XMLEncoder}. 176 * 177 * @since 1.4 178 */ 179 @SuppressWarnings("serial") // Same-version serialization only 180 public class JFormattedTextField extends JTextField { 181 private static final String uiClassID = "FormattedTextFieldUI"; 182 private static final Action[] defaultActions = 183 { new CommitAction(), new CancelAction() }; 184 185 /** 186 * Constant identifying that when focus is lost, 187 * <code>commitEdit</code> should be invoked. If in committing the 188 * new value a <code>ParseException</code> is thrown, the invalid 189 * value will remain. 190 * 191 * @see #setFocusLostBehavior 192 */ 193 public static final int COMMIT = 0; 194 195 /** 196 * Constant identifying that when focus is lost, 197 * <code>commitEdit</code> should be invoked. If in committing the new 198 * value a <code>ParseException</code> is thrown, the value will be 199 * reverted. 200 * 201 * @see #setFocusLostBehavior 202 */ 203 public static final int COMMIT_OR_REVERT = 1; 204 205 /** 206 * Constant identifying that when focus is lost, editing value should 207 * be reverted to current value set on the 208 * <code>JFormattedTextField</code>. 209 * 210 * @see #setFocusLostBehavior 211 */ 212 public static final int REVERT = 2; 213 214 /** 215 * Constant identifying that when focus is lost, the edited value 216 * should be left. 217 * 218 * @see #setFocusLostBehavior 219 */ 220 public static final int PERSIST = 3; 221 222 223 /** 224 * Factory used to obtain an instance of AbstractFormatter. 225 */ 226 private AbstractFormatterFactory factory; 227 /** 228 * Object responsible for formatting the current value. 250 private DocumentListener documentListener; 251 /** 252 * Masked used to set the AbstractFormatterFactory. 253 */ 254 private Object mask; 255 /** 256 * ActionMap that the TextFormatter Actions are added to. 257 */ 258 private ActionMap textFormatterActionMap; 259 /** 260 * Indicates the input method composed text is in the document 261 */ 262 private boolean composedTextExists = false; 263 /** 264 * A handler for FOCUS_LOST event 265 */ 266 private FocusLostHandler focusLostHandler; 267 268 269 /** 270 * Creates a <code>JFormattedTextField</code> with no 271 * <code>AbstractFormatterFactory</code>. Use <code>setMask</code> or 272 * <code>setFormatterFactory</code> to configure the 273 * <code>JFormattedTextField</code> to edit a particular type of 274 * value. 275 */ 276 public JFormattedTextField() { 277 super(); 278 enableEvents(AWTEvent.FOCUS_EVENT_MASK); 279 setFocusLostBehavior(COMMIT_OR_REVERT); 280 } 281 282 /** 283 * Creates a JFormattedTextField with the specified value. This will 284 * create an <code>AbstractFormatterFactory</code> based on the 285 * type of <code>value</code>. 286 * 287 * @param value Initial value for the JFormattedTextField 288 */ 289 public JFormattedTextField(Object value) { 290 this(); 291 setValue(value); 292 } 293 294 /** 295 * Creates a <code>JFormattedTextField</code>. <code>format</code> is 296 * wrapped in an appropriate <code>AbstractFormatter</code> which is 297 * then wrapped in an <code>AbstractFormatterFactory</code>. 298 * 299 * @param format Format used to look up an AbstractFormatter 300 */ 301 public JFormattedTextField(java.text.Format format) { 302 this(); 303 setFormatterFactory(getDefaultFormatterFactory(format)); 304 } 305 306 /** 307 * Creates a <code>JFormattedTextField</code> with the specified 308 * <code>AbstractFormatter</code>. The <code>AbstractFormatter</code> 309 * is placed in an <code>AbstractFormatterFactory</code>. 310 * 311 * @param formatter AbstractFormatter to use for formatting. 312 */ 313 public JFormattedTextField(AbstractFormatter formatter) { 314 this(new DefaultFormatterFactory(formatter)); 315 } 316 317 /** 318 * Creates a <code>JFormattedTextField</code> with the specified 319 * <code>AbstractFormatterFactory</code>. 320 * 321 * @param factory AbstractFormatterFactory used for formatting. 322 */ 323 public JFormattedTextField(AbstractFormatterFactory factory) { 324 this(); 325 setFormatterFactory(factory); 326 } 327 328 /** 329 * Creates a <code>JFormattedTextField</code> with the specified 330 * <code>AbstractFormatterFactory</code> and initial value. 331 * 332 * @param factory <code>AbstractFormatterFactory</code> used for 333 * formatting. 334 * @param currentValue Initial value to use 335 */ 336 public JFormattedTextField(AbstractFormatterFactory factory, 337 Object currentValue) { 338 this(currentValue); 339 setFormatterFactory(factory); 340 } 341 342 /** 343 * Sets the behavior when focus is lost. This will be one of 344 * <code>JFormattedTextField.COMMIT_OR_REVERT</code>, 345 * <code>JFormattedTextField.REVERT</code>, 346 * <code>JFormattedTextField.COMMIT</code> or 347 * <code>JFormattedTextField.PERSIST</code> 348 * Note that some <code>AbstractFormatter</code>s may push changes as 349 * they occur, so that the value of this will have no effect. 350 * <p> 351 * This will throw an <code>IllegalArgumentException</code> if the object 352 * passed in is not one of the afore mentioned values. 353 * <p> 354 * The default value of this property is 355 * <code>JFormattedTextField.COMMIT_OR_REVERT</code>. 356 * 357 * @param behavior Identifies behavior when focus is lost 358 * @throws IllegalArgumentException if behavior is not one of the known 359 * values 360 * @beaninfo 361 * enum: COMMIT JFormattedTextField.COMMIT 362 * COMMIT_OR_REVERT JFormattedTextField.COMMIT_OR_REVERT 363 * REVERT JFormattedTextField.REVERT 364 * PERSIST JFormattedTextField.PERSIST 365 * description: Behavior when component loses focus 366 */ 367 public void setFocusLostBehavior(int behavior) { 368 if (behavior != COMMIT && behavior != COMMIT_OR_REVERT && 369 behavior != PERSIST && behavior != REVERT) { 370 throw new IllegalArgumentException("setFocusLostBehavior must be one of: JFormattedTextField.COMMIT, JFormattedTextField.COMMIT_OR_REVERT, JFormattedTextField.PERSIST or JFormattedTextField.REVERT"); 371 } 372 focusLostBehavior = behavior; 373 } 374 375 /** 376 * Returns the behavior when focus is lost. This will be one of 377 * <code>COMMIT_OR_REVERT</code>, 378 * <code>COMMIT</code>, 379 * <code>REVERT</code> or 380 * <code>PERSIST</code> 381 * Note that some <code>AbstractFormatter</code>s may push changes as 382 * they occur, so that the value of this will have no effect. 383 * 384 * @return returns behavior when focus is lost 385 */ 386 public int getFocusLostBehavior() { 387 return focusLostBehavior; 388 } 389 390 /** 391 * Sets the <code>AbstractFormatterFactory</code>. 392 * <code>AbstractFormatterFactory</code> is 393 * able to return an instance of <code>AbstractFormatter</code> that is 394 * used to format a value for display, as well an enforcing an editing 395 * policy. 396 * <p> 397 * If you have not explicitly set an <code>AbstractFormatterFactory</code> 398 * by way of this method (or a constructor) an 399 * <code>AbstractFormatterFactory</code> and consequently an 400 * <code>AbstractFormatter</code> will be used based on the 401 * <code>Class</code> of the value. <code>NumberFormatter</code> will 402 * be used for <code>Number</code>s, <code>DateFormatter</code> will 403 * be used for <code>Dates</code>, otherwise <code>DefaultFormatter</code> 404 * will be used. 405 * <p> 406 * This is a JavaBeans bound property. 407 * 408 * @param tf <code>AbstractFormatterFactory</code> used to lookup 409 * instances of <code>AbstractFormatter</code> 410 * @beaninfo 411 * bound: true 412 * attribute: visualUpdate true 413 * description: AbstractFormatterFactory, responsible for returning an 414 * AbstractFormatter that can format the current value. 415 */ 416 public void setFormatterFactory(AbstractFormatterFactory tf) { 417 AbstractFormatterFactory oldFactory = factory; 418 419 factory = tf; 420 firePropertyChange("formatterFactory", oldFactory, tf); 421 setValue(getValue(), true, false); 422 } 423 424 /** 425 * Returns the current <code>AbstractFormatterFactory</code>. 426 * 427 * @see #setFormatterFactory 428 * @return <code>AbstractFormatterFactory</code> used to determine 429 * <code>AbstractFormatter</code>s 430 */ 431 public AbstractFormatterFactory getFormatterFactory() { 432 return factory; 433 } 434 435 /** 436 * Sets the current <code>AbstractFormatter</code>. 437 * <p> 438 * You should not normally invoke this, instead set the 439 * <code>AbstractFormatterFactory</code> or set the value. 440 * <code>JFormattedTextField</code> will 441 * invoke this as the state of the <code>JFormattedTextField</code> 442 * changes and requires the value to be reset. 443 * <code>JFormattedTextField</code> passes in the 444 * <code>AbstractFormatter</code> obtained from the 445 * <code>AbstractFormatterFactory</code>. 446 * <p> 447 * This is a JavaBeans bound property. 448 * 449 * @see #setFormatterFactory 450 * @param format AbstractFormatter to use for formatting 451 * @beaninfo 452 * bound: true 453 * attribute: visualUpdate true 454 * description: TextFormatter, responsible for formatting the current value 455 */ 456 protected void setFormatter(AbstractFormatter format) { 457 AbstractFormatter oldFormat = this.format; 458 459 if (oldFormat != null) { 460 oldFormat.uninstall(); 461 } 462 setEditValid(true); 463 this.format = format; 464 if (format != null) { 465 format.install(this); 466 } 467 setEdited(false); 468 firePropertyChange("textFormatter", oldFormat, format); 469 } 470 471 /** 472 * Returns the <code>AbstractFormatter</code> that is used to format and 473 * parse the current value. 474 * 475 * @return AbstractFormatter used for formatting 476 */ 477 public AbstractFormatter getFormatter() { 478 return format; 479 } 480 481 /** 482 * Sets the value that will be formatted by an 483 * <code>AbstractFormatter</code> obtained from the current 484 * <code>AbstractFormatterFactory</code>. If no 485 * <code>AbstractFormatterFactory</code> has been specified, this will 486 * attempt to create one based on the type of <code>value</code>. 487 * <p> 488 * The default value of this property is null. 489 * <p> 490 * This is a JavaBeans bound property. 491 * 492 * @param value Current value to display 493 * @beaninfo 494 * bound: true 495 * attribute: visualUpdate true 496 * description: The value to be formatted. 497 */ 498 public void setValue(Object value) { 499 if (value != null && getFormatterFactory() == null) { 500 setFormatterFactory(getDefaultFormatterFactory(value)); 501 } 502 setValue(value, true, true); 503 } 504 505 /** 506 * Returns the last valid value. Based on the editing policy of 507 * the <code>AbstractFormatter</code> this may not return the current 508 * value. The currently edited value can be obtained by invoking 509 * <code>commitEdit</code> followed by <code>getValue</code>. 510 * 511 * @return Last valid value 512 */ 513 public Object getValue() { 514 return value; 515 } 516 517 /** 518 * Forces the current value to be taken from the 519 * <code>AbstractFormatter</code> and set as the current value. 520 * This has no effect if there is no current 521 * <code>AbstractFormatter</code> installed. 522 * 523 * @throws ParseException if the <code>AbstractFormatter</code> is not able 524 * to format the current value 525 */ 526 public void commitEdit() throws ParseException { 527 AbstractFormatter format = getFormatter(); 528 529 if (format != null) { 530 setValue(format.stringToValue(getText()), false, true); 531 } 532 } 533 534 /** 535 * Sets the validity of the edit on the receiver. You should not normally 536 * invoke this. This will be invoked by the 537 * <code>AbstractFormatter</code> as the user edits the value. 538 * <p> 539 * Not all formatters will allow the component to get into an invalid 540 * state, and thus this may never be invoked. 541 * <p> 542 * Based on the look and feel this may visually change the state of 543 * the receiver. 544 * 545 * @param isValid boolean indicating if the currently edited value is 546 * valid. 547 * @beaninfo 548 * bound: true 549 * attribute: visualUpdate true 550 * description: True indicates the edited value is valid 551 */ 552 private void setEditValid(boolean isValid) { 553 if (isValid != editValid) { 554 editValid = isValid; 555 firePropertyChange("editValid", Boolean.valueOf(!isValid), 556 Boolean.valueOf(isValid)); 557 } 558 } 559 560 /** 561 * Returns true if the current value being edited is valid. The value of 562 * this is managed by the current <code>AbstractFormatter</code>, as such 563 * there is no public setter for it. 564 * 565 * @return true if the current value being edited is valid. 566 */ 567 public boolean isEditValid() { 568 return editValid; 569 } 570 571 /** 572 * Invoked when the user inputs an invalid value. This gives the 573 * component a chance to provide feedback. The default 574 * implementation beeps. 575 */ 576 protected void invalidEdit() { 577 UIManager.getLookAndFeel().provideErrorFeedback(JFormattedTextField.this); 578 } 579 580 /** 581 * Processes any input method events, such as 582 * <code>InputMethodEvent.INPUT_METHOD_TEXT_CHANGED</code> or 583 * <code>InputMethodEvent.CARET_POSITION_CHANGED</code>. 584 * 585 * @param e the <code>InputMethodEvent</code> 586 * @see InputMethodEvent 587 */ 588 protected void processInputMethodEvent(InputMethodEvent e) { 589 AttributedCharacterIterator text = e.getText(); 590 int commitCount = e.getCommittedCharacterCount(); 591 592 // Keep track of the composed text 593 if (text != null) { 594 int begin = text.getBeginIndex(); 595 int end = text.getEndIndex(); 596 composedTextExists = ((end - begin) > commitCount); 597 } else { 598 composedTextExists = false; 599 } 600 601 super.processInputMethodEvent(e); 602 } 603 604 /** 605 * Processes any focus events, such as 606 * <code>FocusEvent.FOCUS_GAINED</code> or 607 * <code>FocusEvent.FOCUS_LOST</code>. 608 * 609 * @param e the <code>FocusEvent</code> 610 * @see FocusEvent 611 */ 612 protected void processFocusEvent(FocusEvent e) { 613 super.processFocusEvent(e); 614 615 // ignore temporary focus event 616 if (e.isTemporary()) { 617 return; 618 } 619 620 if (isEdited() && e.getID() == FocusEvent.FOCUS_LOST) { 621 InputContext ic = getInputContext(); 622 if (focusLostHandler == null) { 623 focusLostHandler = new FocusLostHandler(); 624 } 625 626 // if there is a composed text, process it first 627 if ((ic != null) && composedTextExists) { 628 ic.endComposition(); 629 EventQueue.invokeLater(focusLostHandler); 713 714 /* 715 * See readObject and writeObject in JComponent for more 716 * information about serialization in Swing. 717 * 718 * @param s Stream to write to 719 */ 720 private void writeObject(ObjectOutputStream s) throws IOException { 721 s.defaultWriteObject(); 722 if (getUIClassID().equals(uiClassID)) { 723 byte count = JComponent.getWriteObjCounter(this); 724 JComponent.setWriteObjCounter(this, --count); 725 if (count == 0 && ui != null) { 726 ui.installUI(this); 727 } 728 } 729 } 730 731 /** 732 * Resets the Actions that come from the TextFormatter to 733 * <code>actions</code>. 734 */ 735 private void setFormatterActions(Action[] actions) { 736 if (actions == null) { 737 if (textFormatterActionMap != null) { 738 textFormatterActionMap.clear(); 739 } 740 } 741 else { 742 if (textFormatterActionMap == null) { 743 ActionMap map = getActionMap(); 744 745 textFormatterActionMap = new ActionMap(); 746 while (map != null) { 747 ActionMap parent = map.getParent(); 748 749 if (parent instanceof UIResource || parent == null) { 750 map.setParent(textFormatterActionMap); 751 textFormatterActionMap.setParent(parent); 752 break; 753 } 754 map = parent; 755 } 756 } 757 for (int counter = actions.length - 1; counter >= 0; 758 counter--) { 759 Object key = actions[counter].getValue(Action.NAME); 760 761 if (key != null) { 762 textFormatterActionMap.put(key, actions[counter]); 763 } 764 } 765 } 766 } 767 768 /** 769 * Does the setting of the value. If <code>createFormat</code> is true, 770 * this will also obtain a new <code>AbstractFormatter</code> from the 771 * current factory. The property change event will be fired if 772 * <code>firePC</code> is true. 773 */ 774 private void setValue(Object value, boolean createFormat, boolean firePC) { 775 Object oldValue = this.value; 776 777 this.value = value; 778 779 if (createFormat) { 780 AbstractFormatterFactory factory = getFormatterFactory(); 781 AbstractFormatter atf; 782 783 if (factory != null) { 784 atf = factory.getFormatter(this); 785 } 786 else { 787 atf = null; 788 } 789 setFormatter(atf); 790 } 791 else { 792 // Assumed to be valid 832 (Format)type)); 833 } 834 if (type instanceof Date) { 835 return new DefaultFormatterFactory(new DateFormatter()); 836 } 837 if (type instanceof Number) { 838 AbstractFormatter displayFormatter = new NumberFormatter(); 839 ((NumberFormatter)displayFormatter).setValueClass(type.getClass()); 840 AbstractFormatter editFormatter = new NumberFormatter( 841 new DecimalFormat("#.#")); 842 ((NumberFormatter)editFormatter).setValueClass(type.getClass()); 843 844 return new DefaultFormatterFactory(displayFormatter, 845 displayFormatter,editFormatter); 846 } 847 return new DefaultFormatterFactory(new DefaultFormatter()); 848 } 849 850 851 /** 852 * Instances of <code>AbstractFormatterFactory</code> are used by 853 * <code>JFormattedTextField</code> to obtain instances of 854 * <code>AbstractFormatter</code> which in turn are used to format values. 855 * <code>AbstractFormatterFactory</code> can return different 856 * <code>AbstractFormatter</code>s based on the state of the 857 * <code>JFormattedTextField</code>, perhaps returning different 858 * <code>AbstractFormatter</code>s when the 859 * <code>JFormattedTextField</code> has focus vs when it 860 * doesn't have focus. 861 * @since 1.4 862 */ 863 public abstract static class AbstractFormatterFactory { 864 /** 865 * Returns an <code>AbstractFormatter</code> that can handle formatting 866 * of the passed in <code>JFormattedTextField</code>. 867 * 868 * @param tf JFormattedTextField requesting AbstractFormatter 869 * @return AbstractFormatter to handle formatting duties, a null 870 * return value implies the JFormattedTextField should behave 871 * like a normal JTextField 872 */ 873 public abstract AbstractFormatter getFormatter(JFormattedTextField tf); 874 } 875 876 877 /** 878 * Instances of <code>AbstractFormatter</code> are used by 879 * <code>JFormattedTextField</code> to handle the conversion both 880 * from an Object to a String, and back from a String to an Object. 881 * <code>AbstractFormatter</code>s can also enforce editing policies, 882 * or navigation policies, or manipulate the 883 * <code>JFormattedTextField</code> in any way it sees fit to 884 * enforce the desired policy. 885 * <p> 886 * An <code>AbstractFormatter</code> can only be active in 887 * one <code>JFormattedTextField</code> at a time. 888 * <code>JFormattedTextField</code> invokes 889 * <code>install</code> when it is ready to use it followed 890 * by <code>uninstall</code> when done. Subclasses 891 * that wish to install additional state should override 892 * <code>install</code> and message super appropriately. 893 * <p> 894 * Subclasses must override the conversion methods 895 * <code>stringToValue</code> and <code>valueToString</code>. Optionally 896 * they can override <code>getActions</code>, 897 * <code>getNavigationFilter</code> and <code>getDocumentFilter</code> 898 * to restrict the <code>JFormattedTextField</code> in a particular 899 * way. 900 * <p> 901 * Subclasses that allow the <code>JFormattedTextField</code> to be in 902 * a temporarily invalid state should invoke <code>setEditValid</code> 903 * at the appropriate times. 904 * @since 1.4 905 */ 906 public abstract static class AbstractFormatter implements Serializable { 907 private JFormattedTextField ftf; 908 909 /** 910 * Installs the <code>AbstractFormatter</code> onto a particular 911 * <code>JFormattedTextField</code>. 912 * This will invoke <code>valueToString</code> to convert the 913 * current value from the <code>JFormattedTextField</code> to 914 * a String. This will then install the <code>Action</code>s from 915 * <code>getActions</code>, the <code>DocumentFilter</code> 916 * returned from <code>getDocumentFilter</code> and the 917 * <code>NavigationFilter</code> returned from 918 * <code>getNavigationFilter</code> onto the 919 * <code>JFormattedTextField</code>. 920 * <p> 921 * Subclasses will typically only need to override this if they 922 * wish to install additional listeners on the 923 * <code>JFormattedTextField</code>. 924 * <p> 925 * If there is a <code>ParseException</code> in converting the 926 * current value to a String, this will set the text to an empty 927 * String, and mark the <code>JFormattedTextField</code> as being 928 * in an invalid state. 929 * <p> 930 * While this is a public method, this is typically only useful 931 * for subclassers of <code>JFormattedTextField</code>. 932 * <code>JFormattedTextField</code> will invoke this method at 933 * the appropriate times when the value changes, or its internal 934 * state changes. You will only need to invoke this yourself if 935 * you are subclassing <code>JFormattedTextField</code> and 936 * installing/uninstalling <code>AbstractFormatter</code> at a 937 * different time than <code>JFormattedTextField</code> does. 938 * 939 * @param ftf JFormattedTextField to format for, may be null indicating 940 * uninstall from current JFormattedTextField. 941 */ 942 public void install(JFormattedTextField ftf) { 943 if (this.ftf != null) { 944 uninstall(); 945 } 946 this.ftf = ftf; 947 if (ftf != null) { 948 try { 949 ftf.setText(valueToString(ftf.getValue())); 950 } catch (ParseException pe) { 951 ftf.setText(""); 952 setEditValid(false); 953 } 954 installDocumentFilter(getDocumentFilter()); 955 ftf.setNavigationFilter(getNavigationFilter()); 956 ftf.setFormatterActions(getActions()); 957 } 958 } 959 960 /** 961 * Uninstalls any state the <code>AbstractFormatter</code> may have 962 * installed on the <code>JFormattedTextField</code>. This resets the 963 * <code>DocumentFilter</code>, <code>NavigationFilter</code> 964 * and additional <code>Action</code>s installed on the 965 * <code>JFormattedTextField</code>. 966 */ 967 public void uninstall() { 968 if (this.ftf != null) { 969 installDocumentFilter(null); 970 this.ftf.setNavigationFilter(null); 971 this.ftf.setFormatterActions(null); 972 } 973 } 974 975 /** 976 * Parses <code>text</code> returning an arbitrary Object. Some 977 * formatters may return null. 978 * 979 * @throws ParseException if there is an error in the conversion 980 * @param text String to convert 981 * @return Object representation of text 982 */ 983 public abstract Object stringToValue(String text) throws 984 ParseException; 985 986 /** 987 * Returns the string value to display for <code>value</code>. 988 * 989 * @throws ParseException if there is an error in the conversion 990 * @param value Value to convert 991 * @return String representation of value 992 */ 993 public abstract String valueToString(Object value) throws 994 ParseException; 995 996 /** 997 * Returns the current <code>JFormattedTextField</code> the 998 * <code>AbstractFormatter</code> is installed on. 999 * 1000 * @return JFormattedTextField formatting for. 1001 */ 1002 protected JFormattedTextField getFormattedTextField() { 1003 return ftf; 1004 } 1005 1006 /** 1007 * This should be invoked when the user types an invalid character. 1008 * This forwards the call to the current JFormattedTextField. 1009 */ 1010 protected void invalidEdit() { 1011 JFormattedTextField ftf = getFormattedTextField(); 1012 1013 if (ftf != null) { 1014 ftf.invalidEdit(); 1015 } 1016 } 1017 1018 /** 1019 * Invoke this to update the <code>editValid</code> property of the 1020 * <code>JFormattedTextField</code>. If you an enforce a policy 1021 * such that the <code>JFormattedTextField</code> is always in a 1022 * valid state, you will never need to invoke this. 1023 * 1024 * @param valid Valid state of the JFormattedTextField 1025 */ 1026 protected void setEditValid(boolean valid) { 1027 JFormattedTextField ftf = getFormattedTextField(); 1028 1029 if (ftf != null) { 1030 ftf.setEditValid(valid); 1031 } 1032 } 1033 1034 /** 1035 * Subclass and override if you wish to provide a custom set of 1036 * <code>Action</code>s. <code>install</code> will install these 1037 * on the <code>JFormattedTextField</code>'s <code>ActionMap</code>. 1038 * 1039 * @return Array of Actions to install on JFormattedTextField 1040 */ 1041 protected Action[] getActions() { 1042 return null; 1043 } 1044 1045 /** 1046 * Subclass and override if you wish to provide a 1047 * <code>DocumentFilter</code> to restrict what can be input. 1048 * <code>install</code> will install the returned value onto 1049 * the <code>JFormattedTextField</code>. 1050 * 1051 * @return DocumentFilter to restrict edits 1052 */ 1053 protected DocumentFilter getDocumentFilter() { 1054 return null; 1055 } 1056 1057 /** 1058 * Subclass and override if you wish to provide a filter to restrict 1059 * where the user can navigate to. 1060 * <code>install</code> will install the returned value onto 1061 * the <code>JFormattedTextField</code>. 1062 * 1063 * @return NavigationFilter to restrict navigation 1064 */ 1065 protected NavigationFilter getNavigationFilter() { 1066 return null; 1067 } 1068 1069 /** 1070 * Clones the <code>AbstractFormatter</code>. The returned instance 1071 * is not associated with a <code>JFormattedTextField</code>. 1072 * 1073 * @return Copy of the AbstractFormatter 1074 */ 1075 protected Object clone() throws CloneNotSupportedException { 1076 AbstractFormatter formatter = (AbstractFormatter)super.clone(); 1077 1078 formatter.ftf = null; 1079 return formatter; 1080 } 1081 1082 /** 1083 * Installs the <code>DocumentFilter</code> <code>filter</code> 1084 * onto the current <code>JFormattedTextField</code>. 1085 * 1086 * @param filter DocumentFilter to install on the Document. 1087 */ 1088 private void installDocumentFilter(DocumentFilter filter) { 1089 JFormattedTextField ftf = getFormattedTextField(); 1090 1091 if (ftf != null) { 1092 Document doc = ftf.getDocument(); 1093 1094 if (doc instanceof AbstractDocument) { 1095 ((AbstractDocument)doc).setDocumentFilter(filter); 1096 } 1097 doc.putProperty(DocumentFilter.class, null); 1098 } 1099 } 1100 } 1101 1102 1103 /** 1104 * Used to commit the edit. This extends JTextField.NotifyAction 1105 * so that <code>isEnabled</code> is true while a JFormattedTextField 1106 * has focus, and extends <code>actionPerformed</code> to invoke 1107 * commitEdit. 1108 */ 1109 static class CommitAction extends JTextField.NotifyAction { 1110 public void actionPerformed(ActionEvent e) { 1111 JTextComponent target = getFocusedComponent(); 1112 1113 if (target instanceof JFormattedTextField) { 1114 // Attempt to commit the value 1115 try { 1116 ((JFormattedTextField)target).commitEdit(); 1117 } catch (ParseException pe) { 1118 ((JFormattedTextField)target).invalidEdit(); 1119 // value not committed, don't notify ActionListeners 1120 return; 1121 } 1122 } 1123 // Super behavior. 1124 super.actionPerformed(e); 1125 } 1126 1127 public boolean isEnabled() { 1128 JTextComponent target = getFocusedComponent(); 1129 if (target instanceof JFormattedTextField) { 1130 JFormattedTextField ftf = (JFormattedTextField)target; 1131 if (!ftf.isEdited()) { 1132 return false; 1133 } 1134 return true; 1135 } 1136 return super.isEnabled(); 1137 } 1138 } 1139 1140 1141 /** 1142 * CancelAction will reset the value in the JFormattedTextField when 1143 * <code>actionPerformed</code> is invoked. It will only be 1144 * enabled if the focused component is an instance of 1145 * JFormattedTextField. 1146 */ 1147 private static class CancelAction extends TextAction { 1148 public CancelAction() { 1149 super("reset-field-edit"); 1150 } 1151 1152 public void actionPerformed(ActionEvent e) { 1153 JTextComponent target = getFocusedComponent(); 1154 1155 if (target instanceof JFormattedTextField) { 1156 JFormattedTextField ftf = (JFormattedTextField)target; 1157 ftf.setValue(ftf.getValue()); 1158 } 1159 } 1160 1161 public boolean isEnabled() { 1162 JTextComponent target = getFocusedComponent(); 1163 if (target instanceof JFormattedTextField) { | 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.awt.im.InputContext; 30 import java.io.*; 31 import java.text.*; 32 import java.util.*; 33 import javax.swing.event.*; 34 import javax.swing.plaf.UIResource; 35 import javax.swing.text.*; 36 37 /** 38 * {@code JFormattedTextField} extends {@code JTextField} adding 39 * support for formatting arbitrary values, as well as retrieving a particular 40 * object once the user has edited the text. The following illustrates 41 * configuring a {@code JFormattedTextField} to edit dates: 42 * <pre> 43 * JFormattedTextField ftf = new JFormattedTextField(); 44 * ftf.setValue(new Date()); 45 * </pre> 46 * <p> 47 * Once a {@code JFormattedTextField} has been created, you can 48 * listen for editing changes by way of adding 49 * a {@code PropertyChangeListener} and listening for 50 * {@code PropertyChangeEvent}s with the property name {@code value}. 51 * <p> 52 * {@code JFormattedTextField} allows 53 * configuring what action should be taken when focus is lost. The possible 54 * configurations are: 55 * <table summary="Possible JFormattedTextField configurations and their descriptions"> 56 * <tr><th><p style="text-align:left">Value</p></th><th><p style="text-align:left">Description</p></th></tr> 57 * <tr><td>JFormattedTextField.REVERT 58 * <td>Revert the display to match that of {@code getValue}, 59 * possibly losing the current edit. 60 * <tr><td>JFormattedTextField.COMMIT 61 * <td>Commits the current value. If the value being edited 62 * isn't considered a legal value by the 63 * {@code AbstractFormatter} that is, a 64 * {@code ParseException} is thrown, then the value 65 * will not change, and then edited value will persist. 66 * <tr><td>JFormattedTextField.COMMIT_OR_REVERT 67 * <td>Similar to {@code COMMIT}, but if the value isn't 68 * legal, behave like {@code REVERT}. 69 * <tr><td>JFormattedTextField.PERSIST 70 * <td>Do nothing, don't obtain a new 71 * {@code AbstractFormatter}, and don't update the value. 72 * </table> 73 * The default is {@code JFormattedTextField.COMMIT_OR_REVERT}, 74 * refer to {@link #setFocusLostBehavior} for more information on this. 75 * <p> 76 * {@code JFormattedTextField} allows the focus to leave, even if 77 * the currently edited value is invalid. To lock the focus down while the 78 * {@code JFormattedTextField} is an invalid edit state 79 * you can attach an {@code InputVerifier}. The following code snippet 80 * shows a potential implementation of such an {@code InputVerifier}: 81 * <pre> 82 * public class FormattedTextFieldVerifier extends InputVerifier { 83 * public boolean verify(JComponent input) { 84 * if (input instanceof JFormattedTextField) { 85 * JFormattedTextField ftf = (JFormattedTextField)input; 86 * AbstractFormatter formatter = ftf.getFormatter(); 87 * if (formatter != null) { 88 * String text = ftf.getText(); 89 * try { 90 * formatter.stringToValue(text); 91 * return true; 92 * } catch (ParseException pe) { 93 * return false; 94 * } 95 * } 96 * } 97 * return true; 98 * } 99 * public boolean shouldYieldFocus(JComponent input) { 100 * return verify(input); 101 * } 102 * } 103 * </pre> 104 * <p> 105 * Alternatively, you could invoke {@code commitEdit}, which would also 106 * commit the value. 107 * <p> 108 * {@code JFormattedTextField} does not do the formatting it self, 109 * rather formatting is done through an instance of 110 * {@code JFormattedTextField.AbstractFormatter} which is obtained from 111 * an instance of {@code JFormattedTextField.AbstractFormatterFactory}. 112 * Instances of {@code JFormattedTextField.AbstractFormatter} are 113 * notified when they become active by way of the 114 * {@code install} method, at which point the 115 * {@code JFormattedTextField.AbstractFormatter} can install whatever 116 * it needs to, typically a {@code DocumentFilter}. Similarly when 117 * {@code JFormattedTextField} no longer 118 * needs the {@code AbstractFormatter}, it will invoke 119 * {@code uninstall}. 120 * <p> 121 * {@code JFormattedTextField} typically 122 * queries the {@code AbstractFormatterFactory} for an 123 * {@code AbstractFormat} when it gains or loses focus. Although this 124 * can change based on the focus lost policy. If the focus lost 125 * policy is {@code JFormattedTextField.PERSIST} 126 * and the {@code JFormattedTextField} has been edited, the 127 * {@code AbstractFormatterFactory} will not be queried until the 128 * value has been committed. Similarly if the focus lost policy is 129 * {@code JFormattedTextField.COMMIT} and an exception 130 * is thrown from {@code stringToValue}, the 131 * {@code AbstractFormatterFactory} will not be queried when focus is 132 * lost or gained. 133 * <p> 134 * {@code JFormattedTextField.AbstractFormatter} 135 * is also responsible for determining when values are committed to 136 * the {@code JFormattedTextField}. Some 137 * {@code JFormattedTextField.AbstractFormatter}s will make new values 138 * available on every edit, and others will never commit the value. You can 139 * force the current value to be obtained 140 * from the current {@code JFormattedTextField.AbstractFormatter} 141 * by way of invoking {@code commitEdit}. {@code commitEdit} will 142 * be invoked whenever return is pressed in the 143 * {@code JFormattedTextField}. 144 * <p> 145 * If an {@code AbstractFormatterFactory} has not been explicitly 146 * set, one will be set based on the {@code Class} of the value type after 147 * {@code setValue} has been invoked (assuming value is non-null). 148 * For example, in the following code an appropriate 149 * {@code AbstractFormatterFactory} and {@code AbstractFormatter} 150 * will be created to handle formatting of numbers: 151 * <pre> 152 * JFormattedTextField tf = new JFormattedTextField(); 153 * tf.setValue(100); 154 * </pre> 155 * <p> 156 * <strong>Warning:</strong> As the {@code AbstractFormatter} will 157 * typically install a {@code DocumentFilter} on the 158 * {@code Document}, and a {@code NavigationFilter} on the 159 * {@code JFormattedTextField} you should not install your own. If you do, 160 * you are likely to see odd behavior in that the editing policy of the 161 * {@code AbstractFormatter} will not be enforced. 162 * <p> 163 * <strong>Warning:</strong> Swing is not thread safe. For more 164 * information see <a 165 * href="package-summary.html#threading">Swing's Threading 166 * Policy</a>. 167 * <p> 168 * <strong>Warning:</strong> 169 * Serialized objects of this class will not be compatible with 170 * future Swing releases. The current serialization support is 171 * appropriate for short term storage or RMI between applications running 172 * the same version of Swing. As of 1.4, support for long term storage 173 * of all JavaBeans™ 174 * has been added to the {@code java.beans} package. 175 * Please see {@link java.beans.XMLEncoder}. 176 * 177 * @since 1.4 178 */ 179 @SuppressWarnings("serial") // Same-version serialization only 180 public class JFormattedTextField extends JTextField { 181 private static final String uiClassID = "FormattedTextFieldUI"; 182 private static final Action[] defaultActions = 183 { new CommitAction(), new CancelAction() }; 184 185 /** 186 * Constant identifying that when focus is lost, 187 * {@code commitEdit} should be invoked. If in committing the 188 * new value a {@code ParseException} is thrown, the invalid 189 * value will remain. 190 * 191 * @see #setFocusLostBehavior 192 */ 193 public static final int COMMIT = 0; 194 195 /** 196 * Constant identifying that when focus is lost, 197 * {@code commitEdit} should be invoked. If in committing the new 198 * value a {@code ParseException} is thrown, the value will be 199 * reverted. 200 * 201 * @see #setFocusLostBehavior 202 */ 203 public static final int COMMIT_OR_REVERT = 1; 204 205 /** 206 * Constant identifying that when focus is lost, editing value should 207 * be reverted to current value set on the 208 * {@code JFormattedTextField}. 209 * 210 * @see #setFocusLostBehavior 211 */ 212 public static final int REVERT = 2; 213 214 /** 215 * Constant identifying that when focus is lost, the edited value 216 * should be left. 217 * 218 * @see #setFocusLostBehavior 219 */ 220 public static final int PERSIST = 3; 221 222 223 /** 224 * Factory used to obtain an instance of AbstractFormatter. 225 */ 226 private AbstractFormatterFactory factory; 227 /** 228 * Object responsible for formatting the current value. 250 private DocumentListener documentListener; 251 /** 252 * Masked used to set the AbstractFormatterFactory. 253 */ 254 private Object mask; 255 /** 256 * ActionMap that the TextFormatter Actions are added to. 257 */ 258 private ActionMap textFormatterActionMap; 259 /** 260 * Indicates the input method composed text is in the document 261 */ 262 private boolean composedTextExists = false; 263 /** 264 * A handler for FOCUS_LOST event 265 */ 266 private FocusLostHandler focusLostHandler; 267 268 269 /** 270 * Creates a {@code JFormattedTextField} with no 271 * {@code AbstractFormatterFactory}. Use {@code setMask} or 272 * {@code setFormatterFactory} to configure the 273 * {@code JFormattedTextField} to edit a particular type of 274 * value. 275 */ 276 public JFormattedTextField() { 277 super(); 278 enableEvents(AWTEvent.FOCUS_EVENT_MASK); 279 setFocusLostBehavior(COMMIT_OR_REVERT); 280 } 281 282 /** 283 * Creates a JFormattedTextField with the specified value. This will 284 * create an {@code AbstractFormatterFactory} based on the 285 * type of {@code value}. 286 * 287 * @param value Initial value for the JFormattedTextField 288 */ 289 public JFormattedTextField(Object value) { 290 this(); 291 setValue(value); 292 } 293 294 /** 295 * Creates a {@code JFormattedTextField}. {@code format} is 296 * wrapped in an appropriate {@code AbstractFormatter} which is 297 * then wrapped in an {@code AbstractFormatterFactory}. 298 * 299 * @param format Format used to look up an AbstractFormatter 300 */ 301 public JFormattedTextField(java.text.Format format) { 302 this(); 303 setFormatterFactory(getDefaultFormatterFactory(format)); 304 } 305 306 /** 307 * Creates a {@code JFormattedTextField} with the specified 308 * {@code AbstractFormatter}. The {@code AbstractFormatter} 309 * is placed in an {@code AbstractFormatterFactory}. 310 * 311 * @param formatter AbstractFormatter to use for formatting. 312 */ 313 public JFormattedTextField(AbstractFormatter formatter) { 314 this(new DefaultFormatterFactory(formatter)); 315 } 316 317 /** 318 * Creates a {@code JFormattedTextField} with the specified 319 * {@code AbstractFormatterFactory}. 320 * 321 * @param factory AbstractFormatterFactory used for formatting. 322 */ 323 public JFormattedTextField(AbstractFormatterFactory factory) { 324 this(); 325 setFormatterFactory(factory); 326 } 327 328 /** 329 * Creates a {@code JFormattedTextField} with the specified 330 * {@code AbstractFormatterFactory} and initial value. 331 * 332 * @param factory {@code AbstractFormatterFactory} used for 333 * formatting. 334 * @param currentValue Initial value to use 335 */ 336 public JFormattedTextField(AbstractFormatterFactory factory, 337 Object currentValue) { 338 this(currentValue); 339 setFormatterFactory(factory); 340 } 341 342 /** 343 * Sets the behavior when focus is lost. This will be one of 344 * {@code JFormattedTextField.COMMIT_OR_REVERT}, 345 * {@code JFormattedTextField.REVERT}, 346 * {@code JFormattedTextField.COMMIT} or 347 * {@code JFormattedTextField.PERSIST} 348 * Note that some {@code AbstractFormatter}s may push changes as 349 * they occur, so that the value of this will have no effect. 350 * <p> 351 * This will throw an {@code IllegalArgumentException} if the object 352 * passed in is not one of the afore mentioned values. 353 * <p> 354 * The default value of this property is 355 * {@code JFormattedTextField.COMMIT_OR_REVERT}. 356 * 357 * @param behavior Identifies behavior when focus is lost 358 * @throws IllegalArgumentException if behavior is not one of the known 359 * values 360 * @beaninfo 361 * enum: COMMIT JFormattedTextField.COMMIT 362 * COMMIT_OR_REVERT JFormattedTextField.COMMIT_OR_REVERT 363 * REVERT JFormattedTextField.REVERT 364 * PERSIST JFormattedTextField.PERSIST 365 * description: Behavior when component loses focus 366 */ 367 public void setFocusLostBehavior(int behavior) { 368 if (behavior != COMMIT && behavior != COMMIT_OR_REVERT && 369 behavior != PERSIST && behavior != REVERT) { 370 throw new IllegalArgumentException("setFocusLostBehavior must be one of: JFormattedTextField.COMMIT, JFormattedTextField.COMMIT_OR_REVERT, JFormattedTextField.PERSIST or JFormattedTextField.REVERT"); 371 } 372 focusLostBehavior = behavior; 373 } 374 375 /** 376 * Returns the behavior when focus is lost. This will be one of 377 * {@code COMMIT_OR_REVERT}, 378 * {@code COMMIT}, 379 * {@code REVERT} or 380 * {@code PERSIST} 381 * Note that some {@code AbstractFormatter}s may push changes as 382 * they occur, so that the value of this will have no effect. 383 * 384 * @return returns behavior when focus is lost 385 */ 386 public int getFocusLostBehavior() { 387 return focusLostBehavior; 388 } 389 390 /** 391 * Sets the {@code AbstractFormatterFactory}. 392 * {@code AbstractFormatterFactory} is 393 * able to return an instance of {@code AbstractFormatter} that is 394 * used to format a value for display, as well an enforcing an editing 395 * policy. 396 * <p> 397 * If you have not explicitly set an {@code AbstractFormatterFactory} 398 * by way of this method (or a constructor) an 399 * {@code AbstractFormatterFactory} and consequently an 400 * {@code AbstractFormatter} will be used based on the 401 * {@code Class} of the value. {@code NumberFormatter} will 402 * be used for {@code Number}s, {@code DateFormatter} will 403 * be used for {@code Dates}, otherwise {@code DefaultFormatter} 404 * will be used. 405 * <p> 406 * This is a JavaBeans bound property. 407 * 408 * @param tf {@code AbstractFormatterFactory} used to lookup 409 * instances of {@code AbstractFormatter} 410 * @beaninfo 411 * bound: true 412 * attribute: visualUpdate true 413 * description: AbstractFormatterFactory, responsible for returning an 414 * AbstractFormatter that can format the current value. 415 */ 416 public void setFormatterFactory(AbstractFormatterFactory tf) { 417 AbstractFormatterFactory oldFactory = factory; 418 419 factory = tf; 420 firePropertyChange("formatterFactory", oldFactory, tf); 421 setValue(getValue(), true, false); 422 } 423 424 /** 425 * Returns the current {@code AbstractFormatterFactory}. 426 * 427 * @see #setFormatterFactory 428 * @return {@code AbstractFormatterFactory} used to determine 429 * {@code AbstractFormatter}s 430 */ 431 public AbstractFormatterFactory getFormatterFactory() { 432 return factory; 433 } 434 435 /** 436 * Sets the current {@code AbstractFormatter}. 437 * <p> 438 * You should not normally invoke this, instead set the 439 * {@code AbstractFormatterFactory} or set the value. 440 * {@code JFormattedTextField} will 441 * invoke this as the state of the {@code JFormattedTextField} 442 * changes and requires the value to be reset. 443 * {@code JFormattedTextField} passes in the 444 * {@code AbstractFormatter} obtained from the 445 * {@code AbstractFormatterFactory}. 446 * <p> 447 * This is a JavaBeans bound property. 448 * 449 * @see #setFormatterFactory 450 * @param format AbstractFormatter to use for formatting 451 * @beaninfo 452 * bound: true 453 * attribute: visualUpdate true 454 * description: TextFormatter, responsible for formatting the current value 455 */ 456 protected void setFormatter(AbstractFormatter format) { 457 AbstractFormatter oldFormat = this.format; 458 459 if (oldFormat != null) { 460 oldFormat.uninstall(); 461 } 462 setEditValid(true); 463 this.format = format; 464 if (format != null) { 465 format.install(this); 466 } 467 setEdited(false); 468 firePropertyChange("textFormatter", oldFormat, format); 469 } 470 471 /** 472 * Returns the {@code AbstractFormatter} that is used to format and 473 * parse the current value. 474 * 475 * @return AbstractFormatter used for formatting 476 */ 477 public AbstractFormatter getFormatter() { 478 return format; 479 } 480 481 /** 482 * Sets the value that will be formatted by an 483 * {@code AbstractFormatter} obtained from the current 484 * {@code AbstractFormatterFactory}. If no 485 * {@code AbstractFormatterFactory} has been specified, this will 486 * attempt to create one based on the type of {@code value}. 487 * <p> 488 * The default value of this property is null. 489 * <p> 490 * This is a JavaBeans bound property. 491 * 492 * @param value Current value to display 493 * @beaninfo 494 * bound: true 495 * attribute: visualUpdate true 496 * description: The value to be formatted. 497 */ 498 public void setValue(Object value) { 499 if (value != null && getFormatterFactory() == null) { 500 setFormatterFactory(getDefaultFormatterFactory(value)); 501 } 502 setValue(value, true, true); 503 } 504 505 /** 506 * Returns the last valid value. Based on the editing policy of 507 * the {@code AbstractFormatter} this may not return the current 508 * value. The currently edited value can be obtained by invoking 509 * {@code commitEdit} followed by {@code getValue}. 510 * 511 * @return Last valid value 512 */ 513 public Object getValue() { 514 return value; 515 } 516 517 /** 518 * Forces the current value to be taken from the 519 * {@code AbstractFormatter} and set as the current value. 520 * This has no effect if there is no current 521 * {@code AbstractFormatter} installed. 522 * 523 * @throws ParseException if the {@code AbstractFormatter} is not able 524 * to format the current value 525 */ 526 public void commitEdit() throws ParseException { 527 AbstractFormatter format = getFormatter(); 528 529 if (format != null) { 530 setValue(format.stringToValue(getText()), false, true); 531 } 532 } 533 534 /** 535 * Sets the validity of the edit on the receiver. You should not normally 536 * invoke this. This will be invoked by the 537 * {@code AbstractFormatter} as the user edits the value. 538 * <p> 539 * Not all formatters will allow the component to get into an invalid 540 * state, and thus this may never be invoked. 541 * <p> 542 * Based on the look and feel this may visually change the state of 543 * the receiver. 544 * 545 * @param isValid boolean indicating if the currently edited value is 546 * valid. 547 * @beaninfo 548 * bound: true 549 * attribute: visualUpdate true 550 * description: True indicates the edited value is valid 551 */ 552 private void setEditValid(boolean isValid) { 553 if (isValid != editValid) { 554 editValid = isValid; 555 firePropertyChange("editValid", Boolean.valueOf(!isValid), 556 Boolean.valueOf(isValid)); 557 } 558 } 559 560 /** 561 * Returns true if the current value being edited is valid. The value of 562 * this is managed by the current {@code AbstractFormatter}, as such 563 * there is no public setter for it. 564 * 565 * @return true if the current value being edited is valid. 566 */ 567 public boolean isEditValid() { 568 return editValid; 569 } 570 571 /** 572 * Invoked when the user inputs an invalid value. This gives the 573 * component a chance to provide feedback. The default 574 * implementation beeps. 575 */ 576 protected void invalidEdit() { 577 UIManager.getLookAndFeel().provideErrorFeedback(JFormattedTextField.this); 578 } 579 580 /** 581 * Processes any input method events, such as 582 * {@code InputMethodEvent.INPUT_METHOD_TEXT_CHANGED} or 583 * {@code InputMethodEvent.CARET_POSITION_CHANGED}. 584 * 585 * @param e the {@code InputMethodEvent} 586 * @see InputMethodEvent 587 */ 588 protected void processInputMethodEvent(InputMethodEvent e) { 589 AttributedCharacterIterator text = e.getText(); 590 int commitCount = e.getCommittedCharacterCount(); 591 592 // Keep track of the composed text 593 if (text != null) { 594 int begin = text.getBeginIndex(); 595 int end = text.getEndIndex(); 596 composedTextExists = ((end - begin) > commitCount); 597 } else { 598 composedTextExists = false; 599 } 600 601 super.processInputMethodEvent(e); 602 } 603 604 /** 605 * Processes any focus events, such as 606 * {@code FocusEvent.FOCUS_GAINED} or 607 * {@code FocusEvent.FOCUS_LOST}. 608 * 609 * @param e the {@code FocusEvent} 610 * @see FocusEvent 611 */ 612 protected void processFocusEvent(FocusEvent e) { 613 super.processFocusEvent(e); 614 615 // ignore temporary focus event 616 if (e.isTemporary()) { 617 return; 618 } 619 620 if (isEdited() && e.getID() == FocusEvent.FOCUS_LOST) { 621 InputContext ic = getInputContext(); 622 if (focusLostHandler == null) { 623 focusLostHandler = new FocusLostHandler(); 624 } 625 626 // if there is a composed text, process it first 627 if ((ic != null) && composedTextExists) { 628 ic.endComposition(); 629 EventQueue.invokeLater(focusLostHandler); 713 714 /* 715 * See readObject and writeObject in JComponent for more 716 * information about serialization in Swing. 717 * 718 * @param s Stream to write to 719 */ 720 private void writeObject(ObjectOutputStream s) throws IOException { 721 s.defaultWriteObject(); 722 if (getUIClassID().equals(uiClassID)) { 723 byte count = JComponent.getWriteObjCounter(this); 724 JComponent.setWriteObjCounter(this, --count); 725 if (count == 0 && ui != null) { 726 ui.installUI(this); 727 } 728 } 729 } 730 731 /** 732 * Resets the Actions that come from the TextFormatter to 733 * {@code actions}. 734 */ 735 private void setFormatterActions(Action[] actions) { 736 if (actions == null) { 737 if (textFormatterActionMap != null) { 738 textFormatterActionMap.clear(); 739 } 740 } 741 else { 742 if (textFormatterActionMap == null) { 743 ActionMap map = getActionMap(); 744 745 textFormatterActionMap = new ActionMap(); 746 while (map != null) { 747 ActionMap parent = map.getParent(); 748 749 if (parent instanceof UIResource || parent == null) { 750 map.setParent(textFormatterActionMap); 751 textFormatterActionMap.setParent(parent); 752 break; 753 } 754 map = parent; 755 } 756 } 757 for (int counter = actions.length - 1; counter >= 0; 758 counter--) { 759 Object key = actions[counter].getValue(Action.NAME); 760 761 if (key != null) { 762 textFormatterActionMap.put(key, actions[counter]); 763 } 764 } 765 } 766 } 767 768 /** 769 * Does the setting of the value. If {@code createFormat} is true, 770 * this will also obtain a new {@code AbstractFormatter} from the 771 * current factory. The property change event will be fired if 772 * {@code firePC} is true. 773 */ 774 private void setValue(Object value, boolean createFormat, boolean firePC) { 775 Object oldValue = this.value; 776 777 this.value = value; 778 779 if (createFormat) { 780 AbstractFormatterFactory factory = getFormatterFactory(); 781 AbstractFormatter atf; 782 783 if (factory != null) { 784 atf = factory.getFormatter(this); 785 } 786 else { 787 atf = null; 788 } 789 setFormatter(atf); 790 } 791 else { 792 // Assumed to be valid 832 (Format)type)); 833 } 834 if (type instanceof Date) { 835 return new DefaultFormatterFactory(new DateFormatter()); 836 } 837 if (type instanceof Number) { 838 AbstractFormatter displayFormatter = new NumberFormatter(); 839 ((NumberFormatter)displayFormatter).setValueClass(type.getClass()); 840 AbstractFormatter editFormatter = new NumberFormatter( 841 new DecimalFormat("#.#")); 842 ((NumberFormatter)editFormatter).setValueClass(type.getClass()); 843 844 return new DefaultFormatterFactory(displayFormatter, 845 displayFormatter,editFormatter); 846 } 847 return new DefaultFormatterFactory(new DefaultFormatter()); 848 } 849 850 851 /** 852 * Instances of {@code AbstractFormatterFactory} are used by 853 * {@code JFormattedTextField} to obtain instances of 854 * {@code AbstractFormatter} which in turn are used to format values. 855 * {@code AbstractFormatterFactory} can return different 856 * {@code AbstractFormatter}s based on the state of the 857 * {@code JFormattedTextField}, perhaps returning different 858 * {@code AbstractFormatter}s when the 859 * {@code JFormattedTextField} has focus vs when it 860 * doesn't have focus. 861 * @since 1.4 862 */ 863 public abstract static class AbstractFormatterFactory { 864 /** 865 * Returns an {@code AbstractFormatter} that can handle formatting 866 * of the passed in {@code JFormattedTextField}. 867 * 868 * @param tf JFormattedTextField requesting AbstractFormatter 869 * @return AbstractFormatter to handle formatting duties, a null 870 * return value implies the JFormattedTextField should behave 871 * like a normal JTextField 872 */ 873 public abstract AbstractFormatter getFormatter(JFormattedTextField tf); 874 } 875 876 877 /** 878 * Instances of {@code AbstractFormatter} are used by 879 * {@code JFormattedTextField} to handle the conversion both 880 * from an Object to a String, and back from a String to an Object. 881 * {@code AbstractFormatter}s can also enforce editing policies, 882 * or navigation policies, or manipulate the 883 * {@code JFormattedTextField} in any way it sees fit to 884 * enforce the desired policy. 885 * <p> 886 * An {@code AbstractFormatter} can only be active in 887 * one {@code JFormattedTextField} at a time. 888 * {@code JFormattedTextField} invokes 889 * {@code install} when it is ready to use it followed 890 * by {@code uninstall} when done. Subclasses 891 * that wish to install additional state should override 892 * {@code install} and message super appropriately. 893 * <p> 894 * Subclasses must override the conversion methods 895 * {@code stringToValue} and {@code valueToString}. Optionally 896 * they can override {@code getActions}, 897 * {@code getNavigationFilter} and {@code getDocumentFilter} 898 * to restrict the {@code JFormattedTextField} in a particular 899 * way. 900 * <p> 901 * Subclasses that allow the {@code JFormattedTextField} to be in 902 * a temporarily invalid state should invoke {@code setEditValid} 903 * at the appropriate times. 904 * @since 1.4 905 */ 906 public abstract static class AbstractFormatter implements Serializable { 907 private JFormattedTextField ftf; 908 909 /** 910 * Installs the {@code AbstractFormatter} onto a particular 911 * {@code JFormattedTextField}. 912 * This will invoke {@code valueToString} to convert the 913 * current value from the {@code JFormattedTextField} to 914 * a String. This will then install the {@code Action}s from 915 * {@code getActions}, the {@code DocumentFilter} 916 * returned from {@code getDocumentFilter} and the 917 * {@code NavigationFilter} returned from 918 * {@code getNavigationFilter} onto the 919 * {@code JFormattedTextField}. 920 * <p> 921 * Subclasses will typically only need to override this if they 922 * wish to install additional listeners on the 923 * {@code JFormattedTextField}. 924 * <p> 925 * If there is a {@code ParseException} in converting the 926 * current value to a String, this will set the text to an empty 927 * String, and mark the {@code JFormattedTextField} as being 928 * in an invalid state. 929 * <p> 930 * While this is a public method, this is typically only useful 931 * for subclassers of {@code JFormattedTextField}. 932 * {@code JFormattedTextField} will invoke this method at 933 * the appropriate times when the value changes, or its internal 934 * state changes. You will only need to invoke this yourself if 935 * you are subclassing {@code JFormattedTextField} and 936 * installing/uninstalling {@code AbstractFormatter} at a 937 * different time than {@code JFormattedTextField} does. 938 * 939 * @param ftf JFormattedTextField to format for, may be null indicating 940 * uninstall from current JFormattedTextField. 941 */ 942 public void install(JFormattedTextField ftf) { 943 if (this.ftf != null) { 944 uninstall(); 945 } 946 this.ftf = ftf; 947 if (ftf != null) { 948 try { 949 ftf.setText(valueToString(ftf.getValue())); 950 } catch (ParseException pe) { 951 ftf.setText(""); 952 setEditValid(false); 953 } 954 installDocumentFilter(getDocumentFilter()); 955 ftf.setNavigationFilter(getNavigationFilter()); 956 ftf.setFormatterActions(getActions()); 957 } 958 } 959 960 /** 961 * Uninstalls any state the {@code AbstractFormatter} may have 962 * installed on the {@code JFormattedTextField}. This resets the 963 * {@code DocumentFilter}, {@code NavigationFilter} 964 * and additional {@code Action}s installed on the 965 * {@code JFormattedTextField}. 966 */ 967 public void uninstall() { 968 if (this.ftf != null) { 969 installDocumentFilter(null); 970 this.ftf.setNavigationFilter(null); 971 this.ftf.setFormatterActions(null); 972 } 973 } 974 975 /** 976 * Parses {@code text} returning an arbitrary Object. Some 977 * formatters may return null. 978 * 979 * @throws ParseException if there is an error in the conversion 980 * @param text String to convert 981 * @return Object representation of text 982 */ 983 public abstract Object stringToValue(String text) throws 984 ParseException; 985 986 /** 987 * Returns the string value to display for {@code value}. 988 * 989 * @throws ParseException if there is an error in the conversion 990 * @param value Value to convert 991 * @return String representation of value 992 */ 993 public abstract String valueToString(Object value) throws 994 ParseException; 995 996 /** 997 * Returns the current {@code JFormattedTextField} the 998 * {@code AbstractFormatter} is installed on. 999 * 1000 * @return JFormattedTextField formatting for. 1001 */ 1002 protected JFormattedTextField getFormattedTextField() { 1003 return ftf; 1004 } 1005 1006 /** 1007 * This should be invoked when the user types an invalid character. 1008 * This forwards the call to the current JFormattedTextField. 1009 */ 1010 protected void invalidEdit() { 1011 JFormattedTextField ftf = getFormattedTextField(); 1012 1013 if (ftf != null) { 1014 ftf.invalidEdit(); 1015 } 1016 } 1017 1018 /** 1019 * Invoke this to update the {@code editValid} property of the 1020 * {@code JFormattedTextField}. If you an enforce a policy 1021 * such that the {@code JFormattedTextField} is always in a 1022 * valid state, you will never need to invoke this. 1023 * 1024 * @param valid Valid state of the JFormattedTextField 1025 */ 1026 protected void setEditValid(boolean valid) { 1027 JFormattedTextField ftf = getFormattedTextField(); 1028 1029 if (ftf != null) { 1030 ftf.setEditValid(valid); 1031 } 1032 } 1033 1034 /** 1035 * Subclass and override if you wish to provide a custom set of 1036 * {@code Action}s. {@code install} will install these 1037 * on the {@code JFormattedTextField}'s {@code ActionMap}. 1038 * 1039 * @return Array of Actions to install on JFormattedTextField 1040 */ 1041 protected Action[] getActions() { 1042 return null; 1043 } 1044 1045 /** 1046 * Subclass and override if you wish to provide a 1047 * {@code DocumentFilter} to restrict what can be input. 1048 * {@code install} will install the returned value onto 1049 * the {@code JFormattedTextField}. 1050 * 1051 * @return DocumentFilter to restrict edits 1052 */ 1053 protected DocumentFilter getDocumentFilter() { 1054 return null; 1055 } 1056 1057 /** 1058 * Subclass and override if you wish to provide a filter to restrict 1059 * where the user can navigate to. 1060 * {@code install} will install the returned value onto 1061 * the {@code JFormattedTextField}. 1062 * 1063 * @return NavigationFilter to restrict navigation 1064 */ 1065 protected NavigationFilter getNavigationFilter() { 1066 return null; 1067 } 1068 1069 /** 1070 * Clones the {@code AbstractFormatter}. The returned instance 1071 * is not associated with a {@code JFormattedTextField}. 1072 * 1073 * @return Copy of the AbstractFormatter 1074 */ 1075 protected Object clone() throws CloneNotSupportedException { 1076 AbstractFormatter formatter = (AbstractFormatter)super.clone(); 1077 1078 formatter.ftf = null; 1079 return formatter; 1080 } 1081 1082 /** 1083 * Installs the {@code DocumentFilter filter} 1084 * onto the current {@code JFormattedTextField}. 1085 * 1086 * @param filter DocumentFilter to install on the Document. 1087 */ 1088 private void installDocumentFilter(DocumentFilter filter) { 1089 JFormattedTextField ftf = getFormattedTextField(); 1090 1091 if (ftf != null) { 1092 Document doc = ftf.getDocument(); 1093 1094 if (doc instanceof AbstractDocument) { 1095 ((AbstractDocument)doc).setDocumentFilter(filter); 1096 } 1097 doc.putProperty(DocumentFilter.class, null); 1098 } 1099 } 1100 } 1101 1102 1103 /** 1104 * Used to commit the edit. This extends JTextField.NotifyAction 1105 * so that {@code isEnabled} is true while a JFormattedTextField 1106 * has focus, and extends {@code actionPerformed} to invoke 1107 * commitEdit. 1108 */ 1109 static class CommitAction extends JTextField.NotifyAction { 1110 public void actionPerformed(ActionEvent e) { 1111 JTextComponent target = getFocusedComponent(); 1112 1113 if (target instanceof JFormattedTextField) { 1114 // Attempt to commit the value 1115 try { 1116 ((JFormattedTextField)target).commitEdit(); 1117 } catch (ParseException pe) { 1118 ((JFormattedTextField)target).invalidEdit(); 1119 // value not committed, don't notify ActionListeners 1120 return; 1121 } 1122 } 1123 // Super behavior. 1124 super.actionPerformed(e); 1125 } 1126 1127 public boolean isEnabled() { 1128 JTextComponent target = getFocusedComponent(); 1129 if (target instanceof JFormattedTextField) { 1130 JFormattedTextField ftf = (JFormattedTextField)target; 1131 if (!ftf.isEdited()) { 1132 return false; 1133 } 1134 return true; 1135 } 1136 return super.isEnabled(); 1137 } 1138 } 1139 1140 1141 /** 1142 * CancelAction will reset the value in the JFormattedTextField when 1143 * {@code actionPerformed} is invoked. It will only be 1144 * enabled if the focused component is an instance of 1145 * JFormattedTextField. 1146 */ 1147 private static class CancelAction extends TextAction { 1148 public CancelAction() { 1149 super("reset-field-edit"); 1150 } 1151 1152 public void actionPerformed(ActionEvent e) { 1153 JTextComponent target = getFocusedComponent(); 1154 1155 if (target instanceof JFormattedTextField) { 1156 JFormattedTextField ftf = (JFormattedTextField)target; 1157 ftf.setValue(ftf.getValue()); 1158 } 1159 } 1160 1161 public boolean isEnabled() { 1162 JTextComponent target = getFocusedComponent(); 1163 if (target instanceof JFormattedTextField) { |