/*
 * Copyright (c) 1998, 2016, 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;

import sun.awt.AWTAccessor;
import sun.awt.AWTAccessor.MouseEventAccessor;

This is a basic implementation of the ComboPopup interface. This class represents the ui for the popup portion of the combo box.

All event handling is handled by listener classes created with the createxxxListener() methods and internal classes. You can change the behavior of this class by overriding the createxxxListener() methods and supplying your own event listeners or subclassing from the ones supplied in this class.

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 java.beans package. Please see XMLEncoder.

Author:Tom Santos, Mark Davidson
/** * This is a basic implementation of the <code>ComboPopup</code> 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()</code> methods and internal classes. * You can change the behavior of this class by overriding the * <code>createxxxListener()</code> methods and supplying your own * event listeners or subclassing from the ones supplied in this class. * <p> * <strong>Warning:</strong> * 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&trade; * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @author Tom Santos * @author Mark Davidson */
@SuppressWarnings("serial") // Same-version serialization only 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<Object> EmptyListModel = new EmptyListModelClass(); private static Border LIST_BORDER = new LineBorder(Color.BLACK, 1);
The instance of JComboBox.
/** * The instance of {@code JComboBox}. */
protected JComboBox<Object> comboBox;
This protected field is implementation specific. Do not access directly or override. Use the accessor methods instead.
See Also:
/** * This protected field is implementation specific. Do not access directly * or override. Use the accessor methods instead. * * @see #getList * @see #createList */
protected JList<Object> list;
This protected field is implementation specific. Do not access directly or override. Use the create method instead
See Also:
  • createScroller
