alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (BasicComboPopup.java)

This example Java source code file (BasicComboPopup.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

autoscrollactionhandler, awt, bean, border, comboboxmodel, component, dimension, gui, insets, javabean, jlist, mouseevent, mouselistener, mousemotionlistener, point, propertychangelistener, rectangle, scroll_down, scroll_up, swing

The BasicComboPopup.java Java example source code

/*
 * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package javax.swing.plaf.basic;

import javax.accessibility.AccessibleContext;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.io.Serializable;


/**
 * This is a basic implementation of the <code>ComboPopup interface.
 *
 * This class represents the ui for the popup portion of the combo box.
 * <p>
 * All event handling is handled by listener classes created with the
 * <code>createxxxListener() methods and internal classes.
 * You can change the behavior of this class by overriding the
 * <code>createxxxListener() methods and supplying your own
 * event listeners or subclassing from the ones supplied in this class.
 * <p>
 * <strong>Warning:
 * Serialized objects of this class will not be compatible with
 * future Swing releases. The current serialization support is
 * appropriate for short term storage or RMI between applications running
 * the same version of Swing.  As of 1.4, support for long term storage
 * of all JavaBeans™
 * has been added to the <code>java.beans package.
 * Please see {@link java.beans.XMLEncoder}.
 *
 * @author Tom Santos
 * @author Mark Davidson
 */
public class BasicComboPopup extends JPopupMenu implements ComboPopup {
    // An empty ListMode, this is used when the UI changes to allow
    // the JList to be gc'ed.
    private static class EmptyListModelClass implements ListModel<Object>, Serializable {
        public int getSize() { return 0; }
        public Object getElementAt(int index) { return null; }
        public void addListDataListener(ListDataListener l) {}
        public void removeListDataListener(ListDataListener l) {}
    };

    static final ListModel EmptyListModel = new EmptyListModelClass();

    private static Border LIST_BORDER = new LineBorder(Color.BLACK, 1);

    protected JComboBox                comboBox;
    /**
     * This protected field is implementation specific. Do not access directly
     * or override. Use the accessor methods instead.
     *
     * @see #getList
     * @see #createList
     */
    protected JList                    list;
    /**
     * This protected field is implementation specific. Do not access directly
     * or override. Use the create method instead
     *
     * @see #createScroller
     */
    protected JScrollPane              scroller;

    /**
     * As of Java 2 platform v1.4 this previously undocumented field is no
     * longer used.
     */
    protected boolean                  valueIsAdjusting = false;

    // Listeners that are required by the ComboPopup interface

    /**
     * Implementation of all the listener classes.
     */
    private Handler handler;

    /**
     * This protected field is implementation specific. Do not access directly
     * or override. Use the accessor or create methods instead.
     *
     * @see #getMouseMotionListener
     * @see #createMouseMotionListener
     */
    protected MouseMotionListener      mouseMotionListener;
    /**
     * This protected field is implementation specific. Do not access directly
     * or override. Use the accessor or create methods instead.
     *
     * @see #getMouseListener
     * @see #createMouseListener
     */
    protected MouseListener            mouseListener;

    /**
     * This protected field is implementation specific. Do not access directly
     * or override. Use the accessor or create methods instead.
     *
     * @see #getKeyListener
     * @see #createKeyListener
     */
    protected KeyListener              keyListener;

    /**
     * This protected field is implementation specific. Do not access directly
     * or override. Use the create method instead.
     *
     * @see #createListSelectionListener
     */
    protected ListSelectionListener    listSelectionListener;

    // Listeners that are attached to the list
    /**
     * This protected field is implementation specific. Do not access directly
     * or override. Use the create method instead.
     *
     * @see #createListMouseListener
     */
    protected MouseListener            listMouseListener;
    /**
     * This protected field is implementation specific. Do not access directly
     * or override. Use the create method instead
     *
     * @see #createListMouseMotionListener
     */
    protected MouseMotionListener      listMouseMotionListener;

    // Added to the combo box for bound properties
    /**
     * This protected field is implementation specific. Do not access directly
     * or override. Use the create method instead
     *
     * @see #createPropertyChangeListener
     */
    protected PropertyChangeListener   propertyChangeListener;

    // Added to the combo box model
    /**
     * This protected field is implementation specific. Do not access directly
     * or override. Use the create method instead
     *
     * @see #createListDataListener
     */
    protected ListDataListener         listDataListener;

    /**
     * This protected field is implementation specific. Do not access directly
     * or override. Use the create method instead
     *
     * @see #createItemListener
     */
    protected ItemListener             itemListener;

    /**
     * This protected field is implementation specific. Do not access directly
     * or override.
     */
    protected Timer                    autoscrollTimer;
    protected boolean                  hasEntered = false;
    protected boolean                  isAutoScrolling = false;
    protected int                      scrollDirection = SCROLL_UP;

    protected static final int         SCROLL_UP = 0;
    protected static final int         SCROLL_DOWN = 1;


    //========================================
    // begin ComboPopup method implementations
    //

    /**
     * Implementation of ComboPopup.show().
     */
    public void show() {
        comboBox.firePopupMenuWillBecomeVisible();
        setListSelection(comboBox.getSelectedIndex());
        Point location = getPopupLocation();
        show( comboBox, location.x, location.y );
    }


    /**
     * Implementation of ComboPopup.hide().
     */
    public void hide() {
        MenuSelectionManager manager = MenuSelectionManager.defaultManager();
        MenuElement [] selection = manager.getSelectedPath();
        for ( int i = 0 ; i < selection.length ; i++ ) {
            if ( selection[i] == this ) {
                manager.clearSelectedPath();
                break;
            }
        }
        if (selection.length > 0) {
            comboBox.repaint();
        }
    }

    /**
     * Implementation of ComboPopup.getList().
     */
    public JList getList() {
        return list;
    }

    /**
     * Implementation of ComboPopup.getMouseListener().
     *
     * @return a <code>MouseListener or null
     * @see ComboPopup#getMouseListener
     */
    public MouseListener getMouseListener() {
        if (mouseListener == null) {
            mouseListener = createMouseListener();
        }
        return mouseListener;
    }

    /**
     * Implementation of ComboPopup.getMouseMotionListener().
     *
     * @return a <code>MouseMotionListener or null
     * @see ComboPopup#getMouseMotionListener
     */
    public MouseMotionListener getMouseMotionListener() {
        if (mouseMotionListener == null) {
            mouseMotionListener = createMouseMotionListener();
        }
        return mouseMotionListener;
    }

    /**
     * Implementation of ComboPopup.getKeyListener().
     *
     * @return a <code>KeyListener or null
     * @see ComboPopup#getKeyListener
     */
    public KeyListener getKeyListener() {
        if (keyListener == null) {
            keyListener = createKeyListener();
        }
        return keyListener;
    }

    /**
     * Called when the UI is uninstalling.  Since this popup isn't in the component
     * tree, it won't get it's uninstallUI() called.  It removes the listeners that
     * were added in addComboBoxListeners().
     */
    public void uninstallingUI() {
        if (propertyChangeListener != null) {
            comboBox.removePropertyChangeListener( propertyChangeListener );
        }
        if (itemListener != null) {
            comboBox.removeItemListener( itemListener );
        }
        uninstallComboBoxModelListeners(comboBox.getModel());
        uninstallKeyboardActions();
        uninstallListListeners();
        // We do this, otherwise the listener the ui installs on
        // the model (the combobox model in this case) will keep a
        // reference to the list, causing the list (and us) to never get gced.
        list.setModel(EmptyListModel);
    }

    //
    // end ComboPopup method implementations
    //======================================

    /**
     * Removes the listeners from the combo box model
     *
     * @param model The combo box model to install listeners
     * @see #installComboBoxModelListeners
     */
    protected void uninstallComboBoxModelListeners( ComboBoxModel model ) {
        if (model != null && listDataListener != null) {
            model.removeListDataListener(listDataListener);
        }
    }

    protected void uninstallKeyboardActions() {
        // XXX - shouldn't call this method
//        comboBox.unregisterKeyboardAction( KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, 0 ) );
    }



    //===================================================================
    // begin Initialization routines
    //
    public BasicComboPopup( JComboBox combo ) {
        super();
        setName("ComboPopup.popup");
        comboBox = combo;

        setLightWeightPopupEnabled( comboBox.isLightWeightPopupEnabled() );

        // UI construction of the popup.
        list = createList();
        list.setName("ComboBox.list");
        configureList();
        scroller = createScroller();
        scroller.setName("ComboBox.scrollPane");
        configureScroller();
        configurePopup();

        installComboBoxListeners();
        installKeyboardActions();
    }

    // Overriden PopupMenuListener notification methods to inform combo box
    // PopupMenuListeners.

    protected void firePopupMenuWillBecomeVisible() {
        super.firePopupMenuWillBecomeVisible();
        // comboBox.firePopupMenuWillBecomeVisible() is called from BasicComboPopup.show() method
        // to let the user change the popup menu from the PopupMenuListener.popupMenuWillBecomeVisible()
    }

    protected void firePopupMenuWillBecomeInvisible() {
        super.firePopupMenuWillBecomeInvisible();
        comboBox.firePopupMenuWillBecomeInvisible();
    }

    protected void firePopupMenuCanceled() {
        super.firePopupMenuCanceled();
        comboBox.firePopupMenuCanceled();
    }

    /**
     * Creates a listener
     * that will watch for mouse-press and release events on the combo box.
     *
     * <strong>Warning:
     * When overriding this method, make sure to maintain the existing
     * behavior.
     *
     * @return a <code>MouseListener which will be added to
     * the combo box or null
     */
    protected MouseListener createMouseListener() {
        return getHandler();
    }

    /**
     * Creates the mouse motion listener which will be added to the combo
     * box.
     *
     * <strong>Warning:
     * When overriding this method, make sure to maintain the existing
     * behavior.
     *
     * @return a <code>MouseMotionListener which will be added to
     *         the combo box or null
     */
    protected MouseMotionListener createMouseMotionListener() {
        return getHandler();
    }

    /**
     * Creates the key listener that will be added to the combo box. If
     * this method returns null then it will not be added to the combo box.
     *
     * @return a <code>KeyListener or null
     */
    protected KeyListener createKeyListener() {
        return null;
    }

    /**
     * Creates a list selection listener that watches for selection changes in
     * the popup's list.  If this method returns null then it will not
     * be added to the popup list.
     *
     * @return an instance of a <code>ListSelectionListener or null
     */
    protected ListSelectionListener createListSelectionListener() {
        return null;
    }

    /**
     * Creates a list data listener which will be added to the
     * <code>ComboBoxModel. If this method returns null then
     * it will not be added to the combo box model.
     *
     * @return an instance of a <code>ListDataListener or null
     */
    protected ListDataListener createListDataListener() {
        return null;
    }

    /**
     * Creates a mouse listener that watches for mouse events in
     * the popup's list. If this method returns null then it will
     * not be added to the combo box.
     *
     * @return an instance of a <code>MouseListener or null
     */
    protected MouseListener createListMouseListener() {
        return getHandler();
    }

    /**
     * Creates a mouse motion listener that watches for mouse motion
     * events in the popup's list. If this method returns null then it will
     * not be added to the combo box.
     *
     * @return an instance of a <code>MouseMotionListener or null
     */
    protected MouseMotionListener createListMouseMotionListener() {
        return getHandler();
    }

    /**
     * Creates a <code>PropertyChangeListener which will be added to
     * the combo box. If this method returns null then it will not
     * be added to the combo box.
     *
     * @return an instance of a <code>PropertyChangeListener or null
     */
    protected PropertyChangeListener createPropertyChangeListener() {
        return getHandler();
    }

    /**
     * Creates an <code>ItemListener which will be added to the
     * combo box. If this method returns null then it will not
     * be added to the combo box.
     * <p>
     * Subclasses may override this method to return instances of their own
     * ItemEvent handlers.
     *
     * @return an instance of an <code>ItemListener or null
     */
    protected ItemListener createItemListener() {
        return getHandler();
    }

    private Handler getHandler() {
        if (handler == null) {
            handler = new Handler();
        }
        return handler;
    }

    /**
     * Creates the JList used in the popup to display
     * the items in the combo box model. This method is called when the UI class
     * is created.
     *
     * @return a <code>JList used to display the combo box items
     */
    protected JList createList() {
        return new JList( comboBox.getModel() ) {
            public void processMouseEvent(MouseEvent e)  {
                if (BasicGraphicsUtils.isMenuShortcutKeyDown(e))  {
                    // Fix for 4234053. Filter out the Control Key from the list.
                    // ie., don't allow CTRL key deselection.
                    Toolkit toolkit = Toolkit.getDefaultToolkit();
                    e = new MouseEvent((Component)e.getSource(), e.getID(), e.getWhen(),
                                       e.getModifiers() ^ toolkit.getMenuShortcutKeyMask(),
                                       e.getX(), e.getY(),
                                       e.getXOnScreen(), e.getYOnScreen(),
                                       e.getClickCount(),
                                       e.isPopupTrigger(),
                                       MouseEvent.NOBUTTON);
                }
                super.processMouseEvent(e);
            }
        };
    }

    /**
     * Configures the list which is used to hold the combo box items in the
     * popup. This method is called when the UI class
     * is created.
     *
     * @see #createList
     */
    protected void configureList() {
        list.setFont( comboBox.getFont() );
        list.setForeground( comboBox.getForeground() );
        list.setBackground( comboBox.getBackground() );
        list.setSelectionForeground( UIManager.getColor( "ComboBox.selectionForeground" ) );
        list.setSelectionBackground( UIManager.getColor( "ComboBox.selectionBackground" ) );
        list.setBorder( null );
        list.setCellRenderer( comboBox.getRenderer() );
        list.setFocusable( false );
        list.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
        setListSelection( comboBox.getSelectedIndex() );
        installListListeners();
    }

    /**
     * Adds the listeners to the list control.
     */
    protected void installListListeners() {
        if ((listMouseListener = createListMouseListener()) != null) {
            list.addMouseListener( listMouseListener );
        }
        if ((listMouseMotionListener = createListMouseMotionListener()) != null) {
            list.addMouseMotionListener( listMouseMotionListener );
        }
        if ((listSelectionListener = createListSelectionListener()) != null) {
            list.addListSelectionListener( listSelectionListener );
        }
    }

    void uninstallListListeners() {
        if (listMouseListener != null) {
            list.removeMouseListener(listMouseListener);
            listMouseListener = null;
        }
        if (listMouseMotionListener != null) {
            list.removeMouseMotionListener(listMouseMotionListener);
            listMouseMotionListener = null;
        }
        if (listSelectionListener != null) {
            list.removeListSelectionListener(listSelectionListener);
            listSelectionListener = null;
        }
        handler = null;
    }

    /**
     * Creates the scroll pane which houses the scrollable list.
     */
    protected JScrollPane createScroller() {
        JScrollPane sp = new JScrollPane( list,
                                ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );
        sp.setHorizontalScrollBar(null);
        return sp;
    }

    /**
     * Configures the scrollable portion which holds the list within
     * the combo box popup. This method is called when the UI class
     * is created.
     */
    protected void configureScroller() {
        scroller.setFocusable( false );
        scroller.getVerticalScrollBar().setFocusable( false );
        scroller.setBorder( null );
    }

    /**
     * Configures the popup portion of the combo box. This method is called
     * when the UI class is created.
     */
    protected void configurePopup() {
        setLayout( new BoxLayout( this, BoxLayout.Y_AXIS ) );
        setBorderPainted( true );
        setBorder(LIST_BORDER);
        setOpaque( false );
        add( scroller );
        setDoubleBuffered( true );
        setFocusable( false );
    }

    /**
     * This method adds the necessary listeners to the JComboBox.
     */
    protected void installComboBoxListeners() {
        if ((propertyChangeListener = createPropertyChangeListener()) != null) {
            comboBox.addPropertyChangeListener(propertyChangeListener);
        }
        if ((itemListener = createItemListener()) != null) {
            comboBox.addItemListener(itemListener);
        }
        installComboBoxModelListeners(comboBox.getModel());
    }

    /**
     * Installs the listeners on the combo box model. Any listeners installed
     * on the combo box model should be removed in
     * <code>uninstallComboBoxModelListeners.
     *
     * @param model The combo box model to install listeners
     * @see #uninstallComboBoxModelListeners
     */
    protected void installComboBoxModelListeners( ComboBoxModel model ) {
        if (model != null && (listDataListener = createListDataListener()) != null) {
            model.addListDataListener(listDataListener);
        }
    }

    protected void installKeyboardActions() {

        /* XXX - shouldn't call this method. take it out for testing.
        ActionListener action = new ActionListener() {
            public void actionPerformed(ActionEvent e){
            }
        };

        comboBox.registerKeyboardAction( action,
                                         KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, 0 ),
                                         JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ); */

    }

    //
    // end Initialization routines
    //=================================================================


    //===================================================================
    // begin Event Listenters
    //

    /**
     * A listener to be registered upon the combo box
     * (<em>not its popup menu)
     * to handle mouse events
     * that affect the state of the popup menu.
     * The main purpose of this listener is to make the popup menu
     * appear and disappear.
     * This listener also helps
     * with click-and-drag scenarios by setting the selection if the mouse was
     * released over the list during a drag.
     *
     * <p>
     * <strong>Warning:
     * We recommend that you <em>not
     * create subclasses of this class.
     * If you absolutely must create a subclass,
     * be sure to invoke the superclass
     * version of each method.
     *
     * @see BasicComboPopup#createMouseListener
     */
    protected class InvocationMouseHandler extends MouseAdapter {
        /**
         * Responds to mouse-pressed events on the combo box.
         *
         * @param e the mouse-press event to be handled
         */
        public void mousePressed( MouseEvent e ) {
            getHandler().mousePressed(e);
        }

        /**
         * Responds to the user terminating
         * a click or drag that began on the combo box.
         *
         * @param e the mouse-release event to be handled
         */
        public void mouseReleased( MouseEvent e ) {
            getHandler().mouseReleased(e);
        }
    }

    /**
     * This listener watches for dragging and updates the current selection in the
     * list if it is dragging over the list.
     */
    protected class InvocationMouseMotionHandler extends MouseMotionAdapter {
        public void mouseDragged( MouseEvent e ) {
            getHandler().mouseDragged(e);
        }
    }

    /**
     * As of Java 2 platform v 1.4, this class is now obsolete and is only included for
     * backwards API compatibility. Do not instantiate or subclass.
     * <p>
     * All the functionality of this class has been included in
     * BasicComboBoxUI ActionMap/InputMap methods.
     */
    public class InvocationKeyHandler extends KeyAdapter {
        public void keyReleased( KeyEvent e ) {}
    }

    /**
     * As of Java 2 platform v 1.4, this class is now obsolete, doesn't do anything, and
     * is only included for backwards API compatibility. Do not call or
     * override.
     */
    protected class ListSelectionHandler implements ListSelectionListener {
        public void valueChanged( ListSelectionEvent e ) {}
    }

    /**
     * As of 1.4, this class is now obsolete, doesn't do anything, and
     * is only included for backwards API compatibility. Do not call or
     * override.
     * <p>
     * The functionality has been migrated into <code>ItemHandler.
     *
     * @see #createItemListener
     */
    public class ListDataHandler implements ListDataListener {
        public void contentsChanged( ListDataEvent e ) {}

        public void intervalAdded( ListDataEvent e ) {
        }

        public void intervalRemoved( ListDataEvent e ) {
        }
    }

    /**
     * This listener hides the popup when the mouse is released in the list.
     */
    protected class ListMouseHandler extends MouseAdapter {
        public void mousePressed( MouseEvent e ) {
        }
        public void mouseReleased(MouseEvent anEvent) {
            getHandler().mouseReleased(anEvent);
        }
    }

    /**
     * This listener changes the selected item as you move the mouse over the list.
     * The selection change is not committed to the model, this is for user feedback only.
     */
    protected class ListMouseMotionHandler extends MouseMotionAdapter {
        public void mouseMoved( MouseEvent anEvent ) {
            getHandler().mouseMoved(anEvent);
        }
    }

    /**
     * This listener watches for changes to the selection in the
     * combo box.
     */
    protected class ItemHandler implements ItemListener {
        public void itemStateChanged( ItemEvent e ) {
            getHandler().itemStateChanged(e);
        }
    }

    /**
     * This listener watches for bound properties that have changed in the
     * combo box.
     * <p>
     * Subclasses which wish to listen to combo box property changes should
     * call the superclass methods to ensure that the combo popup correctly
     * handles property changes.
     *
     * @see #createPropertyChangeListener
     */
    protected class PropertyChangeHandler implements PropertyChangeListener {
        public void propertyChange( PropertyChangeEvent e ) {
            getHandler().propertyChange(e);
        }
    }


    private class AutoScrollActionHandler implements ActionListener {
        private int direction;

        AutoScrollActionHandler(int direction) {
            this.direction = direction;
        }

        public void actionPerformed(ActionEvent e) {
            if (direction == SCROLL_UP) {
                autoScrollUp();
            }
            else {
                autoScrollDown();
            }
        }
    }


    private class Handler implements ItemListener, MouseListener,
                          MouseMotionListener, PropertyChangeListener,
                          Serializable {
        //
        // MouseListener
        // NOTE: this is added to both the JList and JComboBox
        //
        public void mouseClicked(MouseEvent e) {
        }

        public void mousePressed(MouseEvent e) {
            if (e.getSource() == list) {
                return;
            }
            if (!SwingUtilities.isLeftMouseButton(e) || !comboBox.isEnabled())
                return;

            if ( comboBox.isEditable() ) {
                Component comp = comboBox.getEditor().getEditorComponent();
                if ((!(comp instanceof JComponent)) || ((JComponent)comp).isRequestFocusEnabled()) {
                    comp.requestFocus();
                }
            }
            else if (comboBox.isRequestFocusEnabled()) {
                comboBox.requestFocus();
            }
            togglePopup();
        }

        public void mouseReleased(MouseEvent e) {
            if (e.getSource() == list) {
                if (list.getModel().getSize() > 0) {
                    // JList mouse listener
                    if (comboBox.getSelectedIndex() == list.getSelectedIndex()) {
                        comboBox.getEditor().setItem(list.getSelectedValue());
                    }
                    comboBox.setSelectedIndex(list.getSelectedIndex());
                }
                comboBox.setPopupVisible(false);
                // workaround for cancelling an edited item (bug 4530953)
                if (comboBox.isEditable() && comboBox.getEditor() != null) {
                    comboBox.configureEditor(comboBox.getEditor(),
                                             comboBox.getSelectedItem());
                }
                return;
            }
            // JComboBox mouse listener
            Component source = (Component)e.getSource();
            Dimension size = source.getSize();
            Rectangle bounds = new Rectangle( 0, 0, size.width - 1, size.height - 1 );
            if ( !bounds.contains( e.getPoint() ) ) {
                MouseEvent newEvent = convertMouseEvent( e );
                Point location = newEvent.getPoint();
                Rectangle r = new Rectangle();
                list.computeVisibleRect( r );
                if ( r.contains( location ) ) {
                    if (comboBox.getSelectedIndex() == list.getSelectedIndex()) {
                        comboBox.getEditor().setItem(list.getSelectedValue());
                    }
                    comboBox.setSelectedIndex(list.getSelectedIndex());
                }
                comboBox.setPopupVisible(false);
            }
            hasEntered = false;
            stopAutoScrolling();
        }

        public void mouseEntered(MouseEvent e) {
        }

        public void mouseExited(MouseEvent e) {
        }

        //
        // MouseMotionListener:
        // NOTE: this is added to both the List and ComboBox
        //
        public void mouseMoved(MouseEvent anEvent) {
            if (anEvent.getSource() == list) {
                Point location = anEvent.getPoint();
                Rectangle r = new Rectangle();
                list.computeVisibleRect( r );
                if ( r.contains( location ) ) {
                    updateListBoxSelectionForEvent( anEvent, false );
                }
            }
        }

        public void mouseDragged( MouseEvent e ) {
            if (e.getSource() == list) {
                return;
            }
            if ( isVisible() ) {
                MouseEvent newEvent = convertMouseEvent( e );
                Rectangle r = new Rectangle();
                list.computeVisibleRect( r );

                if ( newEvent.getPoint().y >= r.y && newEvent.getPoint().y <= r.y + r.height - 1 ) {
                    hasEntered = true;
                    if ( isAutoScrolling ) {
                        stopAutoScrolling();
                    }
                    Point location = newEvent.getPoint();
                    if ( r.contains( location ) ) {
                        updateListBoxSelectionForEvent( newEvent, false );
                    }
                }
                else {
                    if ( hasEntered ) {
                        int directionToScroll = newEvent.getPoint().y < r.y ? SCROLL_UP : SCROLL_DOWN;
                        if ( isAutoScrolling && scrollDirection != directionToScroll ) {
                            stopAutoScrolling();
                            startAutoScrolling( directionToScroll );
                        }
                        else if ( !isAutoScrolling ) {
                            startAutoScrolling( directionToScroll );
                        }
                    }
                    else {
                        if ( e.getPoint().y < 0 ) {
                            hasEntered = true;
                            startAutoScrolling( SCROLL_UP );
                        }
                    }
                }
            }
        }

        //
        // PropertyChangeListener
        //
        public void propertyChange(PropertyChangeEvent e) {
            JComboBox comboBox = (JComboBox)e.getSource();
            String propertyName = e.getPropertyName();

            if ( propertyName == "model" ) {
                ComboBoxModel oldModel = (ComboBoxModel)e.getOldValue();
                ComboBoxModel newModel = (ComboBoxModel)e.getNewValue();
                uninstallComboBoxModelListeners(oldModel);
                installComboBoxModelListeners(newModel);

                list.setModel(newModel);

                if ( isVisible() ) {
                    hide();
                }
            }
            else if ( propertyName == "renderer" ) {
                list.setCellRenderer( comboBox.getRenderer() );
                if ( isVisible() ) {
                    hide();
                }
            }
            else if (propertyName == "componentOrientation") {
                // Pass along the new component orientation
                // to the list and the scroller

                ComponentOrientation o =(ComponentOrientation)e.getNewValue();

                JList list = getList();
                if (list!=null && list.getComponentOrientation()!=o) {
                    list.setComponentOrientation(o);
                }

                if (scroller!=null && scroller.getComponentOrientation()!=o) {
                    scroller.setComponentOrientation(o);
                }

                if (o!=getComponentOrientation()) {
                    setComponentOrientation(o);
                }
            }
            else if (propertyName == "lightWeightPopupEnabled") {
                setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled());
            }
        }

        //
        // ItemListener
        //
        public void itemStateChanged( ItemEvent e ) {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                JComboBox comboBox = (JComboBox)e.getSource();
                setListSelection(comboBox.getSelectedIndex());
            }
        }
    }

    //
    // end Event Listeners
    //=================================================================


    /**
     * Overridden to unconditionally return false.
     */
    public boolean isFocusTraversable() {
        return false;
    }

    //===================================================================
    // begin Autoscroll methods
    //

    /**
     * This protected method is implementation specific and should be private.
     * do not call or override.
     */
    protected void startAutoScrolling( int direction ) {
        // XXX - should be a private method within InvocationMouseMotionHandler
        // if possible.
        if ( isAutoScrolling ) {
            autoscrollTimer.stop();
        }

        isAutoScrolling = true;

        if ( direction == SCROLL_UP ) {
            scrollDirection = SCROLL_UP;
            Point convertedPoint = SwingUtilities.convertPoint( scroller, new Point( 1, 1 ), list );
            int top = list.locationToIndex( convertedPoint );
            list.setSelectedIndex( top );

            autoscrollTimer = new Timer( 100, new AutoScrollActionHandler(
                                             SCROLL_UP) );
        }
        else if ( direction == SCROLL_DOWN ) {
            scrollDirection = SCROLL_DOWN;
            Dimension size = scroller.getSize();
            Point convertedPoint = SwingUtilities.convertPoint( scroller,
                                                                new Point( 1, (size.height - 1) - 2 ),
                                                                list );
            int bottom = list.locationToIndex( convertedPoint );
            list.setSelectedIndex( bottom );

            autoscrollTimer = new Timer(100, new AutoScrollActionHandler(
                                            SCROLL_DOWN));
        }
        autoscrollTimer.start();
    }

    /**
     * This protected method is implementation specific and should be private.
     * do not call or override.
     */
    protected void stopAutoScrolling() {
        isAutoScrolling = false;

        if ( autoscrollTimer != null ) {
            autoscrollTimer.stop();
            autoscrollTimer = null;
        }
    }

    /**
     * This protected method is implementation specific and should be private.
     * do not call or override.
     */
    protected void autoScrollUp() {
        int index = list.getSelectedIndex();
        if ( index > 0 ) {
            list.setSelectedIndex( index - 1 );
            list.ensureIndexIsVisible( index - 1 );
        }
    }

    /**
     * This protected method is implementation specific and should be private.
     * do not call or override.
     */
    protected void autoScrollDown() {
        int index = list.getSelectedIndex();
        int lastItem = list.getModel().getSize() - 1;
        if ( index < lastItem ) {
            list.setSelectedIndex( index + 1 );
            list.ensureIndexIsVisible( index + 1 );
        }
    }

    //
    // end Autoscroll methods
    //=================================================================


    //===================================================================
    // begin Utility methods
    //

    /**
     * Gets the AccessibleContext associated with this BasicComboPopup.
     * The AccessibleContext will have its parent set to the ComboBox.
     *
     * @return an AccessibleContext for the BasicComboPopup
     * @since 1.5
     */
    public AccessibleContext getAccessibleContext() {
        AccessibleContext context = super.getAccessibleContext();
        context.setAccessibleParent(comboBox);
        return context;
    }


    /**
     * This is is a utility method that helps event handlers figure out where to
     * send the focus when the popup is brought up.  The standard implementation
     * delegates the focus to the editor (if the combo box is editable) or to
     * the JComboBox if it is not editable.
     */
    protected void delegateFocus( MouseEvent e ) {
        if ( comboBox.isEditable() ) {
            Component comp = comboBox.getEditor().getEditorComponent();
            if ((!(comp instanceof JComponent)) || ((JComponent)comp).isRequestFocusEnabled()) {
                comp.requestFocus();
            }
        }
        else if (comboBox.isRequestFocusEnabled()) {
            comboBox.requestFocus();
        }
    }

    /**
     * Makes the popup visible if it is hidden and makes it hidden if it is
     * visible.
     */
    protected void togglePopup() {
        if ( isVisible() ) {
            hide();
        }
        else {
            show();
        }
    }

    /**
     * Sets the list selection index to the selectedIndex. This
     * method is used to synchronize the list selection with the
     * combo box selection.
     *
     * @param selectedIndex the index to set the list
     */
    private void setListSelection(int selectedIndex) {
        if ( selectedIndex == -1 ) {
            list.clearSelection();
        }
        else {
            list.setSelectedIndex( selectedIndex );
            list.ensureIndexIsVisible( selectedIndex );
        }
    }

    protected MouseEvent convertMouseEvent( MouseEvent e ) {
        Point convertedPoint = SwingUtilities.convertPoint( (Component)e.getSource(),
                                                            e.getPoint(), list );
        MouseEvent newEvent = new MouseEvent( (Component)e.getSource(),
                                              e.getID(),
                                              e.getWhen(),
                                              e.getModifiers(),
                                              convertedPoint.x,
                                              convertedPoint.y,
                                              e.getXOnScreen(),
                                              e.getYOnScreen(),
                                              e.getClickCount(),
                                              e.isPopupTrigger(),
                                              MouseEvent.NOBUTTON );
        return newEvent;
    }


    /**
     * Retrieves the height of the popup based on the current
     * ListCellRenderer and the maximum row count.
     */
    protected int getPopupHeightForRowCount(int maxRowCount) {
        // Set the cached value of the minimum row count
        int minRowCount = Math.min( maxRowCount, comboBox.getItemCount() );
        int height = 0;
        ListCellRenderer renderer = list.getCellRenderer();
        Object value = null;

        for ( int i = 0; i < minRowCount; ++i ) {
            value = list.getModel().getElementAt( i );
            Component c = renderer.getListCellRendererComponent( list, value, i, false, false );
            height += c.getPreferredSize().height;
        }

        if (height == 0) {
            height = comboBox.getHeight();
        }

        Border border = scroller.getViewportBorder();
        if (border != null) {
            Insets insets = border.getBorderInsets(null);
            height += insets.top + insets.bottom;
        }

        border = scroller.getBorder();
        if (border != null) {
            Insets insets = border.getBorderInsets(null);
            height += insets.top + insets.bottom;
        }

        return height;
    }

    /**
     * Calculate the placement and size of the popup portion of the combo box based
     * on the combo box location and the enclosing screen bounds. If
     * no transformations are required, then the returned rectangle will
     * have the same values as the parameters.
     *
     * @param px starting x location
     * @param py starting y location
     * @param pw starting width
     * @param ph starting height
     * @return a rectangle which represents the placement and size of the popup
     */
    protected Rectangle computePopupBounds(int px,int py,int pw,int ph) {
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Rectangle screenBounds;

        // Calculate the desktop dimensions relative to the combo box.
        GraphicsConfiguration gc = comboBox.getGraphicsConfiguration();
        Point p = new Point();
        SwingUtilities.convertPointFromScreen(p, comboBox);
        if (gc != null) {
            Insets screenInsets = toolkit.getScreenInsets(gc);
            screenBounds = gc.getBounds();
            screenBounds.width -= (screenInsets.left + screenInsets.right);
            screenBounds.height -= (screenInsets.top + screenInsets.bottom);
            screenBounds.x += (p.x + screenInsets.left);
            screenBounds.y += (p.y + screenInsets.top);
        }
        else {
            screenBounds = new Rectangle(p, toolkit.getScreenSize());
        }

        Rectangle rect = new Rectangle(px,py,pw,ph);
        if (py+ph > screenBounds.y+screenBounds.height
            && ph < screenBounds.height) {
            rect.y = -rect.height;
        }
        return rect;
    }

    /**
     * Calculates the upper left location of the Popup.
     */
    private Point getPopupLocation() {
        Dimension popupSize = comboBox.getSize();
        Insets insets = getInsets();

        // reduce the width of the scrollpane by the insets so that the popup
        // is the same width as the combo box.
        popupSize.setSize(popupSize.width - (insets.right + insets.left),
                          getPopupHeightForRowCount( comboBox.getMaximumRowCount()));
        Rectangle popupBounds = computePopupBounds( 0, comboBox.getBounds().height,
                                                    popupSize.width, popupSize.height);
        Dimension scrollSize = popupBounds.getSize();
        Point popupLocation = popupBounds.getLocation();

        scroller.setMaximumSize( scrollSize );
        scroller.setPreferredSize( scrollSize );
        scroller.setMinimumSize( scrollSize );

        list.revalidate();

        return popupLocation;
    }

    /**
     * A utility method used by the event listeners.  Given a mouse event, it changes
     * the list selection to the list item below the mouse.
     */
    protected void updateListBoxSelectionForEvent(MouseEvent anEvent,boolean shouldScroll) {
        // XXX - only seems to be called from this class. shouldScroll flag is
        // never true
        Point location = anEvent.getPoint();
        if ( list == null )
            return;
        int index = list.locationToIndex(location);
        if ( index == -1 ) {
            if ( location.y < 0 )
                index = 0;
            else
                index = comboBox.getModel().getSize() - 1;
        }
        if ( list.getSelectedIndex() != index ) {
            list.setSelectedIndex(index);
            if ( shouldScroll )
                list.ensureIndexIsVisible(index);
        }
    }

    //
    // end Utility methods
    //=================================================================
}

Other Java examples (source code examples)

Here is a short list of links related to this Java BasicComboPopup.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.