BasicComboBoxUI.java revision 0
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * This code is free software; you can redistribute it and/or modify it
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * under the terms of the GNU General Public License version 2 only, as
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * published by the Free Software Foundation. Sun designates this
5c65eaa08f2ec993a19c9bef6e5463918e40e0ebvboxsync * particular file as subject to the "Classpath" exception as provided
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * by Sun in the LICENSE file that accompanied this code.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * This code is distributed in the hope that it will be useful, but WITHOUT
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * version 2 for more details (a copy is included in the LICENSE file that
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * accompanied this code).
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * You should have received a copy of the GNU General Public License version
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * 2 along with this work; if not, write to the Free Software Foundation,
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * CA 95054 USA or visit www.sun.com if you need additional information or
c1b76913eb226361b0f57efd4dc45072db194218vboxsync * have any questions.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * Basic UI implementation for JComboBox.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * The combo box is a compound component which means that it is an agregate of
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * many simpler components. This class creates and manages the listeners
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * on the combo box and the combo box model. These listeners update the user
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * interface in response to changes in the properties and state of the combo box.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * All event handling is handled by listener classes created with the
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * <code>createxxxListener()</code> methods and internal classes.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * You can change the behavior of this class by overriding the
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * <code>createxxxListener()</code> methods and supplying your own
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * event listeners or subclassing from the ones supplied in this class.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * For adding specific actions,
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * overide <code>installKeyboardActions</code> to add actions in response to
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * KeyStroke bindings. See the article <a href="http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html">Keyboard Bindings in Swing</a>
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * at <a href="http://java.sun.com/products/jfc/tsc"><em>The Swing Connection</em></a>.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * @author Arnaud Weber
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * @author Tom Santos
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * @author Mark Davidson
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * This protected field is implementation specific. Do not access directly
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * or override.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync protected boolean hasFocus = false;
783c5efe04be621d9edbe07f2a41ea9a9a35cdcevboxsync // Control the selection behavior of the JComboBox when it is used
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // in the JTable DefaultCellEditor.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync private boolean isTableCellEditor = false;
058e9c6d97c5306126f83d934148c658804f1d6cvboxsync private static final String IS_TABLE_CELL_EDITOR = "JComboBox.isTableCellEditor";
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // This list is for drawing the current item in the combo box.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // Used to render the currently selected item in the combo box.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // It doesn't have anything to do with the popup's rendering.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync protected CellRendererPane currentValuePane = new CellRendererPane();
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // The implementation of ComboPopup that is used to show the popup.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // The Component that the ComboBoxEditor uses for editing
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // The arrow button that invokes the popup.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // Listeners that are attached to the JComboBox
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * This protected field is implementation specific. Do not access directly
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * or override. Override the listener construction method instead.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * @see #createKeyListener
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * This protected field is implementation specific. Do not access directly
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * or override. Override the listener construction method instead.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * @see #createFocusListener
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * This protected field is implementation specific. Do not access directly
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * or override. Override the listener construction method instead.
e66c95fa9950a4d9c567db63a4a495bf086cc4bfvboxsync * @see #createPropertyChangeListener
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync protected PropertyChangeListener propertyChangeListener;
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * This protected field is implementation specific. Do not access directly
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * or override. Override the listener construction method instead.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * @see #createItemListener
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // Listeners that the ComboPopup produces.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync protected MouseMotionListener popupMouseMotionListener;
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // This is used for knowing when to cache the minimum preferred size.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // If the data in the list changes, the cached value get marked for recalc.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // Added to the current JComboBox model
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * This protected field is implementation specific. Do not access directly
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * or override. Override the listener construction method instead.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * @see #createListDataListener
caa5882cb44c59f9b72347f4d901200b1f62fe61vboxsync * Implements all the Listeners needed by this class, all existing
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * listeners redirect to it.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * The time factor to treate the series of typed alphanumeric key
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * as prefix for first letter navigation.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * This is tricky, this variables is needed for DefaultKeySelectionManager
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * to take into account time factor.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * The default key selection manager
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // Flag for recalculating the minimum preferred size.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync protected boolean isMinimumSizeDirty = true;
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // Cached minimum preferred size.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync protected Dimension cachedMinimumSize = new Dimension( 0, 0 );
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // Flag for calculating the display size
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync private boolean isDisplaySizeDirty = true;
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // Cached the size that the display needs to render the largest item
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync private Dimension cachedDisplaySize = new Dimension( 0, 0 );
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // Key used for lookup of the DefaultListCellRenderer in the AppContext.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync private static final Object COMBO_UI_LIST_CELL_RENDERER_KEY =
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync * Whether or not all cells have the same baseline.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync private boolean sameBaseline;
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync // Used for calculating the default size.
783c5efe04be621d9edbe07f2a41ea9a9a35cdcevboxsync private static ListCellRenderer getDefaultListCellRenderer() {
7ed65a06413ef515a03e0d97f51b70d7a9c0a243vboxsync ListCellRenderer renderer = (ListCellRenderer)AppContext.
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync getAppContext().get(COMBO_UI_LIST_CELL_RENDERER_KEY);
41a839133aad7c96a0d55d927dc3475d0cbe9c22vboxsync AppContext.getAppContext().put(COMBO_UI_LIST_CELL_RENDERER_KEY,
new DefaultListCellRenderer());
return renderer;
return new BasicComboBoxUI();
isMinimumSizeDirty = true;
protected void installDefaults() {
protected void installListeners() {
protected void uninstallDefaults() {
protected void uninstallListeners() {
return getHandler();
return getHandler();
return getHandler();
return null;
return getHandler();
return getHandler();
return handler;
private void updateToolTipTextForChildren() {
protected void installComponents() {
addEditor();
protected void uninstallComponents() {
public void addEditor() {
removeEditor();
public void removeEditor() {
protected void configureEditor() {
protected void unconfigureEditor() {
public void configureArrowButton() {
public void unconfigureArrowButton() {
return button;
return getMinimumSize(c);
if ( !isMinimumSizeDirty ) {
isMinimumSizeDirty = false;
if (sameBaseline) {
return baseline;
JComponent c) {
super.getBaselineResizeBehavior(c);
else if (sameBaseline) {
return null;
protected void selectNextPossibleValue() {
int si;
if ( !isTableCellEditor ) {
protected void selectPreviousPossibleValue() {
int si;
if ( !isTableCellEditor ) {
protected void toggleOpenClose() {
Component c;
boolean shouldValidate = false;
if (c instanceof JPanel) {
shouldValidate = true;
g.setColor(t);
void repaintCurrentValue() {
Dimension d = getSizeForComponent(getDefaultListCellRenderer().getListCellRendererComponent(listBox, " ", -1, false, false));
if (!isDisplaySizeDirty) {
sameBaseline = true;
Dimension d;
d = getSizeForComponent(c);
sameBaseline = false;
sameBaseline = false;
isDisplaySizeDirty = false;
return result;
protected void installKeyboardActions() {
return null;
boolean isTableCellEditor() {
return isTableCellEditor;
protected void uninstallKeyboardActions() {
super(name);
getSelectedIndex());
boolean isEnterSelectablePopup =
isMinimumSizeDirty = true;
isDisplaySizeDirty = true;
addEditor();
addEditor();
removeEditor();
isMinimumSizeDirty = true;
isMinimumSizeDirty = true;
isDisplaySizeDirty = true;
isMinimumSizeDirty = true;
isDisplaySizeDirty = true;
e.consume();
hasFocus = true;
hasFocus = false;
if (!e.isTemporary()) {
isMinimumSizeDirty = true;
isDisplaySizeDirty = true;
contentsChanged( e );
contentsChanged( e );
boolean startingFromSelection = true;
startIndex++;
startIndex++;
startingFromSelection = false;
return index;