| 1 7 8 package javax.swing; 9 10 import java.awt.*; 11 import java.awt.event.*; 12 13 import javax.swing.*; 14 import javax.swing.event.*; 15 import javax.swing.text.*; 16 import javax.swing.plaf.SpinnerUI ; 17 18 import java.util.*; 19 import java.beans.*; 20 import java.text.*; 21 import java.io.*; 22 import java.util.HashMap ; 23 import sun.text.resources.LocaleData; 24 25 import javax.accessibility.*; 26 27 28 101 public class JSpinner extends JComponent implements Accessible 102 { 103 107 private static final String uiClassID = "SpinnerUI"; 108 109 private static final Action DISABLED_ACTION = new DisabledAction(); 110 111 private transient SpinnerModel model; 112 private JComponent editor; 113 private ChangeListener modelListener; 114 private transient ChangeEvent changeEvent; 115 private boolean editorExplicitlySet = false; 116 117 118 122 public JSpinner(SpinnerModel model) { 123 this.model = model; 124 this.editor = createEditor(model); 125 setOpaque(true); 126 updateUI(); 127 } 128 129 130 134 public JSpinner() { 135 this(new SpinnerNumberModel ()); 136 } 137 138 139 144 public SpinnerUI getUI() { 145 return (SpinnerUI )ui; 146 } 147 148 149 155 public void setUI(SpinnerUI ui) { 156 super.setUI(ui); 157 } 158 159 160 168 public String getUIClassID() { 169 return uiClassID; 170 } 171 172 173 174 179 public void updateUI() { 180 setUI((SpinnerUI )UIManager.getUI(this)); 181 invalidate(); 182 } 183 184 185 210 protected JComponent createEditor(SpinnerModel model) { 211 if (model instanceof SpinnerDateModel ) { 212 return new DateEditor(this); 213 } 214 else if (model instanceof SpinnerListModel ) { 215 return new ListEditor(this); 216 } 217 else if (model instanceof SpinnerNumberModel ) { 218 return new NumberEditor(this); 219 } 220 else { 221 return new DefaultEditor(this); 222 } 223 } 224 225 226 248 public void setModel(SpinnerModel model) { 249 if (model == null) { 250 throw new IllegalArgumentException ("null model"); 251 } 252 if (!model.equals(this.model)) { 253 SpinnerModel oldModel = this.model; 254 this.model = model; 255 if (modelListener != null) { 256 this.model.addChangeListener(modelListener); 257 } 258 firePropertyChange("model", oldModel, model); 259 if (!editorExplicitlySet) { 260 setEditor(createEditor(model)); editorExplicitlySet = false; 262 } 263 repaint(); 264 revalidate(); 265 } 266 } 267 268 269 276 public SpinnerModel getModel() { 277 return model; 278 } 279 280 281 298 public Object getValue() { 299 return getModel().getValue(); 300 } 301 302 303 320 public void setValue(Object value) { 321 getModel().setValue(value); 322 } 323 324 325 342 public Object getNextValue() { 343 return getModel().getNextValue(); 344 } 345 346 347 351 private class ModelListener implements ChangeListener, Serializable { 352 public void stateChanged(ChangeEvent e) { 353 fireStateChanged(); 354 } 355 } 356 357 358 372 public void addChangeListener(ChangeListener listener) { 373 if (modelListener == null) { 374 modelListener = new ModelListener(); 375 getModel().addChangeListener(modelListener); 376 } 377 listenerList.add(ChangeListener.class, listener); 378 } 379 380 381 382 389 public void removeChangeListener(ChangeListener listener) { 390 listenerList.remove(ChangeListener.class, listener); 391 } 392 393 394 402 public ChangeListener[] getChangeListeners() { 403 return (ChangeListener[])listenerList.getListeners( 404 ChangeListener.class); 405 } 406 407 408 419 protected void fireStateChanged() { 420 Object [] listeners = listenerList.getListenerList(); 421 for (int i = listeners.length - 2; i >= 0; i -= 2) { 422 if (listeners[i] == ChangeListener.class) { 423 if (changeEvent == null) { 424 changeEvent = new ChangeEvent(this); 425 } 426 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent); 427 } 428 } 429 } 430 431 432 451 public Object getPreviousValue() { 452 return getModel().getPreviousValue(); 453 } 454 455 456 475 public void setEditor(JComponent editor) { 476 if (editor == null) { 477 throw new IllegalArgumentException ("null editor"); 478 } 479 if (!editor.equals(this.editor)) { 480 JComponent oldEditor = this.editor; 481 this.editor = editor; 482 if (oldEditor instanceof DefaultEditor) { 483 ((DefaultEditor)oldEditor).dismiss(this); 484 } 485 editorExplicitlySet = true; 486 firePropertyChange("editor", oldEditor, editor); 487 revalidate(); 488 repaint(); 489 } 490 } 491 492 493 502 public JComponent getEditor() { 503 return editor; 504 } 505 506 507 516 public void commitEdit() throws ParseException { 517 JComponent editor = getEditor(); 518 if (editor instanceof DefaultEditor) { 519 ((DefaultEditor)editor).commitEdit(); 520 } 521 } 522 523 524 530 private void writeObject(ObjectOutputStream s) throws IOException { 531 s.defaultWriteObject(); 532 HashMap additionalValues = new HashMap (1); 533 SpinnerModel model = getModel(); 534 535 if (model instanceof Serializable) { 536 additionalValues.put("model", model); 537 } 538 s.writeObject(additionalValues); 539 540 if (getUIClassID().equals(uiClassID)) { 541 byte count = JComponent.getWriteObjCounter(this); 542 JComponent.setWriteObjCounter(this, --count); 543 if (count == 0 && ui != null) { 544 ui.installUI(this); 545 } 546 } 547 } 548 549 550 private void readObject(ObjectInputStream s) 551 throws IOException, ClassNotFoundException { 552 s.defaultReadObject(); 553 554 Map additionalValues = (Map )s.readObject(); 555 556 model = (SpinnerModel )additionalValues.get("model"); 557 } 558 559 560 589 public static class DefaultEditor extends JPanel 590 implements ChangeListener, PropertyChangeListener, LayoutManager 591 { 592 604 public DefaultEditor(JSpinner spinner) { 605 super(null); 606 607 JFormattedTextField ftf = new JFormattedTextField (); 608 ftf.setName("Spinner.formattedTextField"); 609 ftf.setValue(spinner.getValue()); 610 ftf.addPropertyChangeListener(this); 611 ftf.setEditable(false); 612 613 String toolTipText = spinner.getToolTipText(); 614 if (toolTipText != null) { 615 ftf.setToolTipText(toolTipText); 616 } 617 618 add(ftf); 619 620 setLayout(this); 621 spinner.addChangeListener(this); 622 623 ActionMap ftfMap = ftf.getActionMap(); 629 630 if (ftfMap != null) { 631 ftfMap.put("increment", DISABLED_ACTION); 632 ftfMap.put("decrement", DISABLED_ACTION); 633 } 634 } 635 636 637 645 public void dismiss(JSpinner spinner) { 646 spinner.removeChangeListener(this); 647 } 648 649 650 660 public JSpinner getSpinner() { 661 for (Component c = this; c != null; c = c.getParent()) { 662 if (c instanceof JSpinner ) { 663 return (JSpinner )c; 664 } 665 } 666 return null; 667 } 668 669 670 680 public JFormattedTextField getTextField() { 681 return (JFormattedTextField )getComponent(0); 682 } 683 684 685 694 public void stateChanged(ChangeEvent e) { 695 JSpinner spinner = (JSpinner )(e.getSource()); 696 getTextField().setValue(spinner.getValue()); 697 } 698 699 700 715 public void propertyChange(PropertyChangeEvent e) 716 { 717 JSpinner spinner = getSpinner(); 718 719 if (spinner == null) { 720 return; 722 } 723 724 Object source = e.getSource(); 725 String name = e.getPropertyName(); 726 if ((source instanceof JFormattedTextField ) && "value".equals(name)) { 727 Object lastValue = spinner.getValue(); 728 729 try { 731 spinner.setValue(getTextField().getValue()); 732 } catch (IllegalArgumentException iae) { 733 try { 735 ((JFormattedTextField )source).setValue(lastValue); 736 } catch (IllegalArgumentException iae2) { 737 } 741 } 742 } 743 } 744 745 746 754 public void addLayoutComponent(String name, Component child) { 755 } 756 757 758 764 public void removeLayoutComponent(Component child) { 765 } 766 767 768 771 private Dimension insetSize(Container parent) { 772 Insets insets = parent.getInsets(); 773 int w = insets.left + insets.right; 774 int h = insets.top + insets.bottom; 775 return new Dimension(w, h); 776 } 777 778 779 787 public Dimension preferredLayoutSize(Container parent) { 788 Dimension preferredSize = insetSize(parent); 789 if (parent.getComponentCount() > 0) { 790 Dimension childSize = getComponent(0).getPreferredSize(); 791 preferredSize.width += childSize.width; 792 preferredSize.height += childSize.height; 793 } 794 return preferredSize; 795 } 796 797 798 806 public Dimension minimumLayoutSize(Container parent) { 807 Dimension minimumSize = insetSize(parent); 808 if (parent.getComponentCount() > 0) { 809 Dimension childSize = getComponent(0).getMinimumSize(); 810 minimumSize.width += childSize.width; 811 minimumSize.height += childSize.height; 812 } 813 return minimumSize; 814 } 815 816 817 821 public void layoutContainer(Container parent) { 822 if (parent.getComponentCount() > 0) { 823 Insets insets = parent.getInsets(); 824 int w = parent.getWidth() - (insets.left + insets.right); 825 int h = parent.getHeight() - (insets.top + insets.bottom); 826 getComponent(0).setBounds(insets.left, insets.top, w, h); 827 } 828 } 829 830 838 public void commitEdit() throws ParseException { 839 JFormattedTextField ftf = getTextField(); 843 844 ftf.commitEdit(); 845 } 846 } 847 848 849 850 851 855 private static class DateEditorFormatter extends DateFormatter { 856 private final SpinnerDateModel model; 857 858 DateEditorFormatter(SpinnerDateModel model, DateFormat format) { 859 super(format); 860 this.model = model; 861 } 862 863 public void setMinimum(Comparable min) { 864 model.setStart(min); 865 } 866 867 public Comparable getMinimum() { 868 return model.getStart(); 869 } 870 871 public void setMaximum(Comparable max) { 872 model.setEnd(max); 873 } 874 875 public Comparable getMaximum() { 876 return model.getEnd(); 877 } 878 } 879 880 881 889 public static class DateEditor extends DefaultEditor 891 { 892 private static String getDefaultPattern(Locale loc) { 895 ResourceBundle r = LocaleData.getLocaleElements(loc); 896 String [] dateTimePatterns = r.getStringArray("DateTimePatterns"); 897 Object [] dateTimeArgs = {dateTimePatterns[DateFormat.SHORT], 898 dateTimePatterns[DateFormat.SHORT + 4]}; 899 return MessageFormat.format(dateTimePatterns[8], dateTimeArgs); 900 } 901 902 918 public DateEditor(JSpinner spinner) { 919 this(spinner, getDefaultPattern(spinner.getLocale())); 920 } 921 922 923 943 public DateEditor(JSpinner spinner, String dateFormatPattern) { 944 this(spinner, new SimpleDateFormat(dateFormatPattern, 945 spinner.getLocale())); 946 } 947 948 968 private DateEditor(JSpinner spinner, DateFormat format) { 969 super(spinner); 970 if (!(spinner.getModel() instanceof SpinnerDateModel )) { 971 throw new IllegalArgumentException ( 972 "model not a SpinnerDateModel"); 973 } 974 975 SpinnerDateModel model = (SpinnerDateModel )spinner.getModel(); 976 DateFormatter formatter = new DateEditorFormatter(model, format); 977 DefaultFormatterFactory factory = new DefaultFormatterFactory( 978 formatter); 979 JFormattedTextField ftf = getTextField(); 980 ftf.setEditable(true); 981 ftf.setFormatterFactory(factory); 982 983 9
|