1 7 8 package javax.swing.plaf.basic; 9 10 import java.awt.*; 11 import java.awt.event.*; 12 import java.text.ParseException ; 13 14 import javax.swing.*; 15 import javax.swing.border.*; 16 import javax.swing.event.*; 17 import javax.swing.plaf.*; 18 import javax.swing.text.*; 19 20 import java.beans.*; 21 import java.text.*; 22 import java.util.*; 23 import sun.swing.DefaultLookup; 24 25 26 33 public class BasicSpinnerUI extends SpinnerUI 34 { 35 43 protected JSpinner spinner; 44 private Handler handler; 45 46 47 55 private static final ArrowButtonHandler nextButtonHandler = new ArrowButtonHandler("increment", true); 56 private static final ArrowButtonHandler previousButtonHandler = new ArrowButtonHandler("decrement", false); 57 private PropertyChangeListener propertyChangeListener; 58 59 60 64 private static final Dimension zeroSize = new Dimension(0, 0); 65 66 67 75 public static ComponentUI createUI(JComponent c) { 76 return new BasicSpinnerUI (); 77 } 78 79 80 private void maybeAdd(Component c, String s) { 81 if (c != null) { 82 spinner.add(c, s); 83 } 84 } 85 86 87 99 public void installUI(JComponent c) { 100 this.spinner = (JSpinner)c; 101 installDefaults(); 102 installListeners(); 103 maybeAdd(createNextButton(), "Next"); 104 maybeAdd(createPreviousButton(), "Previous"); 105 maybeAdd(createEditor(), "Editor"); 106 updateEnabledState(); 107 installKeyboardActions(); 108 } 109 110 111 117 public void uninstallUI(JComponent c) { 118 uninstallDefaults(); 119 uninstallListeners(); 120 this.spinner = null; 121 c.removeAll(); 122 } 123 124 125 135 protected void installListeners() { 136 propertyChangeListener = createPropertyChangeListener(); 137 spinner.addPropertyChangeListener(propertyChangeListener); 138 JComponent editor = spinner.getEditor(); 139 if (editor != null && editor instanceof JSpinner.DefaultEditor) { 140 JTextField tf = ((JSpinner.DefaultEditor)editor).getTextField(); 141 if (tf != null) { 142 tf.addFocusListener(nextButtonHandler); 143 tf.addFocusListener(previousButtonHandler); 144 } 145 } 146 } 147 148 149 157 protected void uninstallListeners() { 158 spinner.removePropertyChangeListener(propertyChangeListener); 159 JComponent editor = spinner.getEditor(); 160 removeEditorBorderListener(editor); 161 if (editor instanceof JSpinner.DefaultEditor) { 162 JTextField tf = ((JSpinner.DefaultEditor)editor).getTextField(); 163 if (tf != null) { 164 tf.removeFocusListener(nextButtonHandler); 165 tf.removeFocusListener(previousButtonHandler); 166 } 167 } 168 propertyChangeListener = null; 169 handler = null; 170 } 171 172 173 186 protected void installDefaults() { 187 spinner.setLayout(createLayout()); 188 LookAndFeel.installBorder(spinner, "Spinner.border"); 189 LookAndFeel.installColorsAndFont(spinner, "Spinner.background", "Spinner.foreground", "Spinner.font"); 190 LookAndFeel.installProperty(spinner, "opaque", Boolean.TRUE); 191 } 192 193 194 201 protected void uninstallDefaults() { 202 spinner.setLayout(null); 203 } 204 205 206 private Handler getHandler() { 207 if (handler == null) { 208 handler = new Handler(); 209 } 210 return handler; 211 } 212 213 214 223 protected void installNextButtonListeners(Component c) { 224 installButtonListeners(c, nextButtonHandler); 225 } 226 227 236 protected void installPreviousButtonListeners(Component c) { 237 installButtonListeners(c, previousButtonHandler); 238 } 239 240 private void installButtonListeners(Component c, 241 ArrowButtonHandler handler) { 242 if (c instanceof JButton) { 243 ((JButton)c).addActionListener(handler); 244 } 245 c.addMouseListener(handler); 246 } 247 248 261 protected LayoutManager createLayout() { 262 return getHandler(); 263 } 264 265 266 277 protected PropertyChangeListener createPropertyChangeListener() { 278 return getHandler(); 279 } 280 281 282 297 protected Component createPreviousButton() { 298 Component c = createArrowButton(SwingConstants.SOUTH); 299 installPreviousButtonListeners(c); 300 return c; 301 } 302 303 304 318 protected Component createNextButton() { 319 Component c = createArrowButton(SwingConstants.NORTH); 320 installNextButtonListeners(c); 321 return c; 322 } 323 324 private Component createArrowButton(int direction) { 325 JButton b = new BasicArrowButton (direction); 326 Border buttonBorder = UIManager.getBorder("Spinner.arrowButtonBorder"); 327 if (buttonBorder instanceof UIResource) { 328 b.setBorder(new CompoundBorder(buttonBorder, null)); 331 } else { 332 b.setBorder(buttonBorder); 333 } 334 return b; 335 } 336 337 338 361 protected JComponent createEditor() { 362 JComponent editor = spinner.getEditor(); 363 maybeRemoveEditorBorder(editor); 364 installEditorBorderListener(editor); 365 return editor; 366 } 367 368 369 384 protected void replaceEditor(JComponent oldEditor, JComponent newEditor) { 385 spinner.remove(oldEditor); 386 maybeRemoveEditorBorder(newEditor); 387 installEditorBorderListener(newEditor); 388 spinner.add(newEditor, "Editor"); 389 } 390 391 395 private void maybeRemoveEditorBorder(JComponent editor) { 396 if (!UIManager.getBoolean("Spinner.editorBorderPainted")) { 397 if (editor instanceof JPanel && 398 editor.getBorder() == null && 399 editor.getComponentCount() > 0) { 400 401 editor = (JComponent)editor.getComponent(0); 402 } 403 404 if (editor != null && editor.getBorder() instanceof UIResource) { 405 editor.setBorder(null); 406 } 407 } 408 } 409 410 414 private void installEditorBorderListener(JComponent editor) { 415 if (!UIManager.getBoolean("Spinner.editorBorderPainted")) { 416 if (editor instanceof JPanel && 417 editor.getBorder() == null && 418 editor.getComponentCount() > 0) { 419 420 editor = (JComponent)editor.getComponent(0); 421 } 422 if (editor != null && 423 (editor.getBorder() == null || 424 editor.getBorder() instanceof UIResource)) { 425 editor.addPropertyChangeListener(getHandler()); 426 } 427 } 428 } 429 430 private void removeEditorBorderListener(JComponent editor) { 431 if (!UIManager.getBoolean("Spinner.editorBorderPainted")) { 432 if (editor instanceof JPanel && 433 editor.getComponentCount() > 0) { 434 435 editor = (JComponent)editor.getComponent(0); 436 } 437 if (editor != null) { 438 editor.removePropertyChangeListener(getHandler()); 439 } 440 } 441 } 442 443 444 448 private void updateEnabledState() { 449 updateEnabledState(spinner, spinner.isEnabled()); 450 } 451 452 453 457 private void updateEnabledState(Container c, boolean enabled) { 458 for (int counter = c.getComponentCount() - 1; counter >= 0;counter--) { 459 Component child = c.getComponent(counter); 460 461 child.setEnabled(enabled); 462 if (child instanceof Container) { 463 updateEnabledState((Container)child, enabled); 464 } 465 } 466 } 467 468 469 474 protected void installKeyboardActions() { 475 InputMap iMap = getInputMap(JComponent. 476 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 477 478 SwingUtilities.replaceUIInputMap(spinner, JComponent. 479 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, 480 iMap); 481 482 LazyActionMap.installLazyActionMap(spinner, BasicSpinnerUI .class, 483 "Spinner.actionMap"); 484 } 485 486 489 private InputMap getInputMap(int condition) { 490 if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) { 491 return (InputMap)DefaultLookup.get(spinner, this, 492 "Spinner.ancestorInputMap"); 493 } 494 return null; 495 } 496 497 static void loadActionMap(LazyActionMap map) { 498 map.put("increment", nextButtonHandler); 499 map.put("decrement", previousButtonHandler); 500 } 501 502 518 private static class ArrowButtonHandler extends AbstractAction 519 implements FocusListener, MouseListener, UIResource { 520 final javax.swing.Timer autoRepeatTimer; 521 final boolean isNext; 522 JSpinner spinner = null; 523 JButton arrowButton = null; 524 525 ArrowButtonHandler(String name, boolean isNext) { 526 super(name); 527 this.isNext = isNext; 528 autoRepeatTimer = new javax.swing.Timer (60, this); 529 autoRepeatTimer.setInitialDelay(300); 530 } 531 532 private JSpinner eventToSpinner(AWTEvent e) { 533 Object src = e.getSource(); 534 while ((src instanceof Component) && !(src instanceof JSpinner)) { 535 src = ((Component)src).getParent(); 536 } 537 return (src instanceof JSpinner) ? (JSpinner)src : null; 538 } 539 540 public void actionPerformed(ActionEvent e) { 541 JSpinner spinner = this.spinner; 542 543 if (!(e.getSource() instanceof javax.swing.Timer )) { 544 spinner = eventToSpinner(e); 546 if (e.getSource() instanceof JButton) { 547 arrowButton = (JButton)e.getSource(); 548 } 549 } else { 550 if (arrowButton!=null && !arrowButton.getModel().isPressed() 551 && autoRepeatTimer.isRunning()) { 552 autoRepeatTimer.stop(); 553 spinner = null; 554 arrowButton = null; 555 } 556 } 557 if (spinner != null) { 558 try { 559 int calendarField = getCalendarField(spinner); 560 spinner.commitEdit(); 561 if (calendarField != -1) { 562 ((SpinnerDateModel)spinner.getModel()). 563 setCalendarField(calendarField); 564 } 565 Object value = (isNext) ? spinner.getNextValue() : 566 spinner.getPreviousValue(); 567 if (value != null) { 568 spinner.setValue(value); 569 select(spinner); 570 } 571 } catch (IllegalArgumentException iae) { 572 UIManager.getLookAndFeel().provideErrorFeedback(spinner); 573 } catch (ParseException pe) { 574 UIManager.getLookAndFeel().provideErrorFeedback(spinner); 575 } 576 } 577 } 578 579 583 private void select(JSpinner spinner) { 584 JComponent editor = spinner.getEditor(); 585 586 if (editor instanceof JSpinner.DateEditor) { 587 JSpinner.DateEditor dateEditor = (JSpinner.DateEditor)editor; 588 JFormattedTextField ftf = dateEditor.getTextField(); 589 Format format = dateEditor.getFormat(); 590 Object value; 591 592 if (format != null && (value = spinner.getValue()) != null) { 593 SpinnerDateModel model = dateEditor.getModel(); 594 DateFormat.Field field = DateFormat.Field.ofCalendarField( 595 model.getCalendarField()); 596 597 if (field != null) { 598 try { 599 AttributedCharacterIterator iterator = format. 600 formatToCharacterIterator(value); 601 if (!select(ftf, iterator, field) && 602 field == DateFormat.Field.HOUR0) { 603 select(ftf, iterator, DateFormat.Field.HOUR1); 604 } 605 } 606 catch (IllegalArgumentException iae) {} 607 } 608 } 609 } 610 } 611 612 616 private boolean select(JFormattedTextField ftf, 617 AttributedCharacterIterator iterator, 618 DateFormat.Field field) { 619 int max = ftf.getDocument().getLength(); 620 621 iterator.first(); 622 do { 623 Map attrs = iterator.getAttributes(); 624 625 if (attrs != null && attrs.containsKey(field)){ 626 int start = iterator.getRunStart(field); 627 int end = iterator.getRunLimit(field); 628 629 if (start != -1 && end != -1 && start <= max && 630 end <= max) { 631 ftf.select(start, end); 632 } 633 return true; 634 } 635 } while (iterator.next() != CharacterIterator.DONE); 636 return false; 637 } 638 639 644 private int getCalendarField(JSpinner spinner) { 645 JComponent editor = spinner.getEditor(); 646 647 if (editor instanceof JSpinner.DateEditor) { 648 JSpinner.DateEditor dateEditor = (JSpinner.DateEditor)editor; 649 JFormattedTextField ftf = dateEditor.getTextField(); 650 int start = ftf.getSelectionStart(); 651 JFormattedTextField.AbstractFormatter formatter = 652 ftf.getFormatter(); 653 654 if (formatter instanceof InternationalFormatter) { 655 Format.Field[] fields = ((InternationalFormatter) 656 formatter).getFields(start); 657 658 for (int counter = 0; counter < fields.length; counter++) { 659 if (fields[counter] instanceof DateFormat.Field) { 660 int calendarField; 661 662 if (fields[counter] == DateFormat.Field.HOUR1) { 663 calendarField = Calendar.HOUR; 664 } 665 else { 666 calendarField = ((DateFormat.Field) 667 fields[counter]).getCalendarField(); 668 } 669 if (calendarField != -1) { 670 return calendarField; 671 } 672 } 673 } 674 } 675 } 676 return -1; 677 } 678 679 public void mousePressed(MouseEvent e) { 680 if (SwingUtilities.isLeftMouseButton(e) && e.getComponent().isEnabled()) { 681 spinner = eventToSpinner(e); 682 autoRepeatTimer.start(); 683 684 focusSpinnerIfNecessary(); 685 } 686 } 687 688 public void mouseReleased(MouseEvent e) { 689 autoRepeatTimer.stop(); 690 arrowButton = null; 691 spinner = null; 692 } 693 694 public void mouseClicked(MouseEvent e) { 695 } 696 697 public void mouseEntered(MouseEvent e) { 698 if (spinner != null && !autoRepeatTimer.isRunning()) { 699 autoRepeatTimer.start(); 700 } 701 } 702 703 public void mouseExited(MouseEvent e) { 704 if (autoRepeatTimer.isRunning()) { 705 autoRepeatTimer.stop(); 706 } 707 } 708 709 713 private void focusSpinnerIfNecessary() { 714 Component fo = KeyboardFocusManager. 715 getCurrentKeyboardFocusManager().getFocusOwner(); 716 if (spinner.isRequestFocusEnabled() && ( 717 fo == null || 718 !SwingUtilities.isDescendingFrom(fo, spinner))) { 719 Container root = spinner; 720 721 if (!root.isFocusCycleRoot()) { 722 root = root.getFocusCycleRootAncestor(); 723 } 724 if (root != null) { 725 FocusTraversalPolicy ftp = root.getFocusTraversalPolicy(); 726 Component child = ftp.getComponentAfter(root, spinner); 727 728 if (child != null && SwingUtilities.isDescendingFrom( 729 child, spinner)) { 730 child.requestFocus(); 731 } 732 } 733 } 734 } 735 736 public void focusGained(FocusEvent e) { 737 } 738 739 public void focusLost(FocusEvent e) { 740 if (autoRepeatTimer.isRunning()) { 741 autoRepeatTimer.stop(); 742 } 743 spinner = null; 744 if (arrowButton != null) { 745 ButtonModel model = arrowButton.getModel(); 746 model.setPressed(false); 747 model.setArmed(false); 748 arrowButton = null; 749 } 750 } 751 } 752 753 754 private static class Handler implements LayoutManager, 755 PropertyChangeListener { 756 private Component nextButton = null; 760 private Component previousButton = null; 761 private Component editor = null; 762 763 public void addLayoutComponent(String name, Component c) { 764 if ("Next".equals(name)) { 765 nextButton = c; 766 } 767 else if ("Previous".equals(name)) { 768 previousButton = c; 769 } 770 else if ("Editor".equals(name)) { 771 editor = c; 772 } 773 } 774 775 public void removeLayoutComponent(Component c) { 776 if (c == nextButton) { 777 c = null; 778 } 779 else if (c == previousButton) { 780 previousButton = null; 781 } 782 else if (c == editor) { 783 editor = null; 784 } 785 } 786 787 private Dimension preferredSize(Component c) { 788 return (c == null) ? zeroSize : c.getPreferredSize(); 789 } 790 791 public Dimension preferredLayoutSize(Container parent) { 792 Dimension nextD = preferredSize(nextButton); 793 Dimension previousD = preferredSize(previousButton); 794 Dimension editorD = preferredSize(editor); 795 796 798 editorD.height = ((editorD.height + 1) / 2) * 2; 799 800 Dimension size = new Dimension(editorD.width, editorD.height); 801 size.width += Math.max(nextD.width, previousD.width); 802 Insets insets = parent.getInsets(); 803 size.width += insets.left + insets.right; 804 size.height += insets.top + insets.bottom; 805 return size; 806 } 807 808 public Dimension minimumLayoutSize(Container parent) { 809 return preferredLayoutSize(parent); 810 } 811 812 private void setBounds(Component c, int x, int y, int width, int height) { 813 if (c != null) { 814 c.setBounds(x, y, width, height); 815 } 816 } 817 818 public void layoutContainer(Container parent) { 819 int width = parent.getWidth(); 820 int height = parent.getHeight(); 821 822 Insets insets = parent.getInsets(); 823 Dimension nextD = preferredSize(nextButton); 824 Dimension previousD = preferredSize(previousButton); 825 int buttonsWidth = Math.max(nextD.width, previousD.width); 826 int editorHeight = height - (insets.top + insets.bottom); 827 828 Insets buttonInsets = UIManager.getInsets("Spinner.arrowButtonInsets"); 834 if (buttonInsets == null) { 835 buttonInsets = insets; 836 } 837 838 840 int editorX, editorWidth, buttonsX; 841 if (parent.getComponentOrientation().isLeftToRight()) { 842 editorX = insets.left; 843 editorWidth = width - insets.left - buttonsWidth - buttonInsets.right; 844 buttonsX = width - buttonsWidth - buttonInsets.right; 845 } else { 846 buttonsX = buttonInsets.left; 847 editorX = buttonsX + buttonsWidth; 848 editorWidth = width - buttonInsets.left - buttonsWidth - insets.right; 849 } 850 851 int nextY = buttonInsets.top; 852 int nextHeight = (height / 2) + (height % 2) - nextY; 853 int previousY = buttonInsets.top + nextHeight; 854 int previousHeight = height - previousY - buttonInsets.bottom; 855 856 setBounds(editor, editorX, insets.top, editorWidth, editorHeight); 857 setBounds(nextButton, buttonsX, nextY, buttonsWidth, nextHeight); 858 setBounds(previousButton, buttonsX, previousY, buttonsWidth, previousHeight); 859 } 860 861 862 public void propertyChange(PropertyChangeEvent e) 866 { 867 String propertyName = e.getPropertyName(); 868 if (e.getSource() instanceof JSpinner) { 869 JSpinner spinner = (JSpinner)(e.getSource()); 870 SpinnerUI spinnerUI = spinner.getUI(); 871 872 if (spinnerUI instanceof BasicSpinnerUI ) { 873 BasicSpinnerUI ui = (BasicSpinnerUI )spinnerUI; 874 875 if ("editor".equals(propertyName)) { 876 JComponent oldEditor = (JComponent)e.getOldValue(); 877 JComponent newEditor = (JComponent)e.getNewValue(); 878 ui.replaceEditor(oldEditor, newEditor); 879 ui.updateEnabledState(); 880 if (oldEditor instanceof JSpinner.DefaultEditor) { 881 JTextField tf = 882 ((JSpinner.DefaultEditor)oldEditor).getTextField(); 883 if (tf != null) { 884 tf.removeFocusListener(nextButtonHandler); 885 tf.removeFocusListener(previousButtonHandler); 886 } 887 } 888 if (newEditor instanceof JSpinner.DefaultEditor) { 889 JTextField tf = 890 ((JSpinner.DefaultEditor)newEditor).getTextField(); 891 if (tf != null) { 892 if (tf.getFont() instanceof UIResource) { 893 tf.setFont(spinner.getFont()); 894 } 895 tf.addFocusListener(nextButtonHandler); 896 tf.addFocusListener(previousButtonHandler); 897 } 898 } 899 if (newEditor instanceof JSpinner.DefaultEditor) { 900 JTextField tf = 901 ((JSpinner.DefaultEditor)newEditor).getTextField(); 902 if (tf != null) { 903 if (tf.getFont() instanceof UIResource) { 904 tf.setFont(spinner.getFont()); 905 } 906 } 907 } 908 } 909 else if ("enabled".equals(propertyName)) { 910 ui.updateEnabledState(); 911 } 912 else if ("font".equals(propertyName)) { 913 JComponent editor = spinner.getEditor(); 914 if (editor!=null && editor instanceof JSpinner.DefaultEditor) { 915 JTextField tf = 916 ((JSpinner.DefaultEditor)editor).getTextField(); 917 if (tf != null) { 918 if (tf.getFont() instanceof UIResource) { 919 tf.setFont(spinner.getFont()); 920 } 921 } 922 } 923 } 924 else if (JComponent.TOOL_TIP_TEXT_KEY.equals(propertyName)) { 925 updateToolTipTextForChildren(spinner); 926 } 927 } 928 } else if (e.getSource() instanceof JComponent) { 929 JComponent c = (JComponent)e.getSource(); 930 if ((c.getParent() instanceof JPanel) && 931 (c.getParent().getParent() instanceof JSpinner) && 932 "border".equals(propertyName)) { 933 934 JSpinner spinner = (JSpinner)c.getParent().getParent(); 935 SpinnerUI spinnerUI = spinner.getUI(); 936 if (spinnerUI instanceof BasicSpinnerUI ) { 937 BasicSpinnerUI ui = (BasicSpinnerUI )spinnerUI; 938 ui.maybeRemoveEditorBorder(c); 939 } 940 } 941 } 942 } 943 944 private void updateToolTipTextForChildren(JComponent spinner) { 947 String toolTipText = spinner.getToolTipText(); 948 Component[] children = spinner.getComponents(); 949 for (int i = 0; i < children.length; i++) { 950 if (children[i] instanceof JSpinner.DefaultEditor) { 951 JTextField tf = ((JSpinner.DefaultEditor)children[i]).getTextField(); 952 if (tf != null) { 953 tf.setToolTipText(toolTipText); 954 } 955 } else if (children[i] instanceof JComponent) { 956 ((JComponent)children[i]).setToolTipText( spinner.getToolTipText() ); 957 } 958 } 959 } 960 } 961 } 962 | Popular Tags |