30 import javax.swing.*;
31 import javax.accessibility.*;
32 import javax.swing.plaf.*;
33 import javax.swing.text.*;
34 import javax.swing.event.*;
35 import java.beans.PropertyChangeListener;
36 import java.beans.PropertyChangeEvent;
37 import sun.awt.AppContext;
38 import sun.swing.DefaultLookup;
39 import sun.swing.UIAction;
40
41 /**
42 * Basic UI implementation for JComboBox.
43 * <p>
44 * The combo box is a compound component which means that it is an aggregate of
45 * many simpler components. This class creates and manages the listeners
46 * on the combo box and the combo box model. These listeners update the user
47 * interface in response to changes in the properties and state of the combo box.
48 * <p>
49 * All event handling is handled by listener classes created with the
50 * <code>createxxxListener()</code> methods and internal classes.
51 * You can change the behavior of this class by overriding the
52 * <code>createxxxListener()</code> methods and supplying your own
53 * event listeners or subclassing from the ones supplied in this class.
54 * <p>
55 * For adding specific actions,
56 * overide <code>installKeyboardActions</code> to add actions in response to
57 * KeyStroke bindings. See the article <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html">How to Use Key Bindings</a>
58 *
59 * @author Arnaud Weber
60 * @author Tom Santos
61 * @author Mark Davidson
62 */
63 public class BasicComboBoxUI extends ComboBoxUI {
64
65 /**
66 * The instance of {@code JComboBox}.
67 */
68 protected JComboBox<Object> comboBox;
69 /**
70 * This protected field is implementation specific. Do not access directly
71 * or override.
72 */
73 protected boolean hasFocus = false;
74
75 // Control the selection behavior of the JComboBox when it is used
76 // in the JTable DefaultCellEditor.
419 if ((mouseWheelListener = createMouseWheelListener()) != null) {
420 comboBox.addMouseWheelListener(mouseWheelListener);
421 }
422 }
423
424 /**
425 * Uninstalls the default colors, default font, default renderer,
426 * and default editor from the combo box.
427 */
428 protected void uninstallDefaults() {
429 LookAndFeel.installColorsAndFont( comboBox,
430 "ComboBox.background",
431 "ComboBox.foreground",
432 "ComboBox.font" );
433 LookAndFeel.uninstallBorder( comboBox );
434 }
435
436 /**
437 * Removes the installed listeners from the combo box and its model.
438 * The number and types of listeners removed and in this method should be
439 * the same that was added in <code>installListeners</code>
440 */
441 protected void uninstallListeners() {
442 if ( keyListener != null ) {
443 comboBox.removeKeyListener( keyListener );
444 }
445 if ( itemListener != null) {
446 comboBox.removeItemListener( itemListener );
447 }
448 if ( propertyChangeListener != null ) {
449 comboBox.removePropertyChangeListener( propertyChangeListener );
450 }
451 if ( focusListener != null) {
452 comboBox.removeFocusListener( focusListener );
453 }
454 if ( popupMouseListener != null) {
455 comboBox.removeMouseListener( popupMouseListener );
456 }
457 if ( popupMouseMotionListener != null) {
458 comboBox.removeMouseMotionListener( popupMouseMotionListener );
459 }
460 if (popupKeyListener != null) {
461 comboBox.removeKeyListener(popupKeyListener);
462 }
463 if ( comboBox.getModel() != null ) {
464 if ( listDataListener != null ) {
465 comboBox.getModel().removeListDataListener( listDataListener );
466 }
467 }
468 if (mouseWheelListener != null) {
469 comboBox.removeMouseWheelListener(mouseWheelListener);
470 }
471 }
472
473 /**
474 * Creates the popup portion of the combo box.
475 *
476 * @return an instance of <code>ComboPopup</code>
477 * @see ComboPopup
478 */
479 protected ComboPopup createPopup() {
480 return new BasicComboPopup( comboBox );
481 }
482
483 /**
484 * Creates a <code>KeyListener</code> which will be added to the
485 * combo box. If this method returns null then it will not be added
486 * to the combo box.
487 *
488 * @return an instance <code>KeyListener</code> or null
489 */
490 protected KeyListener createKeyListener() {
491 return getHandler();
492 }
493
494 /**
495 * Creates a <code>FocusListener</code> which will be added to the combo box.
496 * If this method returns null then it will not be added to the combo box.
497 *
498 * @return an instance of a <code>FocusListener</code> or null
499 */
500 protected FocusListener createFocusListener() {
501 return getHandler();
502 }
503
504 /**
505 * Creates a list data listener which will be added to the
506 * <code>ComboBoxModel</code>. If this method returns null then
507 * it will not be added to the combo box model.
508 *
509 * @return an instance of a <code>ListDataListener</code> or null
510 */
511 protected ListDataListener createListDataListener() {
512 return getHandler();
513 }
514
515 /**
516 * Creates an <code>ItemListener</code> which will be added to the
517 * combo box. If this method returns null then it will not
518 * be added to the combo box.
519 * <p>
520 * Subclasses may override this method to return instances of their own
521 * ItemEvent handlers.
522 *
523 * @return an instance of an <code>ItemListener</code> or null
524 */
525 protected ItemListener createItemListener() {
526 return null;
527 }
528
529 /**
530 * Creates a <code>PropertyChangeListener</code> which will be added to
531 * the combo box. If this method returns null then it will not
532 * be added to the combo box.
533 *
534 * @return an instance of a <code>PropertyChangeListener</code> or null
535 */
536 protected PropertyChangeListener createPropertyChangeListener() {
537 return getHandler();
538 }
539
540 /**
541 * Creates a layout manager for managing the components which make up the
542 * combo box.
543 *
544 * @return an instance of a layout manager
545 */
546 protected LayoutManager createLayoutManager() {
547 return getHandler();
548 }
549
550 /**
551 * Creates the default renderer that will be used in a non-editiable combo
552 * box. A default renderer will used only if a renderer has not been
553 * explicitly set with <code>setRenderer</code>.
554 *
555 * @return a <code>ListCellRender</code> used for the combo box
556 * @see javax.swing.JComboBox#setRenderer
557 */
558 protected ListCellRenderer<Object> createRenderer() {
559 return new BasicComboBoxRenderer.UIResource();
560 }
561
562 /**
563 * Creates the default editor that will be used in editable combo boxes.
564 * A default editor will be used only if an editor has not been
565 * explicitly set with <code>setEditor</code>.
566 *
567 * @return a <code>ComboBoxEditor</code> used for the combo box
568 * @see javax.swing.JComboBox#setEditor
569 */
570 protected ComboBoxEditor createEditor() {
571 return new BasicComboBoxEditor.UIResource();
572 }
573
574 /**
575 * Returns the shared listener.
576 */
577 private Handler getHandler() {
578 if (handler == null) {
579 handler = new Handler();
580 }
581 return handler;
582 }
583
584 private MouseWheelListener createMouseWheelListener() {
585 return getHandler();
586 }
587
588 //
589 // end UI Initialization
590 //======================
591
592
593 //======================
594 // begin Inner classes
595 //
596
597 /**
598 * This listener checks to see if the key event isn't a navigation key. If
599 * it finds a key event that wasn't a navigation key it dispatches it to
600 * JComboBox.selectWithKeyChar() so that it can do type-ahead.
601 *
602 * This public inner class should be treated as protected.
603 * Instantiate it only within subclasses of
604 * <code>BasicComboBoxUI</code>.
605 */
606 public class KeyHandler extends KeyAdapter {
607 @Override
608 public void keyPressed( KeyEvent e ) {
609 getHandler().keyPressed(e);
610 }
611 }
612
613 /**
614 * This listener hides the popup when the focus is lost. It also repaints
615 * when focus is gained or lost.
616 *
617 * This public inner class should be treated as protected.
618 * Instantiate it only within subclasses of
619 * <code>BasicComboBoxUI</code>.
620 */
621 public class FocusHandler implements FocusListener {
622 public void focusGained( FocusEvent e ) {
623 getHandler().focusGained(e);
624 }
625
626 public void focusLost( FocusEvent e ) {
627 getHandler().focusLost(e);
628 }
629 }
630
631 /**
632 * This listener watches for changes in the
633 * <code>ComboBoxModel</code>.
634 * <p>
635 * This public inner class should be treated as protected.
636 * Instantiate it only within subclasses of
637 * <code>BasicComboBoxUI</code>.
638 *
639 * @see #createListDataListener
640 */
641 public class ListDataHandler implements ListDataListener {
642 public void contentsChanged( ListDataEvent e ) {
643 getHandler().contentsChanged(e);
644 }
645
646 public void intervalAdded( ListDataEvent e ) {
647 getHandler().intervalAdded(e);
648 }
649
650 public void intervalRemoved( ListDataEvent e ) {
651 getHandler().intervalRemoved(e);
652 }
653 }
654
655 /**
656 * This listener watches for changes to the selection in the
657 * combo box.
658 * <p>
659 * This public inner class should be treated as protected.
660 * Instantiate it only within subclasses of
661 * <code>BasicComboBoxUI</code>.
662 *
663 * @see #createItemListener
664 */
665 public class ItemHandler implements ItemListener {
666 // This class used to implement behavior which is now redundant.
667 public void itemStateChanged(ItemEvent e) {}
668 }
669
670 /**
671 * This listener watches for bound properties that have changed in the
672 * combo box.
673 * <p>
674 * Subclasses which wish to listen to combo box property changes should
675 * call the superclass methods to ensure that the combo box ui correctly
676 * handles property changes.
677 * <p>
678 * This public inner class should be treated as protected.
679 * Instantiate it only within subclasses of
680 * <code>BasicComboBoxUI</code>.
681 *
682 * @see #createPropertyChangeListener
683 */
684 public class PropertyChangeHandler implements PropertyChangeListener {
685 public void propertyChange(PropertyChangeEvent e) {
686 getHandler().propertyChange(e);
687 }
688 }
689
690
691 // Syncronizes the ToolTip text for the components within the combo box to be the
692 // same value as the combo box ToolTip text.
693 private void updateToolTipTextForChildren() {
694 Component[] children = comboBox.getComponents();
695 for ( int i = 0; i < children.length; ++i ) {
696 if ( children[i] instanceof JComponent ) {
697 ((JComponent)children[i]).setToolTipText( comboBox.getToolTipText() );
698 }
699 }
700 }
701
702 /**
703 * This layout manager handles the 'standard' layout of combo boxes. It puts
704 * the arrow button to the right and the editor to the left. If there is no
705 * editor it still keeps the arrow button to the right.
706 *
707 * This public inner class should be treated as protected.
708 * Instantiate it only within subclasses of
709 * <code>BasicComboBoxUI</code>.
710 */
711 public class ComboBoxLayoutManager implements LayoutManager {
712 public void addLayoutComponent(String name, Component comp) {}
713
714 public void removeLayoutComponent(Component comp) {}
715
716 public Dimension preferredLayoutSize(Container parent) {
717 return getHandler().preferredLayoutSize(parent);
718 }
719
720 public Dimension minimumLayoutSize(Container parent) {
721 return getHandler().minimumLayoutSize(parent);
722 }
723
724 public void layoutContainer(Container parent) {
725 getHandler().layoutContainer(parent);
726 }
727 }
728
729 //
757
758 /**
759 * The aggregate components which comprise the combo box are
760 * unregistered and uninitialized. This method is called as part of the
761 * UI uninstallation process.
762 */
763 protected void uninstallComponents() {
764 if ( arrowButton != null ) {
765 unconfigureArrowButton();
766 }
767 if ( editor != null ) {
768 unconfigureEditor();
769 }
770 comboBox.removeAll(); // Just to be safe.
771 arrowButton = null;
772 }
773
774 /**
775 * This public method is implementation specific and should be private.
776 * do not call or override. To implement a specific editor create a
777 * custom <code>ComboBoxEditor</code>
778 *
779 * @see #createEditor
780 * @see javax.swing.JComboBox#setEditor
781 * @see javax.swing.ComboBoxEditor
782 */
783 public void addEditor() {
784 removeEditor();
785 editor = comboBox.getEditor().getEditorComponent();
786 if ( editor != null ) {
787 configureEditor();
788 comboBox.add(editor);
789 if(comboBox.isFocusOwner()) {
790 // Switch focus to the editor component
791 editor.requestFocusInWindow();
792 }
793 }
794 }
795
796 /**
797 * This public method is implementation specific and should be private.
|
30 import javax.swing.*;
31 import javax.accessibility.*;
32 import javax.swing.plaf.*;
33 import javax.swing.text.*;
34 import javax.swing.event.*;
35 import java.beans.PropertyChangeListener;
36 import java.beans.PropertyChangeEvent;
37 import sun.awt.AppContext;
38 import sun.swing.DefaultLookup;
39 import sun.swing.UIAction;
40
41 /**
42 * Basic UI implementation for JComboBox.
43 * <p>
44 * The combo box is a compound component which means that it is an aggregate of
45 * many simpler components. This class creates and manages the listeners
46 * on the combo box and the combo box model. These listeners update the user
47 * interface in response to changes in the properties and state of the combo box.
48 * <p>
49 * All event handling is handled by listener classes created with the
50 * {@code createxxxListener()} methods and internal classes.
51 * You can change the behavior of this class by overriding the
52 * {@code createxxxListener()} methods and supplying your own
53 * event listeners or subclassing from the ones supplied in this class.
54 * <p>
55 * For adding specific actions,
56 * overide {@code installKeyboardActions} to add actions in response to
57 * KeyStroke bindings. See the article <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html">How to Use Key Bindings</a>
58 *
59 * @author Arnaud Weber
60 * @author Tom Santos
61 * @author Mark Davidson
62 */
63 public class BasicComboBoxUI extends ComboBoxUI {
64
65 /**
66 * The instance of {@code JComboBox}.
67 */
68 protected JComboBox<Object> comboBox;
69 /**
70 * This protected field is implementation specific. Do not access directly
71 * or override.
72 */
73 protected boolean hasFocus = false;
74
75 // Control the selection behavior of the JComboBox when it is used
76 // in the JTable DefaultCellEditor.
419 if ((mouseWheelListener = createMouseWheelListener()) != null) {
420 comboBox.addMouseWheelListener(mouseWheelListener);
421 }
422 }
423
424 /**
425 * Uninstalls the default colors, default font, default renderer,
426 * and default editor from the combo box.
427 */
428 protected void uninstallDefaults() {
429 LookAndFeel.installColorsAndFont( comboBox,
430 "ComboBox.background",
431 "ComboBox.foreground",
432 "ComboBox.font" );
433 LookAndFeel.uninstallBorder( comboBox );
434 }
435
436 /**
437 * Removes the installed listeners from the combo box and its model.
438 * The number and types of listeners removed and in this method should be
439 * the same that was added in {@code installListeners}
440 */
441 protected void uninstallListeners() {
442 if ( keyListener != null ) {
443 comboBox.removeKeyListener( keyListener );
444 }
445 if ( itemListener != null) {
446 comboBox.removeItemListener( itemListener );
447 }
448 if ( propertyChangeListener != null ) {
449 comboBox.removePropertyChangeListener( propertyChangeListener );
450 }
451 if ( focusListener != null) {
452 comboBox.removeFocusListener( focusListener );
453 }
454 if ( popupMouseListener != null) {
455 comboBox.removeMouseListener( popupMouseListener );
456 }
457 if ( popupMouseMotionListener != null) {
458 comboBox.removeMouseMotionListener( popupMouseMotionListener );
459 }
460 if (popupKeyListener != null) {
461 comboBox.removeKeyListener(popupKeyListener);
462 }
463 if ( comboBox.getModel() != null ) {
464 if ( listDataListener != null ) {
465 comboBox.getModel().removeListDataListener( listDataListener );
466 }
467 }
468 if (mouseWheelListener != null) {
469 comboBox.removeMouseWheelListener(mouseWheelListener);
470 }
471 }
472
473 /**
474 * Creates the popup portion of the combo box.
475 *
476 * @return an instance of {@code ComboPopup}
477 * @see ComboPopup
478 */
479 protected ComboPopup createPopup() {
480 return new BasicComboPopup( comboBox );
481 }
482
483 /**
484 * Creates a {@code KeyListener} which will be added to the
485 * combo box. If this method returns null then it will not be added
486 * to the combo box.
487 *
488 * @return an instance {@code KeyListener} or null
489 */
490 protected KeyListener createKeyListener() {
491 return getHandler();
492 }
493
494 /**
495 * Creates a {@code FocusListener} which will be added to the combo box.
496 * If this method returns null then it will not be added to the combo box.
497 *
498 * @return an instance of a {@code FocusListener} or null
499 */
500 protected FocusListener createFocusListener() {
501 return getHandler();
502 }
503
504 /**
505 * Creates a list data listener which will be added to the
506 * {@code ComboBoxModel}. If this method returns null then
507 * it will not be added to the combo box model.
508 *
509 * @return an instance of a {@code ListDataListener} or null
510 */
511 protected ListDataListener createListDataListener() {
512 return getHandler();
513 }
514
515 /**
516 * Creates an {@code ItemListener} which will be added to the
517 * combo box. If this method returns null then it will not
518 * be added to the combo box.
519 * <p>
520 * Subclasses may override this method to return instances of their own
521 * ItemEvent handlers.
522 *
523 * @return an instance of an {@code ItemListener} or null
524 */
525 protected ItemListener createItemListener() {
526 return null;
527 }
528
529 /**
530 * Creates a {@code PropertyChangeListener} which will be added to
531 * the combo box. If this method returns null then it will not
532 * be added to the combo box.
533 *
534 * @return an instance of a {@code PropertyChangeListener} or null
535 */
536 protected PropertyChangeListener createPropertyChangeListener() {
537 return getHandler();
538 }
539
540 /**
541 * Creates a layout manager for managing the components which make up the
542 * combo box.
543 *
544 * @return an instance of a layout manager
545 */
546 protected LayoutManager createLayoutManager() {
547 return getHandler();
548 }
549
550 /**
551 * Creates the default renderer that will be used in a non-editiable combo
552 * box. A default renderer will used only if a renderer has not been
553 * explicitly set with {@code setRenderer}.
554 *
555 * @return a {@code ListCellRender} used for the combo box
556 * @see javax.swing.JComboBox#setRenderer
557 */
558 protected ListCellRenderer<Object> createRenderer() {
559 return new BasicComboBoxRenderer.UIResource();
560 }
561
562 /**
563 * Creates the default editor that will be used in editable combo boxes.
564 * A default editor will be used only if an editor has not been
565 * explicitly set with {@code setEditor}.
566 *
567 * @return a {@code ComboBoxEditor} used for the combo box
568 * @see javax.swing.JComboBox#setEditor
569 */
570 protected ComboBoxEditor createEditor() {
571 return new BasicComboBoxEditor.UIResource();
572 }
573
574 /**
575 * Returns the shared listener.
576 */
577 private Handler getHandler() {
578 if (handler == null) {
579 handler = new Handler();
580 }
581 return handler;
582 }
583
584 private MouseWheelListener createMouseWheelListener() {
585 return getHandler();
586 }
587
588 //
589 // end UI Initialization
590 //======================
591
592
593 //======================
594 // begin Inner classes
595 //
596
597 /**
598 * This listener checks to see if the key event isn't a navigation key. If
599 * it finds a key event that wasn't a navigation key it dispatches it to
600 * JComboBox.selectWithKeyChar() so that it can do type-ahead.
601 *
602 * This public inner class should be treated as protected.
603 * Instantiate it only within subclasses of
604 * {@code BasicComboBoxUI}.
605 */
606 public class KeyHandler extends KeyAdapter {
607 @Override
608 public void keyPressed( KeyEvent e ) {
609 getHandler().keyPressed(e);
610 }
611 }
612
613 /**
614 * This listener hides the popup when the focus is lost. It also repaints
615 * when focus is gained or lost.
616 *
617 * This public inner class should be treated as protected.
618 * Instantiate it only within subclasses of
619 * {@code BasicComboBoxUI}.
620 */
621 public class FocusHandler implements FocusListener {
622 public void focusGained( FocusEvent e ) {
623 getHandler().focusGained(e);
624 }
625
626 public void focusLost( FocusEvent e ) {
627 getHandler().focusLost(e);
628 }
629 }
630
631 /**
632 * This listener watches for changes in the
633 * {@code ComboBoxModel}.
634 * <p>
635 * This public inner class should be treated as protected.
636 * Instantiate it only within subclasses of
637 * {@code BasicComboBoxUI}.
638 *
639 * @see #createListDataListener
640 */
641 public class ListDataHandler implements ListDataListener {
642 public void contentsChanged( ListDataEvent e ) {
643 getHandler().contentsChanged(e);
644 }
645
646 public void intervalAdded( ListDataEvent e ) {
647 getHandler().intervalAdded(e);
648 }
649
650 public void intervalRemoved( ListDataEvent e ) {
651 getHandler().intervalRemoved(e);
652 }
653 }
654
655 /**
656 * This listener watches for changes to the selection in the
657 * combo box.
658 * <p>
659 * This public inner class should be treated as protected.
660 * Instantiate it only within subclasses of
661 * {@code BasicComboBoxUI}.
662 *
663 * @see #createItemListener
664 */
665 public class ItemHandler implements ItemListener {
666 // This class used to implement behavior which is now redundant.
667 public void itemStateChanged(ItemEvent e) {}
668 }
669
670 /**
671 * This listener watches for bound properties that have changed in the
672 * combo box.
673 * <p>
674 * Subclasses which wish to listen to combo box property changes should
675 * call the superclass methods to ensure that the combo box ui correctly
676 * handles property changes.
677 * <p>
678 * This public inner class should be treated as protected.
679 * Instantiate it only within subclasses of
680 * {@code BasicComboBoxUI}.
681 *
682 * @see #createPropertyChangeListener
683 */
684 public class PropertyChangeHandler implements PropertyChangeListener {
685 public void propertyChange(PropertyChangeEvent e) {
686 getHandler().propertyChange(e);
687 }
688 }
689
690
691 // Syncronizes the ToolTip text for the components within the combo box to be the
692 // same value as the combo box ToolTip text.
693 private void updateToolTipTextForChildren() {
694 Component[] children = comboBox.getComponents();
695 for ( int i = 0; i < children.length; ++i ) {
696 if ( children[i] instanceof JComponent ) {
697 ((JComponent)children[i]).setToolTipText( comboBox.getToolTipText() );
698 }
699 }
700 }
701
702 /**
703 * This layout manager handles the 'standard' layout of combo boxes. It puts
704 * the arrow button to the right and the editor to the left. If there is no
705 * editor it still keeps the arrow button to the right.
706 *
707 * This public inner class should be treated as protected.
708 * Instantiate it only within subclasses of
709 * {@code BasicComboBoxUI}.
710 */
711 public class ComboBoxLayoutManager implements LayoutManager {
712 public void addLayoutComponent(String name, Component comp) {}
713
714 public void removeLayoutComponent(Component comp) {}
715
716 public Dimension preferredLayoutSize(Container parent) {
717 return getHandler().preferredLayoutSize(parent);
718 }
719
720 public Dimension minimumLayoutSize(Container parent) {
721 return getHandler().minimumLayoutSize(parent);
722 }
723
724 public void layoutContainer(Container parent) {
725 getHandler().layoutContainer(parent);
726 }
727 }
728
729 //
757
758 /**
759 * The aggregate components which comprise the combo box are
760 * unregistered and uninitialized. This method is called as part of the
761 * UI uninstallation process.
762 */
763 protected void uninstallComponents() {
764 if ( arrowButton != null ) {
765 unconfigureArrowButton();
766 }
767 if ( editor != null ) {
768 unconfigureEditor();
769 }
770 comboBox.removeAll(); // Just to be safe.
771 arrowButton = null;
772 }
773
774 /**
775 * This public method is implementation specific and should be private.
776 * do not call or override. To implement a specific editor create a
777 * custom {@code ComboBoxEditor}
778 *
779 * @see #createEditor
780 * @see javax.swing.JComboBox#setEditor
781 * @see javax.swing.ComboBoxEditor
782 */
783 public void addEditor() {
784 removeEditor();
785 editor = comboBox.getEditor().getEditorComponent();
786 if ( editor != null ) {
787 configureEditor();
788 comboBox.add(editor);
789 if(comboBox.isFocusOwner()) {
790 // Switch focus to the editor component
791 editor.requestFocusInWindow();
792 }
793 }
794 }
795
796 /**
797 * This public method is implementation specific and should be private.
|