/** * 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.
/** * 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.
/** * 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 Also:
/** * 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 Also:
/** * 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 Also:
/** * 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 Also:
  • createListSelectionListener
/** * 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 Also:
  • createListMouseListener
/** * 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 Also:
  • createListMouseMotionListener
/** * 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 Also:
  • createPropertyChangeListener
/** * 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 Also:
  • createListDataListener
/** * 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 Also:
  • createItemListener
/** * This protected field is implementation specific. Do not access directly * or override. Use the create method instead * * @see #createItemListener */
protected ItemListener itemListener; private MouseWheelListener scrollerMouseWheelListener;
This protected field is implementation specific. Do not access directly or override.
/** * This protected field is implementation specific. Do not access directly * or override. */
protected Timer autoscrollTimer;
true if the mouse cursor is in the popup.
/** * {@code true} if the mouse cursor is in the popup. */
protected boolean hasEntered = false;
If true the auto-scrolling is enabled.
/** * If {@code true} the auto-scrolling is enabled. */
protected boolean isAutoScrolling = false;
The direction of scrolling.
/** * The direction of scrolling. */
protected int scrollDirection = SCROLL_UP;
The direction of scrolling up.
/** * The direction of scrolling up. */
protected static final int SCROLL_UP = 0;
The direction of scrolling down.
/** * The direction of scrolling down. */
protected static final int SCROLL_DOWN = 1; //======================================== // begin ComboPopup method implementations //
Implementation of ComboPopup.show().
/** * Implementation of ComboPopup.show(). */
@SuppressWarnings("deprecation") public void show() { comboBox.firePopupMenuWillBecomeVisible(); setListSelection(comboBox.getSelectedIndex()); Point location = getPopupLocation(); show( comboBox, location.x, location.y ); }
Implementation of ComboPopup.hide().
/** * Implementation of ComboPopup.hide(). */
@SuppressWarnings("deprecation") 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().
/** * Implementation of ComboPopup.getList(). */
public JList<Object> getList() { return list; }
Implementation of ComboPopup.getMouseListener().
See Also:
Returns:a MouseListener or null
/** * Implementation of ComboPopup.getMouseListener(). * * @return a <code>MouseListener</code> or null * @see ComboPopup#getMouseListener */
public MouseListener getMouseListener() { if (mouseListener == null) { mouseListener = createMouseListener(); } return mouseListener; }
Implementation of ComboPopup.getMouseMotionListener().
See Also:
Returns:a MouseMotionListener or null
/** * Implementation of ComboPopup.getMouseMotionListener(). * * @return a <code>MouseMotionListener</code> or null * @see ComboPopup#getMouseMotionListener */
public MouseMotionListener getMouseMotionListener() { if (mouseMotionListener == null) { mouseMotionListener = createMouseMotionListener(); } return mouseMotionListener; }
Implementation of ComboPopup.getKeyListener().
See Also:
Returns:a KeyListener or null
/** * Implementation of ComboPopup.getKeyListener(). * * @return a <code>KeyListener</code> 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().
/** * 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(); uninstallScrollerListeners(); // 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
Params:
  • model – The combo box model to install listeners
See Also:
/** * 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); } }
Unregisters keyboard actions.
/** * Unregisters keyboard actions. */
protected void uninstallKeyboardActions() { // XXX - shouldn't call this method // comboBox.unregisterKeyboardAction( KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, 0 ) ); } //=================================================================== // begin Initialization routines //
Constructs a new instance of BasicComboPopup.
Params:
  • combo – an instance of JComboBox
/** * Constructs a new instance of {@code BasicComboPopup}. * * @param combo an instance of {@code JComboBox} */
public BasicComboPopup( JComboBox<Object> 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() { if (scrollerMouseWheelListener != null) { comboBox.addMouseWheelListener(scrollerMouseWheelListener); } 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() { if (scrollerMouseWheelListener != null) { comboBox.removeMouseWheelListener(scrollerMouseWheelListener); } super.firePopupMenuWillBecomeInvisible(); comboBox.firePopupMenuWillBecomeInvisible(); } protected void firePopupMenuCanceled() { if (scrollerMouseWheelListener != null) { comboBox.removeMouseWheelListener(scrollerMouseWheelListener); } super.firePopupMenuCanceled(); comboBox.firePopupMenuCanceled(); }
Creates a listener that will watch for mouse-press and release events on the combo box. Warning: When overriding this method, make sure to maintain the existing behavior.
Returns:a MouseListener which will be added to the combo box or null
/** * Creates a listener * that will watch for mouse-press and release events on the combo box. * * <strong>Warning:</strong> * When overriding this method, make sure to maintain the existing * behavior. * * @return a <code>MouseListener</code> 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. Warning: When overriding this method, make sure to maintain the existing behavior.
Returns:a MouseMotionListener which will be added to the combo box or null
/** * Creates the mouse motion listener which will be added to the combo * box. * * <strong>Warning:</strong> * When overriding this method, make sure to maintain the existing * behavior. * * @return a <code>MouseMotionListener</code> 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.
Returns:a KeyListener or null
/** * 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</code> 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.
Returns:an instance of a ListSelectionListener or 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</code> or null */
protected ListSelectionListener createListSelectionListener() { return null; }
Creates a list data listener which will be added to the ComboBoxModel. If this method returns null then it will not be added to the combo box model.
Returns:an instance of a ListDataListener or null
/** * Creates a list data listener which will be added to the * <code>ComboBoxModel</code>. If this method returns null then * it will not be added to the combo box model. * * @return an instance of a <code>ListDataListener</code> 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.
Returns:an instance of a MouseListener or 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</code> 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.
Returns:an instance of a MouseMotionListener or null
/** * 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</code> or null */
protected MouseMotionListener createListMouseMotionListener() { return getHandler(); }
Creates a PropertyChangeListener which will be added to the combo box. If this method returns null then it will not be added to the combo box.
Returns:an instance of a PropertyChangeListener or null
/** * Creates a <code>PropertyChangeListener</code> 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</code> or null */
protected PropertyChangeListener createPropertyChangeListener() { return getHandler(); }
Creates an ItemListener which will be added to the combo box. If this method returns null then it will not be added to the combo box.

Subclasses may override this method to return instances of their own ItemEvent handlers.

Returns:an instance of an ItemListener or null
/** * Creates an <code>ItemListener</code> 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</code> 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.
Returns:a JList used to display the combo box items
/** * 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</code> used to display the combo box items */
protected JList<Object> createList() { return new JList<Object>( 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(); MouseEvent newEvent = new MouseEvent( (Component)e.getSource(), e.getID(), e.getWhen(), e.getModifiersEx() ^ toolkit.getMenuShortcutKeyMaskEx(), e.getX(), e.getY(), e.getXOnScreen(), e.getYOnScreen(), e.getClickCount(), e.isPopupTrigger(), MouseEvent.NOBUTTON); MouseEventAccessor meAccessor = AWTAccessor.getMouseEventAccessor(); meAccessor.setCausedByTouchEvent(newEvent, meAccessor.isCausedByTouchEvent(e)); e = newEvent; } 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 Also:
  • createList
/** * 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.
/** * 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.
Returns:the scroll pane which houses the scrollable list
/** * Creates the scroll pane which houses the scrollable list. * * @return 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.
/** * 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 ); installScrollerListeners(); }
Configures the popup portion of the combo box. This method is called when the UI class is created.
/** * 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 ); } private void installScrollerListeners() { scrollerMouseWheelListener = getHandler(); if (scrollerMouseWheelListener != null) { scroller.addMouseWheelListener(scrollerMouseWheelListener); } } private void uninstallScrollerListeners() { if (scrollerMouseWheelListener != null) { scroller.removeMouseWheelListener(scrollerMouseWheelListener); scrollerMouseWheelListener = null; } }
This method adds the necessary listeners to the JComboBox.
/** * 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 uninstallComboBoxModelListeners.
Params:
  • model – The combo box model to install listeners
See Also:
/** * Installs the listeners on the combo box model. Any listeners installed * on the combo box model should be removed in * <code>uninstallComboBoxModelListeners</code>. * * @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); } }
Registers keyboard actions.
/** * Registers keyboard actions. */
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 (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.

Warning: We recommend that you not create subclasses of this class. If you absolutely must create a subclass, be sure to invoke the superclass version of each method.

See Also:
  • createMouseListener.createMouseListener
/** * A listener to be registered upon the combo box * (<em>not</em> 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:</strong> * We recommend that you <em>not</em> * 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.
Params:
  • e – the mouse-press event to be handled
/** * 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.
Params:
  • e – the mouse-release event to be handled
/** * 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.
/** * 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.

All the functionality of this class has been included in BasicComboBoxUI ActionMap/InputMap methods.

/** * 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.
/** * 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.

The functionality has been migrated into ItemHandler.

See Also:
  • createItemListener
/** * 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</code>. * * @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.
/** * 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.
/** * 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.
/** * 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.

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 Also:
  • createPropertyChangeListener
/** * 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, MouseWheelListener, 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, size.height); 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) { @SuppressWarnings("unchecked") JComboBox<Object> comboBox = (JComboBox)e.getSource(); String propertyName = e.getPropertyName(); if ( propertyName == "model" ) { @SuppressWarnings("unchecked") ComboBoxModel<Object> oldModel = (ComboBoxModel)e.getOldValue(); @SuppressWarnings("unchecked") ComboBoxModel<Object> 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) { @SuppressWarnings("unchecked") JComboBox<Object> comboBox = (JComboBox)e.getSource(); setListSelection(comboBox.getSelectedIndex()); } else { setListSelection(-1); } } // // MouseWheelListener // public void mouseWheelMoved(MouseWheelEvent e) { e.consume(); } } // // end Event Listeners //=================================================================
Overridden to unconditionally return false.
/** * Overridden to unconditionally return false. */
@SuppressWarnings("deprecation") public boolean isFocusTraversable() { return false; } //=================================================================== // begin Autoscroll methods //
This protected method is implementation specific and should be private. do not call or override.
Params:
  • direction – the direction of scrolling
/** * This protected method is implementation specific and should be private. * do not call or override. * * @param direction the direction of scrolling */
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.
/** * 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.
/** * 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.
/** * 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.
Returns:an AccessibleContext for the BasicComboPopup
Since:1.5
/** * 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 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.
Params:
  • e – a mouse event
/** * This 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. * * @param e a mouse event */
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.
/** * 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.
Params:
  • selectedIndex – the index to set the list
/** * 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 ); } }
Converts mouse event.
Params:
  • e – a mouse event
Returns:converted mouse event
/** * Converts mouse event. * * @param e a mouse event * @return converted mouse event */
protected MouseEvent convertMouseEvent( MouseEvent e ) { Point convertedPoint = SwingUtilities.convertPoint( (Component)e.getSource(), e.getPoint(), list ); @SuppressWarnings("deprecation") 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 ); MouseEventAccessor meAccessor = AWTAccessor.getMouseEventAccessor(); meAccessor.setCausedByTouchEvent(newEvent, meAccessor.isCausedByTouchEvent(e)); return newEvent; }
Retrieves the height of the popup based on the current ListCellRenderer and the maximum row count.
Params:
  • maxRowCount – the row count
Returns:the height of the popup
/** * Retrieves the height of the popup based on the current * ListCellRenderer and the maximum row count. * * @param maxRowCount the row count * @return the height of the popup */
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<Object> 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.
Params:
  • px – starting x location
  • py – starting y location
  • pw – starting width
  • ph – starting height
Returns:a rectangle which represents the placement and size of the popup
/** * 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()); } int borderHeight = 0; Border popupBorder = getBorder(); if (popupBorder != null) { Insets borderInsets = popupBorder.getBorderInsets(this); borderHeight = borderInsets.top + borderInsets.bottom; screenBounds.width -= (borderInsets.left + borderInsets.right); screenBounds.height -= borderHeight; } Rectangle rect = new Rectangle(px, py, pw, ph); if (py + ph > screenBounds.y + screenBounds.height) { if (ph <= -screenBounds.y - borderHeight) { // popup goes above rect.y = -ph - borderHeight; } else { // a full screen height popup rect.y = screenBounds.y + Math.max(0, (screenBounds.height - ph) / 2 ); rect.height = Math.min(screenBounds.height, ph); } } return rect; }
Calculates the upper left location of the Popup.
/** * 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.
Params:
  • anEvent – a mouse event
  • shouldScroll – if true list should be scrolled.
/** * A utility method used by the event listeners. Given a mouse event, it changes * the list selection to the list item below the mouse. * * @param anEvent a mouse event * @param shouldScroll if {@code true} list should be scrolled. */
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 //================================================================= }