/*
* Copyright (c) 1998, 2006, 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 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 JavaBeansTM
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<sup><font size="-2">TM</font></sup>
* has been added to the <code>java.beans</code> 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,
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 Also: - getList
- createList
/**
* 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 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: - getMouseMotionListener
- createMouseMotionListener
/**
* 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: - getMouseListener
- createMouseListener
/**
* 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: - getKeyListener
- createKeyListener
/**
* 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;
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;
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().
/**
* Implementation of ComboPopup.show().
*/
public void show() {
setListSelection(comboBox.getSelectedIndex());
Point location = getPopupLocation();
show( comboBox, location.x, location.y );
}
Implementation of ComboPopup.hide().
/**
* 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().
/**
* Implementation of ComboPopup.getList().
*/
public JList 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();
// 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);
}
}
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();
}
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.
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 createList() {
return new JList( comboBox.getModel() ) {
public void processMouseEvent(MouseEvent e) {
if (e.isControlDown()) {
// Fix for 4234053. Filter out the Control Key from the list.
// ie., don't allow CTRL key deselection.
e = new MouseEvent((Component)e.getSource(), e.getID(), e.getWhen(),
e.getModifiers() ^ InputEvent.CTRL_MASK,
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 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.
/**
* 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.
/**
* 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.
/**
* 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.
/**
* 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);
}
}
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, 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.setSelectedIndex( list.getSelectedIndex() );
} else {
comboBox.getEditor().setItem( list.getSelectedValue() );
}
}
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.setSelectedIndex( list.getSelectedIndex() );
} else {
comboBox.getEditor().setItem( list.getSelectedValue() );
}
}
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.
/**
* 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.
/**
* 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.
/**
* 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 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.
/**
* 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.
/**
* 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 );
}
}
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.
/**
* 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.
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());
}
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.
/**
* 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.
/**
* 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
//=================================================================
}