0N/A/*
5822N/A * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage javax.swing.plaf.basic;
0N/A
0N/Aimport java.awt.*;
0N/Aimport java.awt.event.*;
0N/Aimport javax.swing.*;
0N/Aimport javax.accessibility.*;
0N/Aimport javax.swing.plaf.*;
0N/Aimport javax.swing.text.*;
0N/Aimport javax.swing.event.*;
0N/Aimport java.beans.PropertyChangeListener;
0N/Aimport java.beans.PropertyChangeEvent;
0N/Aimport sun.awt.AppContext;
0N/Aimport sun.swing.DefaultLookup;
0N/Aimport sun.swing.UIAction;
0N/A
0N/A/**
0N/A * Basic UI implementation for JComboBox.
0N/A * <p>
0N/A * The combo box is a compound component which means that it is an agregate of
0N/A * many simpler components. This class creates and manages the listeners
0N/A * on the combo box and the combo box model. These listeners update the user
0N/A * interface in response to changes in the properties and state of the combo box.
0N/A * <p>
0N/A * All event handling is handled by listener classes created with the
0N/A * <code>createxxxListener()</code> methods and internal classes.
0N/A * You can change the behavior of this class by overriding the
0N/A * <code>createxxxListener()</code> methods and supplying your own
0N/A * event listeners or subclassing from the ones supplied in this class.
0N/A * <p>
0N/A * For adding specific actions,
0N/A * overide <code>installKeyboardActions</code> to add actions in response to
0N/A * KeyStroke bindings. See the article <a href="http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html">Keyboard Bindings in Swing</a>
0N/A * at <a href="http://java.sun.com/products/jfc/tsc"><em>The Swing Connection</em></a>.
0N/A *
0N/A * @author Arnaud Weber
0N/A * @author Tom Santos
0N/A * @author Mark Davidson
0N/A */
0N/Apublic class BasicComboBoxUI extends ComboBoxUI {
0N/A protected JComboBox comboBox;
0N/A /**
0N/A * This protected field is implementation specific. Do not access directly
0N/A * or override.
0N/A */
0N/A protected boolean hasFocus = false;
0N/A
0N/A // Control the selection behavior of the JComboBox when it is used
0N/A // in the JTable DefaultCellEditor.
0N/A private boolean isTableCellEditor = false;
0N/A private static final String IS_TABLE_CELL_EDITOR = "JComboBox.isTableCellEditor";
0N/A
0N/A // This list is for drawing the current item in the combo box.
0N/A protected JList listBox;
0N/A
0N/A // Used to render the currently selected item in the combo box.
0N/A // It doesn't have anything to do with the popup's rendering.
0N/A protected CellRendererPane currentValuePane = new CellRendererPane();
0N/A
0N/A // The implementation of ComboPopup that is used to show the popup.
0N/A protected ComboPopup popup;
0N/A
0N/A // The Component that the ComboBoxEditor uses for editing
0N/A protected Component editor;
0N/A
0N/A // The arrow button that invokes the popup.
0N/A protected JButton arrowButton;
0N/A
0N/A // Listeners that are attached to the JComboBox
0N/A /**
0N/A * This protected field is implementation specific. Do not access directly
0N/A * or override. Override the listener construction method instead.
0N/A *
0N/A * @see #createKeyListener
0N/A */
0N/A protected KeyListener keyListener;
0N/A /**
0N/A * This protected field is implementation specific. Do not access directly
0N/A * or override. Override the listener construction method instead.
0N/A *
0N/A * @see #createFocusListener
0N/A */
0N/A protected FocusListener focusListener;
0N/A /**
0N/A * This protected field is implementation specific. Do not access directly
0N/A * or override. Override the listener construction method instead.
0N/A *
0N/A * @see #createPropertyChangeListener
0N/A */
0N/A protected PropertyChangeListener propertyChangeListener;
0N/A
0N/A /**
0N/A * This protected field is implementation specific. Do not access directly
0N/A * or override. Override the listener construction method instead.
0N/A *
0N/A * @see #createItemListener
0N/A */
0N/A protected ItemListener itemListener;
0N/A
0N/A // Listeners that the ComboPopup produces.
0N/A protected MouseListener popupMouseListener;
0N/A protected MouseMotionListener popupMouseMotionListener;
0N/A protected KeyListener popupKeyListener;
0N/A
0N/A // This is used for knowing when to cache the minimum preferred size.
0N/A // If the data in the list changes, the cached value get marked for recalc.
0N/A // Added to the current JComboBox model
0N/A /**
0N/A * This protected field is implementation specific. Do not access directly
0N/A * or override. Override the listener construction method instead.
0N/A *
0N/A * @see #createListDataListener
0N/A */
0N/A protected ListDataListener listDataListener;
0N/A
0N/A /**
0N/A * Implements all the Listeners needed by this class, all existing
0N/A * listeners redirect to it.
0N/A */
0N/A private Handler handler;
0N/A
0N/A /**
0N/A * The time factor to treate the series of typed alphanumeric key
0N/A * as prefix for first letter navigation.
0N/A */
0N/A private long timeFactor = 1000L;
0N/A
0N/A /**
0N/A * This is tricky, this variables is needed for DefaultKeySelectionManager
0N/A * to take into account time factor.
0N/A */
0N/A private long lastTime = 0L;
0N/A private long time = 0L;
0N/A
0N/A /**
0N/A * The default key selection manager
0N/A */
0N/A JComboBox.KeySelectionManager keySelectionManager;
0N/A
0N/A // Flag for recalculating the minimum preferred size.
0N/A protected boolean isMinimumSizeDirty = true;
0N/A
0N/A // Cached minimum preferred size.
0N/A protected Dimension cachedMinimumSize = new Dimension( 0, 0 );
0N/A
0N/A // Flag for calculating the display size
0N/A private boolean isDisplaySizeDirty = true;
0N/A
0N/A // Cached the size that the display needs to render the largest item
0N/A private Dimension cachedDisplaySize = new Dimension( 0, 0 );
0N/A
0N/A // Key used for lookup of the DefaultListCellRenderer in the AppContext.
0N/A private static final Object COMBO_UI_LIST_CELL_RENDERER_KEY =
0N/A new StringBuffer("DefaultListCellRendererKey");
0N/A
0N/A static final StringBuffer HIDE_POPUP_KEY
0N/A = new StringBuffer("HidePopupKey");
0N/A
0N/A /**
0N/A * Whether or not all cells have the same baseline.
0N/A */
0N/A private boolean sameBaseline;
0N/A
1173N/A /**
1173N/A * Indicates whether or not the combo box button should be square.
1173N/A * If square, then the width and height are equal, and are both set to
1999N/A * the height of the combo minus appropriate insets.
1999N/A *
1999N/A * @since 1.7
1173N/A */
1999N/A protected boolean squareButton = true;
1173N/A
1173N/A /**
1999N/A * If specified, these insets act as padding around the cell renderer when
1999N/A * laying out and painting the "selected" item in the combo box. These
1999N/A * insets add to those specified by the cell renderer.
1999N/A *
1999N/A * @since 1.7
1173N/A */
1999N/A protected Insets padding;
1173N/A
0N/A // Used for calculating the default size.
0N/A private static ListCellRenderer getDefaultListCellRenderer() {
0N/A ListCellRenderer renderer = (ListCellRenderer)AppContext.
0N/A getAppContext().get(COMBO_UI_LIST_CELL_RENDERER_KEY);
0N/A
0N/A if (renderer == null) {
0N/A renderer = new DefaultListCellRenderer();
0N/A AppContext.getAppContext().put(COMBO_UI_LIST_CELL_RENDERER_KEY,
0N/A new DefaultListCellRenderer());
0N/A }
0N/A return renderer;
0N/A }
0N/A
0N/A /**
0N/A * Populates ComboBox's actions.
0N/A */
0N/A static void loadActionMap(LazyActionMap map) {
0N/A map.put(new Actions(Actions.HIDE));
0N/A map.put(new Actions(Actions.PAGE_DOWN));
0N/A map.put(new Actions(Actions.PAGE_UP));
0N/A map.put(new Actions(Actions.HOME));
0N/A map.put(new Actions(Actions.END));
0N/A map.put(new Actions(Actions.DOWN));
0N/A map.put(new Actions(Actions.DOWN_2));
0N/A map.put(new Actions(Actions.TOGGLE));
0N/A map.put(new Actions(Actions.TOGGLE_2));
0N/A map.put(new Actions(Actions.UP));
0N/A map.put(new Actions(Actions.UP_2));
0N/A map.put(new Actions(Actions.ENTER));
0N/A }
0N/A
0N/A //========================
0N/A // begin UI Initialization
0N/A //
0N/A
0N/A public static ComponentUI createUI(JComponent c) {
0N/A return new BasicComboBoxUI();
0N/A }
0N/A
1173N/A @Override
0N/A public void installUI( JComponent c ) {
0N/A isMinimumSizeDirty = true;
0N/A
0N/A comboBox = (JComboBox)c;
0N/A installDefaults();
0N/A popup = createPopup();
0N/A listBox = popup.getList();
0N/A
0N/A // Is this combo box a cell editor?
0N/A Boolean inTable = (Boolean)c.getClientProperty(IS_TABLE_CELL_EDITOR );
0N/A if (inTable != null) {
0N/A isTableCellEditor = inTable.equals(Boolean.TRUE) ? true : false;
0N/A }
0N/A
0N/A if ( comboBox.getRenderer() == null || comboBox.getRenderer() instanceof UIResource ) {
0N/A comboBox.setRenderer( createRenderer() );
0N/A }
0N/A
0N/A if ( comboBox.getEditor() == null || comboBox.getEditor() instanceof UIResource ) {
0N/A comboBox.setEditor( createEditor() );
0N/A }
0N/A
0N/A installListeners();
0N/A installComponents();
0N/A
0N/A comboBox.setLayout( createLayoutManager() );
0N/A
0N/A comboBox.setRequestFocusEnabled( true );
0N/A
0N/A installKeyboardActions();
0N/A
0N/A comboBox.putClientProperty("doNotCancelPopup", HIDE_POPUP_KEY);
0N/A
0N/A if (keySelectionManager == null || keySelectionManager instanceof UIResource) {
0N/A keySelectionManager = new DefaultKeySelectionManager();
0N/A }
0N/A comboBox.setKeySelectionManager(keySelectionManager);
0N/A }
0N/A
1173N/A @Override
0N/A public void uninstallUI( JComponent c ) {
0N/A setPopupVisible( comboBox, false);
0N/A popup.uninstallingUI();
0N/A
0N/A uninstallKeyboardActions();
0N/A
0N/A comboBox.setLayout( null );
0N/A
0N/A uninstallComponents();
0N/A uninstallListeners();
0N/A uninstallDefaults();
0N/A
0N/A if ( comboBox.getRenderer() == null || comboBox.getRenderer() instanceof UIResource ) {
0N/A comboBox.setRenderer( null );
0N/A }
0N/A
0N/A ComboBoxEditor comboBoxEditor = comboBox.getEditor();
0N/A if (comboBoxEditor instanceof UIResource ) {
0N/A if (comboBoxEditor.getEditorComponent().hasFocus()) {
0N/A // Leave focus in JComboBox.
0N/A comboBox.requestFocusInWindow();
0N/A }
0N/A comboBox.setEditor( null );
0N/A }
0N/A
0N/A if (keySelectionManager instanceof UIResource) {
0N/A comboBox.setKeySelectionManager(null);
0N/A }
0N/A
0N/A handler = null;
0N/A keyListener = null;
0N/A focusListener = null;
0N/A listDataListener = null;
0N/A propertyChangeListener = null;
0N/A popup = null;
0N/A listBox = null;
0N/A comboBox = null;
0N/A }
0N/A
0N/A /**
0N/A * Installs the default colors, default font, default renderer, and default
0N/A * editor into the JComboBox.
0N/A */
0N/A protected void installDefaults() {
0N/A LookAndFeel.installColorsAndFont( comboBox,
0N/A "ComboBox.background",
0N/A "ComboBox.foreground",
0N/A "ComboBox.font" );
0N/A LookAndFeel.installBorder( comboBox, "ComboBox.border" );
0N/A LookAndFeel.installProperty( comboBox, "opaque", Boolean.TRUE);
0N/A
0N/A Long l = (Long)UIManager.get("ComboBox.timeFactor");
1173N/A timeFactor = l == null ? 1000L : l.longValue();
1173N/A
1173N/A //NOTE: this needs to default to true if not specified
1173N/A Boolean b = (Boolean)UIManager.get("ComboBox.squareButton");
1173N/A squareButton = b == null ? true : b;
1173N/A
1173N/A padding = UIManager.getInsets("ComboBox.padding");
0N/A }
0N/A
0N/A /**
1999N/A * Creates and installs listeners for the combo box and its model.
0N/A * This method is called when the UI is installed.
0N/A */
0N/A protected void installListeners() {
0N/A if ( (itemListener = createItemListener()) != null) {
0N/A comboBox.addItemListener( itemListener );
0N/A }
0N/A if ( (propertyChangeListener = createPropertyChangeListener()) != null ) {
0N/A comboBox.addPropertyChangeListener( propertyChangeListener );
0N/A }
0N/A if ( (keyListener = createKeyListener()) != null ) {
0N/A comboBox.addKeyListener( keyListener );
0N/A }
0N/A if ( (focusListener = createFocusListener()) != null ) {
0N/A comboBox.addFocusListener( focusListener );
0N/A }
0N/A if ((popupMouseListener = popup.getMouseListener()) != null) {
0N/A comboBox.addMouseListener( popupMouseListener );
0N/A }
0N/A if ((popupMouseMotionListener = popup.getMouseMotionListener()) != null) {
0N/A comboBox.addMouseMotionListener( popupMouseMotionListener );
0N/A }
0N/A if ((popupKeyListener = popup.getKeyListener()) != null) {
0N/A comboBox.addKeyListener(popupKeyListener);
0N/A }
0N/A
0N/A if ( comboBox.getModel() != null ) {
0N/A if ( (listDataListener = createListDataListener()) != null ) {
0N/A comboBox.getModel().addListDataListener( listDataListener );
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
1999N/A * Uninstalls the default colors, default font, default renderer,
1999N/A * and default editor from the combo box.
0N/A */
0N/A protected void uninstallDefaults() {
0N/A LookAndFeel.installColorsAndFont( comboBox,
0N/A "ComboBox.background",
0N/A "ComboBox.foreground",
0N/A "ComboBox.font" );
0N/A LookAndFeel.uninstallBorder( comboBox );
0N/A }
0N/A
0N/A /**
1999N/A * Removes the installed listeners from the combo box and its model.
0N/A * The number and types of listeners removed and in this method should be
0N/A * the same that was added in <code>installListeners</code>
0N/A */
0N/A protected void uninstallListeners() {
0N/A if ( keyListener != null ) {
0N/A comboBox.removeKeyListener( keyListener );
0N/A }
0N/A if ( itemListener != null) {
0N/A comboBox.removeItemListener( itemListener );
0N/A }
0N/A if ( propertyChangeListener != null ) {
0N/A comboBox.removePropertyChangeListener( propertyChangeListener );
0N/A }
0N/A if ( focusListener != null) {
0N/A comboBox.removeFocusListener( focusListener );
0N/A }
0N/A if ( popupMouseListener != null) {
0N/A comboBox.removeMouseListener( popupMouseListener );
0N/A }
0N/A if ( popupMouseMotionListener != null) {
0N/A comboBox.removeMouseMotionListener( popupMouseMotionListener );
0N/A }
0N/A if (popupKeyListener != null) {
0N/A comboBox.removeKeyListener(popupKeyListener);
0N/A }
0N/A if ( comboBox.getModel() != null ) {
0N/A if ( listDataListener != null ) {
0N/A comboBox.getModel().removeListDataListener( listDataListener );
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Creates the popup portion of the combo box.
0N/A *
0N/A * @return an instance of <code>ComboPopup</code>
0N/A * @see ComboPopup
0N/A */
0N/A protected ComboPopup createPopup() {
0N/A return new BasicComboPopup( comboBox );
0N/A }
0N/A
0N/A /**
0N/A * Creates a <code>KeyListener</code> which will be added to the
0N/A * combo box. If this method returns null then it will not be added
0N/A * to the combo box.
0N/A *
0N/A * @return an instance <code>KeyListener</code> or null
0N/A */
0N/A protected KeyListener createKeyListener() {
0N/A return getHandler();
0N/A }
0N/A
0N/A /**
0N/A * Creates a <code>FocusListener</code> which will be added to the combo box.
0N/A * If this method returns null then it will not be added to the combo box.
0N/A *
0N/A * @return an instance of a <code>FocusListener</code> or null
0N/A */
0N/A protected FocusListener createFocusListener() {
0N/A return getHandler();
0N/A }
0N/A
0N/A /**
0N/A * Creates a list data listener which will be added to the
0N/A * <code>ComboBoxModel</code>. If this method returns null then
0N/A * it will not be added to the combo box model.
0N/A *
0N/A * @return an instance of a <code>ListDataListener</code> or null
0N/A */
0N/A protected ListDataListener createListDataListener() {
0N/A return getHandler();
0N/A }
0N/A
0N/A /**
0N/A * Creates an <code>ItemListener</code> which will be added to the
0N/A * combo box. If this method returns null then it will not
0N/A * be added to the combo box.
0N/A * <p>
0N/A * Subclasses may override this method to return instances of their own
0N/A * ItemEvent handlers.
0N/A *
0N/A * @return an instance of an <code>ItemListener</code> or null
0N/A */
0N/A protected ItemListener createItemListener() {
0N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * Creates a <code>PropertyChangeListener</code> which will be added to
0N/A * the combo box. If this method returns null then it will not
0N/A * be added to the combo box.
0N/A *
0N/A * @return an instance of a <code>PropertyChangeListener</code> or null
0N/A */
0N/A protected PropertyChangeListener createPropertyChangeListener() {
0N/A return getHandler();
0N/A }
0N/A
0N/A /**
0N/A * Creates a layout manager for managing the components which make up the
0N/A * combo box.
0N/A *
0N/A * @return an instance of a layout manager
0N/A */
0N/A protected LayoutManager createLayoutManager() {
0N/A return getHandler();
0N/A }
0N/A
0N/A /**
0N/A * Creates the default renderer that will be used in a non-editiable combo
0N/A * box. A default renderer will used only if a renderer has not been
0N/A * explicitly set with <code>setRenderer</code>.
0N/A *
0N/A * @return a <code>ListCellRender</code> used for the combo box
0N/A * @see javax.swing.JComboBox#setRenderer
0N/A */
0N/A protected ListCellRenderer createRenderer() {
0N/A return new BasicComboBoxRenderer.UIResource();
0N/A }
0N/A
0N/A /**
0N/A * Creates the default editor that will be used in editable combo boxes.
0N/A * A default editor will be used only if an editor has not been
0N/A * explicitly set with <code>setEditor</code>.
0N/A *
0N/A * @return a <code>ComboBoxEditor</code> used for the combo box
0N/A * @see javax.swing.JComboBox#setEditor
0N/A */
0N/A protected ComboBoxEditor createEditor() {
0N/A return new BasicComboBoxEditor.UIResource();
0N/A }
0N/A
0N/A /**
0N/A * Returns the shared listener.
0N/A */
0N/A private Handler getHandler() {
0N/A if (handler == null) {
0N/A handler = new Handler();
0N/A }
0N/A return handler;
0N/A }
0N/A
0N/A //
0N/A // end UI Initialization
0N/A //======================
0N/A
0N/A
0N/A //======================
0N/A // begin Inner classes
0N/A //
0N/A
0N/A /**
0N/A * This listener checks to see if the key event isn't a navigation key. If
0N/A * it finds a key event that wasn't a navigation key it dispatches it to
0N/A * JComboBox.selectWithKeyChar() so that it can do type-ahead.
0N/A *
0N/A * This public inner class should be treated as protected.
0N/A * Instantiate it only within subclasses of
0N/A * <code>BasicComboBoxUI</code>.
0N/A */
0N/A public class KeyHandler extends KeyAdapter {
1173N/A @Override
0N/A public void keyPressed( KeyEvent e ) {
0N/A getHandler().keyPressed(e);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * This listener hides the popup when the focus is lost. It also repaints
0N/A * when focus is gained or lost.
0N/A *
0N/A * This public inner class should be treated as protected.
0N/A * Instantiate it only within subclasses of
0N/A * <code>BasicComboBoxUI</code>.
0N/A */
0N/A public class FocusHandler implements FocusListener {
0N/A public void focusGained( FocusEvent e ) {
0N/A getHandler().focusGained(e);
0N/A }
0N/A
0N/A public void focusLost( FocusEvent e ) {
0N/A getHandler().focusLost(e);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * This listener watches for changes in the
0N/A * <code>ComboBoxModel</code>.
0N/A * <p>
0N/A * This public inner class should be treated as protected.
0N/A * Instantiate it only within subclasses of
0N/A * <code>BasicComboBoxUI</code>.
0N/A *
0N/A * @see #createListDataListener
0N/A */
0N/A public class ListDataHandler implements ListDataListener {
0N/A public void contentsChanged( ListDataEvent e ) {
0N/A getHandler().contentsChanged(e);
0N/A }
0N/A
0N/A public void intervalAdded( ListDataEvent e ) {
0N/A getHandler().intervalAdded(e);
0N/A }
0N/A
0N/A public void intervalRemoved( ListDataEvent e ) {
0N/A getHandler().intervalRemoved(e);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * This listener watches for changes to the selection in the
0N/A * combo box.
0N/A * <p>
0N/A * This public inner class should be treated as protected.
0N/A * Instantiate it only within subclasses of
0N/A * <code>BasicComboBoxUI</code>.
0N/A *
0N/A * @see #createItemListener
0N/A */
0N/A public class ItemHandler implements ItemListener {
0N/A // This class used to implement behavior which is now redundant.
0N/A public void itemStateChanged(ItemEvent e) {}
0N/A }
0N/A
0N/A /**
0N/A * This listener watches for bound properties that have changed in the
0N/A * combo box.
0N/A * <p>
0N/A * Subclasses which wish to listen to combo box property changes should
0N/A * call the superclass methods to ensure that the combo box ui correctly
0N/A * handles property changes.
0N/A * <p>
0N/A * This public inner class should be treated as protected.
0N/A * Instantiate it only within subclasses of
0N/A * <code>BasicComboBoxUI</code>.
0N/A *
0N/A * @see #createPropertyChangeListener
0N/A */
0N/A public class PropertyChangeHandler implements PropertyChangeListener {
0N/A public void propertyChange(PropertyChangeEvent e) {
0N/A getHandler().propertyChange(e);
0N/A }
0N/A }
0N/A
0N/A
0N/A // Syncronizes the ToolTip text for the components within the combo box to be the
0N/A // same value as the combo box ToolTip text.
0N/A private void updateToolTipTextForChildren() {
0N/A Component[] children = comboBox.getComponents();
0N/A for ( int i = 0; i < children.length; ++i ) {
0N/A if ( children[i] instanceof JComponent ) {
0N/A ((JComponent)children[i]).setToolTipText( comboBox.getToolTipText() );
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * This layout manager handles the 'standard' layout of combo boxes. It puts
0N/A * the arrow button to the right and the editor to the left. If there is no
0N/A * editor it still keeps the arrow button to the right.
0N/A *
0N/A * This public inner class should be treated as protected.
0N/A * Instantiate it only within subclasses of
0N/A * <code>BasicComboBoxUI</code>.
0N/A */
0N/A public class ComboBoxLayoutManager implements LayoutManager {
0N/A public void addLayoutComponent(String name, Component comp) {}
0N/A
0N/A public void removeLayoutComponent(Component comp) {}
0N/A
0N/A public Dimension preferredLayoutSize(Container parent) {
0N/A return getHandler().preferredLayoutSize(parent);
0N/A }
0N/A
0N/A public Dimension minimumLayoutSize(Container parent) {
0N/A return getHandler().minimumLayoutSize(parent);
0N/A }
0N/A
0N/A public void layoutContainer(Container parent) {
0N/A getHandler().layoutContainer(parent);
0N/A }
0N/A }
0N/A
0N/A //
0N/A // end Inner classes
0N/A //====================
0N/A
0N/A
0N/A //===============================
0N/A // begin Sub-Component Management
0N/A //
0N/A
0N/A /**
0N/A * Creates and initializes the components which make up the
0N/A * aggregate combo box. This method is called as part of the UI
0N/A * installation process.
0N/A */
0N/A protected void installComponents() {
0N/A arrowButton = createArrowButton();
0N/A
0N/A if (arrowButton != null) {
6131N/A comboBox.add(arrowButton);
0N/A configureArrowButton();
0N/A }
0N/A
0N/A if ( comboBox.isEditable() ) {
0N/A addEditor();
0N/A }
0N/A
0N/A comboBox.add( currentValuePane );
0N/A }
0N/A
0N/A /**
0N/A * The aggregate components which compise the combo box are
0N/A * unregistered and uninitialized. This method is called as part of the
0N/A * UI uninstallation process.
0N/A */
0N/A protected void uninstallComponents() {
0N/A if ( arrowButton != null ) {
0N/A unconfigureArrowButton();
0N/A }
0N/A if ( editor != null ) {
0N/A unconfigureEditor();
0N/A }
0N/A comboBox.removeAll(); // Just to be safe.
0N/A arrowButton = null;
0N/A }
0N/A
0N/A /**
0N/A * This public method is implementation specific and should be private.
0N/A * do not call or override. To implement a specific editor create a
0N/A * custom <code>ComboBoxEditor</code>
0N/A *
0N/A * @see #createEditor
0N/A * @see javax.swing.JComboBox#setEditor
0N/A * @see javax.swing.ComboBoxEditor
0N/A */
0N/A public void addEditor() {
0N/A removeEditor();
0N/A editor = comboBox.getEditor().getEditorComponent();
0N/A if ( editor != null ) {
0N/A configureEditor();
0N/A comboBox.add(editor);
0N/A if(comboBox.isFocusOwner()) {
0N/A // Switch focus to the editor component
0N/A editor.requestFocusInWindow();
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * This public method is implementation specific and should be private.
0N/A * do not call or override.
0N/A *
0N/A * @see #addEditor
0N/A */
0N/A public void removeEditor() {
0N/A if ( editor != null ) {
0N/A unconfigureEditor();
0N/A comboBox.remove( editor );
0N/A editor = null;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * This protected method is implementation specific and should be private.
0N/A * do not call or override.
0N/A *
0N/A * @see #addEditor
0N/A */
0N/A protected void configureEditor() {
0N/A // Should be in the same state as the combobox
0N/A editor.setEnabled(comboBox.isEnabled());
0N/A
0N/A editor.setFocusable(comboBox.isFocusable());
0N/A
0N/A editor.setFont( comboBox.getFont() );
0N/A
0N/A if (focusListener != null) {
0N/A editor.addFocusListener(focusListener);
0N/A }
0N/A
0N/A editor.addFocusListener( getHandler() );
0N/A
0N/A comboBox.getEditor().addActionListener(getHandler());
0N/A
0N/A if(editor instanceof JComponent) {
0N/A ((JComponent)editor).putClientProperty("doNotCancelPopup",
0N/A HIDE_POPUP_KEY);
0N/A ((JComponent)editor).setInheritsPopupMenu(true);
0N/A }
0N/A
0N/A comboBox.configureEditor(comboBox.getEditor(),comboBox.getSelectedItem());
1173N/A
1173N/A editor.addPropertyChangeListener(propertyChangeListener);
0N/A }
0N/A
0N/A /**
0N/A * This protected method is implementation specific and should be private.
0N/A * Do not call or override.
0N/A *
0N/A * @see #addEditor
0N/A */
0N/A protected void unconfigureEditor() {
0N/A if (focusListener != null) {
0N/A editor.removeFocusListener(focusListener);
0N/A }
0N/A
1173N/A editor.removePropertyChangeListener(propertyChangeListener);
0N/A editor.removeFocusListener(getHandler());
0N/A comboBox.getEditor().removeActionListener(getHandler());
0N/A }
0N/A
0N/A /**
0N/A * This public method is implementation specific and should be private. Do
0N/A * not call or override.
0N/A *
0N/A * @see #createArrowButton
0N/A */
0N/A public void configureArrowButton() {
0N/A if ( arrowButton != null ) {
0N/A arrowButton.setEnabled( comboBox.isEnabled() );
0N/A arrowButton.setFocusable(comboBox.isFocusable());
0N/A arrowButton.setRequestFocusEnabled(false);
0N/A arrowButton.addMouseListener( popup.getMouseListener() );
0N/A arrowButton.addMouseMotionListener( popup.getMouseMotionListener() );
0N/A arrowButton.resetKeyboardActions();
0N/A arrowButton.putClientProperty("doNotCancelPopup", HIDE_POPUP_KEY);
0N/A arrowButton.setInheritsPopupMenu(true);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * This public method is implementation specific and should be private. Do
0N/A * not call or override.
0N/A *
0N/A * @see #createArrowButton
0N/A */
0N/A public void unconfigureArrowButton() {
0N/A if ( arrowButton != null ) {
0N/A arrowButton.removeMouseListener( popup.getMouseListener() );
0N/A arrowButton.removeMouseMotionListener( popup.getMouseMotionListener() );
0N/A }
0N/A }
0N/A
0N/A /**
1999N/A * Creates a button which will be used as the control to show or hide
0N/A * the popup portion of the combo box.
0N/A *
0N/A * @return a button which represents the popup control
0N/A */
0N/A protected JButton createArrowButton() {
0N/A JButton button = new BasicArrowButton(BasicArrowButton.SOUTH,
0N/A UIManager.getColor("ComboBox.buttonBackground"),
0N/A UIManager.getColor("ComboBox.buttonShadow"),
0N/A UIManager.getColor("ComboBox.buttonDarkShadow"),
0N/A UIManager.getColor("ComboBox.buttonHighlight"));
0N/A button.setName("ComboBox.arrowButton");
0N/A return button;
0N/A }
0N/A
0N/A //
0N/A // end Sub-Component Management
0N/A //===============================
0N/A
0N/A
0N/A //================================
0N/A // begin ComboBoxUI Implementation
0N/A //
0N/A
0N/A /**
0N/A * Tells if the popup is visible or not.
0N/A */
0N/A public boolean isPopupVisible( JComboBox c ) {
0N/A return popup.isVisible();
0N/A }
0N/A
0N/A /**
0N/A * Hides the popup.
0N/A */
0N/A public void setPopupVisible( JComboBox c, boolean v ) {
0N/A if ( v ) {
0N/A popup.show();
0N/A } else {
0N/A popup.hide();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Determines if the JComboBox is focus traversable. If the JComboBox is editable
0N/A * this returns false, otherwise it returns true.
0N/A */
0N/A public boolean isFocusTraversable( JComboBox c ) {
0N/A return !comboBox.isEditable();
0N/A }
0N/A
0N/A //
0N/A // end ComboBoxUI Implementation
0N/A //==============================
0N/A
0N/A
0N/A //=================================
0N/A // begin ComponentUI Implementation
1173N/A @Override
0N/A public void paint( Graphics g, JComponent c ) {
0N/A hasFocus = comboBox.hasFocus();
0N/A if ( !comboBox.isEditable() ) {
0N/A Rectangle r = rectangleForCurrentValue();
0N/A paintCurrentValueBackground(g,r,hasFocus);
0N/A paintCurrentValue(g,r,hasFocus);
0N/A }
0N/A }
0N/A
1173N/A @Override
0N/A public Dimension getPreferredSize( JComponent c ) {
0N/A return getMinimumSize(c);
0N/A }
0N/A
0N/A /**
0N/A * The minumum size is the size of the display area plus insets plus the button.
0N/A */
1173N/A @Override
0N/A public Dimension getMinimumSize( JComponent c ) {
0N/A if ( !isMinimumSizeDirty ) {
0N/A return new Dimension(cachedMinimumSize);
0N/A }
0N/A Dimension size = getDisplaySize();
0N/A Insets insets = getInsets();
1173N/A //calculate the width and height of the button
1173N/A int buttonHeight = size.height;
1173N/A int buttonWidth = squareButton ? buttonHeight : arrowButton.getPreferredSize().width;
1173N/A //adjust the size based on the button width
0N/A size.height += insets.top + insets.bottom;
1173N/A size.width += insets.left + insets.right + buttonWidth;
0N/A
0N/A cachedMinimumSize.setSize( size.width, size.height );
0N/A isMinimumSizeDirty = false;
0N/A
0N/A return new Dimension(size);
0N/A }
0N/A
1173N/A @Override
0N/A public Dimension getMaximumSize( JComponent c ) {
0N/A return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
0N/A }
0N/A
0N/A /**
0N/A * Returns the baseline.
0N/A *
0N/A * @throws NullPointerException {@inheritDoc}
0N/A * @throws IllegalArgumentException {@inheritDoc}
0N/A * @see javax.swing.JComponent#getBaseline(int, int)
0N/A * @since 1.6
0N/A */
1173N/A @Override
0N/A public int getBaseline(JComponent c, int width, int height) {
0N/A super.getBaseline(c, width, height);
0N/A int baseline = -1;
0N/A // force sameBaseline to be updated.
0N/A getDisplaySize();
0N/A if (sameBaseline) {
0N/A Insets insets = c.getInsets();
0N/A height = height - insets.top - insets.bottom;
0N/A if (!comboBox.isEditable()) {
0N/A ListCellRenderer renderer = comboBox.getRenderer();
0N/A if (renderer == null) {
0N/A renderer = new DefaultListCellRenderer();
0N/A }
0N/A Object value = null;
0N/A Object prototypeValue = comboBox.getPrototypeDisplayValue();
0N/A if (prototypeValue != null) {
0N/A value = prototypeValue;
0N/A }
0N/A else if (comboBox.getModel().getSize() > 0) {
0N/A // Note, we're assuming the baseline is the same for all
0N/A // cells, if not, this needs to loop through all.
0N/A value = comboBox.getModel().getElementAt(0);
0N/A }
0N/A if (value == null) {
0N/A value = " ";
0N/A } else if (value instanceof String && "".equals(value)) {
0N/A value = " ";
0N/A }
0N/A Component component = renderer.
0N/A getListCellRendererComponent(listBox, value, -1,
0N/A false, false);
0N/A if (component instanceof JComponent) {
0N/A component.setFont(comboBox.getFont());
0N/A }
0N/A baseline = component.getBaseline(width, height);
0N/A }
0N/A else {
0N/A baseline = editor.getBaseline(width, height);
0N/A }
0N/A if (baseline > 0) {
0N/A baseline += insets.top;
0N/A }
0N/A }
0N/A return baseline;
0N/A }
0N/A
0N/A /**
0N/A * Returns an enum indicating how the baseline of the component
0N/A * changes as the size changes.
0N/A *
0N/A * @throws NullPointerException {@inheritDoc}
0N/A * @see javax.swing.JComponent#getBaseline(int, int)
0N/A * @since 1.6
0N/A */
1173N/A @Override
0N/A public Component.BaselineResizeBehavior getBaselineResizeBehavior(
0N/A JComponent c) {
0N/A super.getBaselineResizeBehavior(c);
0N/A // Force sameBaseline to be updated.
0N/A getDisplaySize();
0N/A if (comboBox.isEditable()) {
0N/A return editor.getBaselineResizeBehavior();
0N/A }
0N/A else if (sameBaseline) {
0N/A ListCellRenderer renderer = comboBox.getRenderer();
0N/A if (renderer == null) {
0N/A renderer = new DefaultListCellRenderer();
0N/A }
0N/A Object value = null;
0N/A Object prototypeValue = comboBox.getPrototypeDisplayValue();
0N/A if (prototypeValue != null) {
0N/A value = prototypeValue;
0N/A }
0N/A else if (comboBox.getModel().getSize() > 0) {
0N/A // Note, we're assuming the baseline is the same for all
0N/A // cells, if not, this needs to loop through all.
0N/A value = comboBox.getModel().getElementAt(0);
0N/A }
0N/A if (value != null) {
0N/A Component component = renderer.
0N/A getListCellRendererComponent(listBox, value, -1,
0N/A false, false);
0N/A return component.getBaselineResizeBehavior();
0N/A }
0N/A }
0N/A return Component.BaselineResizeBehavior.OTHER;
0N/A }
0N/A
0N/A // This is currently hacky...
1173N/A @Override
0N/A public int getAccessibleChildrenCount(JComponent c) {
0N/A if ( comboBox.isEditable() ) {
0N/A return 2;
0N/A }
0N/A else {
0N/A return 1;
0N/A }
0N/A }
0N/A
0N/A // This is currently hacky...
1173N/A @Override
0N/A public Accessible getAccessibleChild(JComponent c, int i) {
0N/A // 0 = the popup
0N/A // 1 = the editor
0N/A switch ( i ) {
0N/A case 0:
0N/A if ( popup instanceof Accessible ) {
0N/A AccessibleContext ac = ((Accessible) popup).getAccessibleContext();
0N/A ac.setAccessibleParent(comboBox);
0N/A return(Accessible) popup;
0N/A }
0N/A break;
0N/A case 1:
0N/A if ( comboBox.isEditable()
0N/A && (editor instanceof Accessible) ) {
0N/A AccessibleContext ac = ((Accessible) editor).getAccessibleContext();
0N/A ac.setAccessibleParent(comboBox);
0N/A return(Accessible) editor;
0N/A }
0N/A break;
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A //
0N/A // end ComponentUI Implementation
0N/A //===============================
0N/A
0N/A
0N/A //======================
0N/A // begin Utility Methods
0N/A //
0N/A
0N/A /**
0N/A * Returns whether or not the supplied keyCode maps to a key that is used for
0N/A * navigation. This is used for optimizing key input by only passing non-
0N/A * navigation keys to the type-ahead mechanism. Subclasses should override this
0N/A * if they change the navigation keys.
0N/A */
0N/A protected boolean isNavigationKey( int keyCode ) {
0N/A return keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN ||
0N/A keyCode == KeyEvent.VK_KP_UP || keyCode == KeyEvent.VK_KP_DOWN;
0N/A }
0N/A
0N/A private boolean isNavigationKey(int keyCode, int modifiers) {
0N/A InputMap inputMap = comboBox.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
0N/A KeyStroke key = KeyStroke.getKeyStroke(keyCode, modifiers);
0N/A
0N/A if (inputMap != null && inputMap.get(key) != null) {
0N/A return true;
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /**
0N/A * Selects the next item in the list. It won't change the selection if the
0N/A * currently selected item is already the last item.
0N/A */
0N/A protected void selectNextPossibleValue() {
0N/A int si;
0N/A
0N/A if ( comboBox.isPopupVisible() ) {
0N/A si = listBox.getSelectedIndex();
0N/A }
0N/A else {
0N/A si = comboBox.getSelectedIndex();
0N/A }
0N/A
0N/A if ( si < comboBox.getModel().getSize() - 1 ) {
0N/A listBox.setSelectedIndex( si + 1 );
0N/A listBox.ensureIndexIsVisible( si + 1 );
0N/A if ( !isTableCellEditor ) {
5822N/A if (!(UIManager.getBoolean("ComboBox.noActionOnKeyNavigation") && comboBox.isPopupVisible())) {
5822N/A comboBox.setSelectedIndex(si+1);
5822N/A }
0N/A }
0N/A comboBox.repaint();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Selects the previous item in the list. It won't change the selection if the
0N/A * currently selected item is already the first item.
0N/A */
0N/A protected void selectPreviousPossibleValue() {
0N/A int si;
0N/A
0N/A if ( comboBox.isPopupVisible() ) {
0N/A si = listBox.getSelectedIndex();
0N/A }
0N/A else {
0N/A si = comboBox.getSelectedIndex();
0N/A }
0N/A
0N/A if ( si > 0 ) {
0N/A listBox.setSelectedIndex( si - 1 );
0N/A listBox.ensureIndexIsVisible( si - 1 );
0N/A if ( !isTableCellEditor ) {
5822N/A if (!(UIManager.getBoolean("ComboBox.noActionOnKeyNavigation") && comboBox.isPopupVisible())) {
5822N/A comboBox.setSelectedIndex(si-1);
5822N/A }
0N/A }
0N/A comboBox.repaint();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Hides the popup if it is showing and shows the popup if it is hidden.
0N/A */
0N/A protected void toggleOpenClose() {
0N/A setPopupVisible(comboBox, !isPopupVisible(comboBox));
0N/A }
0N/A
0N/A /**
0N/A * Returns the area that is reserved for drawing the currently selected item.
0N/A */
0N/A protected Rectangle rectangleForCurrentValue() {
0N/A int width = comboBox.getWidth();
0N/A int height = comboBox.getHeight();
0N/A Insets insets = getInsets();
0N/A int buttonSize = height - (insets.top + insets.bottom);
0N/A if ( arrowButton != null ) {
0N/A buttonSize = arrowButton.getWidth();
0N/A }
0N/A if(BasicGraphicsUtils.isLeftToRight(comboBox)) {
0N/A return new Rectangle(insets.left, insets.top,
0N/A width - (insets.left + insets.right + buttonSize),
0N/A height - (insets.top + insets.bottom));
0N/A }
0N/A else {
0N/A return new Rectangle(insets.left + buttonSize, insets.top,
0N/A width - (insets.left + insets.right + buttonSize),
0N/A height - (insets.top + insets.bottom));
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Gets the insets from the JComboBox.
0N/A */
0N/A protected Insets getInsets() {
0N/A return comboBox.getInsets();
0N/A }
0N/A
0N/A //
0N/A // end Utility Methods
0N/A //====================
0N/A
0N/A
0N/A //===============================
0N/A // begin Painting Utility Methods
0N/A //
0N/A
0N/A /**
0N/A * Paints the currently selected item.
0N/A */
0N/A public void paintCurrentValue(Graphics g,Rectangle bounds,boolean hasFocus) {
0N/A ListCellRenderer renderer = comboBox.getRenderer();
0N/A Component c;
0N/A
0N/A if ( hasFocus && !isPopupVisible(comboBox) ) {
0N/A c = renderer.getListCellRendererComponent( listBox,
0N/A comboBox.getSelectedItem(),
0N/A -1,
0N/A true,
0N/A false );
0N/A }
0N/A else {
0N/A c = renderer.getListCellRendererComponent( listBox,
0N/A comboBox.getSelectedItem(),
0N/A -1,
0N/A false,
0N/A false );
0N/A c.setBackground(UIManager.getColor("ComboBox.background"));
0N/A }
0N/A c.setFont(comboBox.getFont());
0N/A if ( hasFocus && !isPopupVisible(comboBox) ) {
0N/A c.setForeground(listBox.getSelectionForeground());
0N/A c.setBackground(listBox.getSelectionBackground());
0N/A }
0N/A else {
0N/A if ( comboBox.isEnabled() ) {
0N/A c.setForeground(comboBox.getForeground());
0N/A c.setBackground(comboBox.getBackground());
0N/A }
0N/A else {
0N/A c.setForeground(DefaultLookup.getColor(
0N/A comboBox, this, "ComboBox.disabledForeground", null));
0N/A c.setBackground(DefaultLookup.getColor(
0N/A comboBox, this, "ComboBox.disabledBackground", null));
0N/A }
0N/A }
0N/A
0N/A // Fix for 4238829: should lay out the JPanel.
0N/A boolean shouldValidate = false;
0N/A if (c instanceof JPanel) {
0N/A shouldValidate = true;
0N/A }
0N/A
1173N/A int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height;
1173N/A if (padding != null) {
1173N/A x = bounds.x + padding.left;
1173N/A y = bounds.y + padding.top;
1173N/A w = bounds.width - (padding.left + padding.right);
1173N/A h = bounds.height - (padding.top + padding.bottom);
1173N/A }
1173N/A
1173N/A currentValuePane.paintComponent(g,c,comboBox,x,y,w,h,shouldValidate);
0N/A }
0N/A
0N/A /**
0N/A * Paints the background of the currently selected item.
0N/A */
0N/A public void paintCurrentValueBackground(Graphics g,Rectangle bounds,boolean hasFocus) {
0N/A Color t = g.getColor();
0N/A if ( comboBox.isEnabled() )
0N/A g.setColor(DefaultLookup.getColor(comboBox, this,
0N/A "ComboBox.background", null));
0N/A else
0N/A g.setColor(DefaultLookup.getColor(comboBox, this,
0N/A "ComboBox.disabledBackground", null));
0N/A g.fillRect(bounds.x,bounds.y,bounds.width,bounds.height);
0N/A g.setColor(t);
0N/A }
0N/A
0N/A /**
0N/A * Repaint the currently selected item.
0N/A */
0N/A void repaintCurrentValue() {
0N/A Rectangle r = rectangleForCurrentValue();
0N/A comboBox.repaint(r.x,r.y,r.width,r.height);
0N/A }
0N/A
0N/A //
0N/A // end Painting Utility Methods
0N/A //=============================
0N/A
0N/A
0N/A //===============================
0N/A // begin Size Utility Methods
0N/A //
0N/A
0N/A /**
0N/A * Return the default size of an empty display area of the combo box using
0N/A * the current renderer and font.
0N/A *
0N/A * @return the size of an empty display area
0N/A * @see #getDisplaySize
0N/A */
0N/A protected Dimension getDefaultSize() {
0N/A // Calculates the height and width using the default text renderer
0N/A Dimension d = getSizeForComponent(getDefaultListCellRenderer().getListCellRendererComponent(listBox, " ", -1, false, false));
0N/A
0N/A return new Dimension(d.width, d.height);
0N/A }
0N/A
0N/A /**
0N/A * Returns the calculated size of the display area. The display area is the
0N/A * portion of the combo box in which the selected item is displayed. This
0N/A * method will use the prototype display value if it has been set.
0N/A * <p>
0N/A * For combo boxes with a non trivial number of items, it is recommended to
0N/A * use a prototype display value to significantly speed up the display
0N/A * size calculation.
0N/A *
0N/A * @return the size of the display area calculated from the combo box items
0N/A * @see javax.swing.JComboBox#setPrototypeDisplayValue
0N/A */
0N/A protected Dimension getDisplaySize() {
0N/A if (!isDisplaySizeDirty) {
0N/A return new Dimension(cachedDisplaySize);
0N/A }
0N/A Dimension result = new Dimension();
0N/A
0N/A ListCellRenderer renderer = comboBox.getRenderer();
0N/A if (renderer == null) {
0N/A renderer = new DefaultListCellRenderer();
0N/A }
0N/A
0N/A sameBaseline = true;
0N/A
0N/A Object prototypeValue = comboBox.getPrototypeDisplayValue();
0N/A if (prototypeValue != null) {
0N/A // Calculates the dimension based on the prototype value
0N/A result = getSizeForComponent(renderer.getListCellRendererComponent(listBox,
0N/A prototypeValue,
0N/A -1, false, false));
0N/A } else {
0N/A // Calculate the dimension by iterating over all the elements in the combo
0N/A // box list.
0N/A ComboBoxModel model = comboBox.getModel();
0N/A int modelSize = model.getSize();
0N/A int baseline = -1;
0N/A Dimension d;
0N/A
0N/A Component cpn;
0N/A
0N/A if (modelSize > 0 ) {
0N/A for (int i = 0; i < modelSize ; i++ ) {
0N/A // Calculates the maximum height and width based on the largest
0N/A // element
0N/A Object value = model.getElementAt(i);
0N/A Component c = renderer.getListCellRendererComponent(
0N/A listBox, value, -1, false, false);
0N/A d = getSizeForComponent(c);
0N/A if (sameBaseline && value != null &&
0N/A (!(value instanceof String) || !"".equals(value))) {
0N/A int newBaseline = c.getBaseline(d.width, d.height);
0N/A if (newBaseline == -1) {
0N/A sameBaseline = false;
0N/A }
0N/A else if (baseline == -1) {
0N/A baseline = newBaseline;
0N/A }
0N/A else if (baseline != newBaseline) {
0N/A sameBaseline = false;
0N/A }
0N/A }
0N/A result.width = Math.max(result.width,d.width);
0N/A result.height = Math.max(result.height,d.height);
0N/A }
0N/A } else {
0N/A result = getDefaultSize();
0N/A if (comboBox.isEditable()) {
0N/A result.width = 100;
0N/A }
0N/A }
0N/A }
0N/A
0N/A if ( comboBox.isEditable() ) {
0N/A Dimension d = editor.getPreferredSize();
0N/A result.width = Math.max(result.width,d.width);
0N/A result.height = Math.max(result.height,d.height);
0N/A }
0N/A
1173N/A // calculate in the padding
1173N/A if (padding != null) {
1173N/A result.width += padding.left + padding.right;
1173N/A result.height += padding.top + padding.bottom;
1173N/A }
1173N/A
0N/A // Set the cached value
0N/A cachedDisplaySize.setSize(result.width, result.height);
0N/A isDisplaySizeDirty = false;
0N/A
0N/A return result;
0N/A }
0N/A
0N/A /**
1999N/A * Returns the size a component would have if used as a cell renderer.
1999N/A *
1999N/A * @param comp a {@code Component} to check
1999N/A * @return size of the component
1999N/A * @since 1.7
0N/A */
1999N/A protected Dimension getSizeForComponent(Component comp) {
1999N/A // This has been refactored out in hopes that it may be investigated and
1999N/A // simplified for the next major release. adding/removing
1999N/A // the component to the currentValuePane and changing the font may be
1999N/A // redundant operations.
0N/A currentValuePane.add(comp);
0N/A comp.setFont(comboBox.getFont());
0N/A Dimension d = comp.getPreferredSize();
0N/A currentValuePane.remove(comp);
0N/A return d;
0N/A }
0N/A
0N/A
0N/A //
0N/A // end Size Utility Methods
0N/A //=============================
0N/A
0N/A
0N/A //=================================
0N/A // begin Keyboard Action Management
0N/A //
0N/A
0N/A /**
0N/A * Adds keyboard actions to the JComboBox. Actions on enter and esc are already
0N/A * supplied. Add more actions as you need them.
0N/A */
0N/A protected void installKeyboardActions() {
0N/A InputMap km = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
0N/A SwingUtilities.replaceUIInputMap(comboBox, JComponent.
0N/A WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, km);
0N/A
0N/A
0N/A LazyActionMap.installLazyActionMap(comboBox, BasicComboBoxUI.class,
0N/A "ComboBox.actionMap");
0N/A }
0N/A
0N/A InputMap getInputMap(int condition) {
0N/A if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
0N/A return (InputMap)DefaultLookup.get(comboBox, this,
0N/A "ComboBox.ancestorInputMap");
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A boolean isTableCellEditor() {
0N/A return isTableCellEditor;
0N/A }
0N/A
0N/A /**
0N/A * Removes the focus InputMap and ActionMap.
0N/A */
0N/A protected void uninstallKeyboardActions() {
0N/A SwingUtilities.replaceUIInputMap(comboBox, JComponent.
0N/A WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
0N/A SwingUtilities.replaceUIActionMap(comboBox, null);
0N/A }
0N/A
0N/A
0N/A //
0N/A // Actions
0N/A //
0N/A private static class Actions extends UIAction {
0N/A private static final String HIDE = "hidePopup";
0N/A private static final String DOWN = "selectNext";
0N/A private static final String DOWN_2 = "selectNext2";
0N/A private static final String TOGGLE = "togglePopup";
0N/A private static final String TOGGLE_2 = "spacePopup";
0N/A private static final String UP = "selectPrevious";
0N/A private static final String UP_2 = "selectPrevious2";
0N/A private static final String ENTER = "enterPressed";
0N/A private static final String PAGE_DOWN = "pageDownPassThrough";
0N/A private static final String PAGE_UP = "pageUpPassThrough";
0N/A private static final String HOME = "homePassThrough";
0N/A private static final String END = "endPassThrough";
0N/A
0N/A Actions(String name) {
0N/A super(name);
0N/A }
0N/A
0N/A public void actionPerformed( ActionEvent e ) {
0N/A String key = getName();
0N/A JComboBox comboBox = (JComboBox)e.getSource();
0N/A BasicComboBoxUI ui = (BasicComboBoxUI)BasicLookAndFeel.getUIOfType(
0N/A comboBox.getUI(), BasicComboBoxUI.class);
0N/A if (key == HIDE) {
0N/A comboBox.firePopupMenuCanceled();
0N/A comboBox.setPopupVisible(false);
0N/A }
0N/A else if (key == PAGE_DOWN || key == PAGE_UP ||
0N/A key == HOME || key == END) {
0N/A int index = getNextIndex(comboBox, key);
0N/A if (index >= 0 && index < comboBox.getItemCount()) {
5822N/A if (UIManager.getBoolean("ComboBox.noActionOnKeyNavigation") && comboBox.isPopupVisible()) {
5822N/A ui.listBox.setSelectedIndex(index);
5822N/A ui.listBox.ensureIndexIsVisible(index);
5822N/A comboBox.repaint();
5822N/A } else {
5822N/A comboBox.setSelectedIndex(index);
5822N/A }
0N/A }
0N/A }
0N/A else if (key == DOWN) {
0N/A if (comboBox.isShowing() ) {
0N/A if ( comboBox.isPopupVisible() ) {
0N/A if (ui != null) {
0N/A ui.selectNextPossibleValue();
0N/A }
0N/A } else {
0N/A comboBox.setPopupVisible(true);
0N/A }
0N/A }
0N/A }
0N/A else if (key == DOWN_2) {
0N/A // Special case in which pressing the arrow keys will not
0N/A // make the popup appear - except for editable combo boxes
0N/A // and combo boxes inside a table.
0N/A if (comboBox.isShowing() ) {
0N/A if ( (comboBox.isEditable() ||
0N/A (ui != null && ui.isTableCellEditor()))
0N/A && !comboBox.isPopupVisible() ) {
0N/A comboBox.setPopupVisible(true);
0N/A } else {
0N/A if (ui != null) {
0N/A ui.selectNextPossibleValue();
0N/A }
0N/A }
0N/A }
0N/A }
0N/A else if (key == TOGGLE || key == TOGGLE_2) {
0N/A if (ui != null && (key == TOGGLE || !comboBox.isEditable())) {
0N/A if ( ui.isTableCellEditor() ) {
0N/A // Forces the selection of the list item if the
0N/A // combo box is in a JTable.
0N/A comboBox.setSelectedIndex(ui.popup.getList().
0N/A getSelectedIndex());
0N/A }
0N/A else {
0N/A comboBox.setPopupVisible(!comboBox.isPopupVisible());
0N/A }
0N/A }
0N/A }
0N/A else if (key == UP) {
0N/A if (ui != null) {
0N/A if (ui.isPopupVisible(comboBox)) {
0N/A ui.selectPreviousPossibleValue();
0N/A }
0N/A else if (DefaultLookup.getBoolean(comboBox, ui,
0N/A "ComboBox.showPopupOnNavigation", false)) {
0N/A ui.setPopupVisible(comboBox, true);
0N/A }
0N/A }
0N/A }
0N/A else if (key == UP_2) {
0N/A // Special case in which pressing the arrow keys will not
0N/A // make the popup appear - except for editable combo boxes.
0N/A if (comboBox.isShowing() && ui != null) {
0N/A if ( comboBox.isEditable() && !comboBox.isPopupVisible()) {
0N/A comboBox.setPopupVisible(true);
0N/A } else {
0N/A ui.selectPreviousPossibleValue();
0N/A }
0N/A }
0N/A }
0N/A
0N/A else if (key == ENTER) {
0N/A if (comboBox.isPopupVisible()) {
5822N/A // If ComboBox.noActionOnKeyNavigation is set,
5822N/A // forse selection of list item
5822N/A if (UIManager.getBoolean("ComboBox.noActionOnKeyNavigation")) {
0N/A Object listItem = ui.popup.getList().getSelectedValue();
0N/A if (listItem != null) {
0N/A comboBox.getEditor().setItem(listItem);
608N/A comboBox.setSelectedItem(listItem);
0N/A }
5822N/A comboBox.setPopupVisible(false);
5822N/A } else {
5822N/A // Forces the selection of the list item
5822N/A boolean isEnterSelectablePopup =
5822N/A UIManager.getBoolean("ComboBox.isEnterSelectablePopup");
5822N/A if (!comboBox.isEditable() || isEnterSelectablePopup
5822N/A || ui.isTableCellEditor) {
5822N/A Object listItem = ui.popup.getList().getSelectedValue();
5822N/A if (listItem != null) {
5822N/A // Use the selected value from popup
5822N/A // to set the selected item in combo box,
5822N/A // but ensure before that JComboBox.actionPerformed()
5822N/A // won't use editor's value to set the selected item
5822N/A comboBox.getEditor().setItem(listItem);
5822N/A comboBox.setSelectedItem(listItem);
5822N/A }
5822N/A }
5822N/A comboBox.setPopupVisible(false);
0N/A }
0N/A }
0N/A else {
608N/A // Hide combo box if it is a table cell editor
608N/A if (ui.isTableCellEditor && !comboBox.isEditable()) {
608N/A comboBox.setSelectedItem(comboBox.getSelectedItem());
608N/A }
0N/A // Call the default button binding.
0N/A // This is a pretty messy way of passing an event through
0N/A // to the root pane.
0N/A JRootPane root = SwingUtilities.getRootPane(comboBox);
0N/A if (root != null) {
0N/A InputMap im = root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
0N/A ActionMap am = root.getActionMap();
0N/A if (im != null && am != null) {
0N/A Object obj = im.get(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0));
0N/A if (obj != null) {
0N/A Action action = am.get(obj);
0N/A if (action != null) {
0N/A action.actionPerformed(new ActionEvent(
0N/A root, e.getID(), e.getActionCommand(),
0N/A e.getWhen(), e.getModifiers()));
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A private int getNextIndex(JComboBox comboBox, String key) {
5822N/A int listHeight = comboBox.getMaximumRowCount();
5822N/A
5822N/A int selectedIndex = comboBox.getSelectedIndex();
5822N/A if (UIManager.getBoolean("ComboBox.noActionOnKeyNavigation")
5822N/A && (comboBox.getUI() instanceof BasicComboBoxUI)) {
5822N/A selectedIndex = ((BasicComboBoxUI) comboBox.getUI()).listBox.getSelectedIndex();
5822N/A }
5822N/A
0N/A if (key == PAGE_UP) {
5822N/A int index = selectedIndex - listHeight;
0N/A return (index < 0 ? 0: index);
0N/A }
0N/A else if (key == PAGE_DOWN) {
5822N/A int index = selectedIndex + listHeight;
0N/A int max = comboBox.getItemCount();
0N/A return (index < max ? index: max-1);
0N/A }
0N/A else if (key == HOME) {
0N/A return 0;
0N/A }
0N/A else if (key == END) {
0N/A return comboBox.getItemCount() - 1;
0N/A }
0N/A return comboBox.getSelectedIndex();
0N/A }
0N/A
0N/A public boolean isEnabled(Object c) {
0N/A if (getName() == HIDE) {
0N/A return (c != null && ((JComboBox)c).isPopupVisible());
0N/A }
0N/A return true;
0N/A }
0N/A }
0N/A //
0N/A // end Keyboard Action Management
0N/A //===============================
0N/A
0N/A
0N/A //
0N/A // Shared Handler, implements all listeners
0N/A //
0N/A private class Handler implements ActionListener, FocusListener,
0N/A KeyListener, LayoutManager,
0N/A ListDataListener, PropertyChangeListener {
0N/A //
0N/A // PropertyChangeListener
0N/A //
0N/A public void propertyChange(PropertyChangeEvent e) {
0N/A String propertyName = e.getPropertyName();
1173N/A if (e.getSource() == editor){
1173N/A // If the border of the editor changes then this can effect
1173N/A // the size of the editor which can cause the combo's size to
1173N/A // become invalid so we need to clear size caches
1173N/A if ("border".equals(propertyName)){
1173N/A isMinimumSizeDirty = true;
1173N/A isDisplaySizeDirty = true;
1173N/A comboBox.revalidate();
0N/A }
1173N/A } else {
1173N/A JComboBox comboBox = (JComboBox)e.getSource();
1173N/A if ( propertyName == "model" ) {
1173N/A ComboBoxModel newModel = (ComboBoxModel)e.getNewValue();
1173N/A ComboBoxModel oldModel = (ComboBoxModel)e.getOldValue();
0N/A
1173N/A if ( oldModel != null && listDataListener != null ) {
1173N/A oldModel.removeListDataListener( listDataListener );
1173N/A }
1173N/A
1173N/A if ( newModel != null && listDataListener != null ) {
1173N/A newModel.addListDataListener( listDataListener );
1173N/A }
0N/A
1173N/A if ( editor != null ) {
1173N/A comboBox.configureEditor( comboBox.getEditor(), comboBox.getSelectedItem() );
1173N/A }
1173N/A isMinimumSizeDirty = true;
1173N/A isDisplaySizeDirty = true;
1173N/A comboBox.revalidate();
1173N/A comboBox.repaint();
1173N/A }
1173N/A else if ( propertyName == "editor" && comboBox.isEditable() ) {
1173N/A addEditor();
1173N/A comboBox.revalidate();
1173N/A }
1173N/A else if ( propertyName == "editable" ) {
1173N/A if ( comboBox.isEditable() ) {
1173N/A comboBox.setRequestFocusEnabled( false );
1173N/A addEditor();
1173N/A } else {
1173N/A comboBox.setRequestFocusEnabled( true );
1173N/A removeEditor();
1173N/A }
1173N/A updateToolTipTextForChildren();
1173N/A comboBox.revalidate();
1173N/A }
1173N/A else if ( propertyName == "enabled" ) {
1173N/A boolean enabled = comboBox.isEnabled();
1173N/A if ( editor != null )
1173N/A editor.setEnabled(enabled);
1173N/A if ( arrowButton != null )
1173N/A arrowButton.setEnabled(enabled);
1173N/A comboBox.repaint();
0N/A }
1173N/A else if ( propertyName == "focusable" ) {
1173N/A boolean focusable = comboBox.isFocusable();
1173N/A if ( editor != null )
1173N/A editor.setFocusable(focusable);
1173N/A if ( arrowButton != null )
1173N/A arrowButton.setFocusable(focusable);
1173N/A comboBox.repaint();
1173N/A }
1173N/A else if ( propertyName == "maximumRowCount" ) {
1173N/A if ( isPopupVisible( comboBox ) ) {
1173N/A setPopupVisible(comboBox, false);
1173N/A setPopupVisible(comboBox, true);
1173N/A }
0N/A }
1173N/A else if ( propertyName == "font" ) {
1173N/A listBox.setFont( comboBox.getFont() );
1173N/A if ( editor != null ) {
1173N/A editor.setFont( comboBox.getFont() );
1173N/A }
1173N/A isMinimumSizeDirty = true;
3456N/A isDisplaySizeDirty = true;
1173N/A comboBox.validate();
1173N/A }
1173N/A else if ( propertyName == JComponent.TOOL_TIP_TEXT_KEY ) {
1173N/A updateToolTipTextForChildren();
1173N/A }
1173N/A else if ( propertyName == BasicComboBoxUI.IS_TABLE_CELL_EDITOR ) {
1173N/A Boolean inTable = (Boolean)e.getNewValue();
1173N/A isTableCellEditor = inTable.equals(Boolean.TRUE) ? true : false;
1173N/A }
1173N/A else if (propertyName == "prototypeDisplayValue") {
1173N/A isMinimumSizeDirty = true;
1173N/A isDisplaySizeDirty = true;
1173N/A comboBox.revalidate();
1173N/A }
1173N/A else if (propertyName == "renderer") {
1173N/A isMinimumSizeDirty = true;
1173N/A isDisplaySizeDirty = true;
1173N/A comboBox.revalidate();
1173N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A //
0N/A // KeyListener
0N/A //
0N/A
0N/A // This listener checks to see if the key event isn't a navigation
0N/A // key. If it finds a key event that wasn't a navigation key it
0N/A // dispatches it to JComboBox.selectWithKeyChar() so that it can do
0N/A // type-ahead.
0N/A public void keyPressed( KeyEvent e ) {
0N/A if ( isNavigationKey(e.getKeyCode(), e.getModifiers()) ) {
0N/A lastTime = 0L;
0N/A } else if ( comboBox.isEnabled() && comboBox.getModel().getSize()!=0 &&
0N/A isTypeAheadKey( e ) && e.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
0N/A time = e.getWhen();
0N/A if ( comboBox.selectWithKeyChar(e.getKeyChar()) ) {
0N/A e.consume();
0N/A }
0N/A }
0N/A }
0N/A
0N/A public void keyTyped(KeyEvent e) {
0N/A }
0N/A
0N/A public void keyReleased(KeyEvent e) {
0N/A }
0N/A
0N/A private boolean isTypeAheadKey( KeyEvent e ) {
1735N/A return !e.isAltDown() && !BasicGraphicsUtils.isMenuShortcutKeyDown(e);
0N/A }
0N/A
0N/A //
0N/A // FocusListener
0N/A //
0N/A // NOTE: The class is added to both the Editor and ComboBox.
0N/A // The combo box listener hides the popup when the focus is lost.
0N/A // It also repaints when focus is gained or lost.
0N/A
0N/A public void focusGained( FocusEvent e ) {
0N/A ComboBoxEditor comboBoxEditor = comboBox.getEditor();
0N/A
0N/A if ( (comboBoxEditor != null) &&
0N/A (e.getSource() == comboBoxEditor.getEditorComponent()) ) {
0N/A return;
0N/A }
0N/A hasFocus = true;
0N/A comboBox.repaint();
0N/A
0N/A if (comboBox.isEditable() && editor != null) {
0N/A editor.requestFocus();
0N/A }
0N/A }
0N/A
0N/A public void focusLost( FocusEvent e ) {
0N/A ComboBoxEditor editor = comboBox.getEditor();
0N/A if ( (editor != null) &&
0N/A (e.getSource() == editor.getEditorComponent()) ) {
0N/A Object item = editor.getItem();
0N/A
0N/A Object selectedItem = comboBox.getSelectedItem();
0N/A if (!e.isTemporary() && item != null &&
0N/A !item.equals((selectedItem == null) ? "" : selectedItem )) {
0N/A comboBox.actionPerformed
0N/A (new ActionEvent(editor, 0, "",
0N/A EventQueue.getMostRecentEventTime(), 0));
0N/A }
0N/A }
0N/A
0N/A hasFocus = false;
0N/A if (!e.isTemporary()) {
0N/A setPopupVisible(comboBox, false);
0N/A }
0N/A comboBox.repaint();
0N/A }
0N/A
0N/A //
0N/A // ListDataListener
0N/A //
0N/A
0N/A // This listener watches for changes in the ComboBoxModel
0N/A public void contentsChanged( ListDataEvent e ) {
0N/A if ( !(e.getIndex0() == -1 && e.getIndex1() == -1) ) {
0N/A isMinimumSizeDirty = true;
0N/A comboBox.revalidate();
0N/A }
0N/A
0N/A // set the editor with the selected item since this
0N/A // is the event handler for a selected item change.
0N/A if (comboBox.isEditable() && editor != null) {
0N/A comboBox.configureEditor( comboBox.getEditor(),
0N/A comboBox.getSelectedItem() );
0N/A }
0N/A
0N/A isDisplaySizeDirty = true;
0N/A comboBox.repaint();
0N/A }
0N/A
0N/A public void intervalAdded( ListDataEvent e ) {
0N/A contentsChanged( e );
0N/A }
0N/A
0N/A public void intervalRemoved( ListDataEvent e ) {
0N/A contentsChanged( e );
0N/A }
0N/A
0N/A //
0N/A // LayoutManager
0N/A //
0N/A
0N/A // This layout manager handles the 'standard' layout of combo boxes.
0N/A // It puts the arrow button to the right and the editor to the left.
0N/A // If there is no editor it still keeps the arrow button to the right.
0N/A public void addLayoutComponent(String name, Component comp) {}
0N/A
0N/A public void removeLayoutComponent(Component comp) {}
0N/A
0N/A public Dimension preferredLayoutSize(Container parent) {
0N/A return parent.getPreferredSize();
0N/A }
0N/A
0N/A public Dimension minimumLayoutSize(Container parent) {
0N/A return parent.getMinimumSize();
0N/A }
0N/A
0N/A public void layoutContainer(Container parent) {
0N/A JComboBox cb = (JComboBox)parent;
0N/A int width = cb.getWidth();
0N/A int height = cb.getHeight();
0N/A
0N/A Insets insets = getInsets();
1173N/A int buttonHeight = height - (insets.top + insets.bottom);
1173N/A int buttonWidth = buttonHeight;
1173N/A if (arrowButton != null) {
1173N/A Insets arrowInsets = arrowButton.getInsets();
1173N/A buttonWidth = squareButton ?
1173N/A buttonHeight :
1173N/A arrowButton.getPreferredSize().width + arrowInsets.left + arrowInsets.right;
1173N/A }
0N/A Rectangle cvb;
0N/A
1173N/A if (arrowButton != null) {
1173N/A if (BasicGraphicsUtils.isLeftToRight(cb)) {
1173N/A arrowButton.setBounds(width - (insets.right + buttonWidth),
1173N/A insets.top, buttonWidth, buttonHeight);
1173N/A } else {
1173N/A arrowButton.setBounds(insets.left, insets.top,
1173N/A buttonWidth, buttonHeight);
0N/A }
0N/A }
0N/A if ( editor != null ) {
0N/A cvb = rectangleForCurrentValue();
0N/A editor.setBounds(cvb);
0N/A }
0N/A }
0N/A
0N/A //
0N/A // ActionListener
0N/A //
0N/A // Fix for 4515752: Forward the Enter pressed on the
0N/A // editable combo box to the default button
0N/A
0N/A // Note: This could depend on event ordering. The first ActionEvent
0N/A // from the editor may be handled by the JComboBox in which case, the
0N/A // enterPressed action will always be invoked.
0N/A public void actionPerformed(ActionEvent evt) {
0N/A Object item = comboBox.getEditor().getItem();
0N/A if (item != null) {
0N/A if(!comboBox.isPopupVisible() && !item.equals(comboBox.getSelectedItem())) {
0N/A comboBox.setSelectedItem(comboBox.getEditor().getItem());
0N/A }
0N/A ActionMap am = comboBox.getActionMap();
0N/A if (am != null) {
0N/A Action action = am.get("enterPressed");
0N/A if (action != null) {
0N/A action.actionPerformed(new ActionEvent(comboBox, evt.getID(),
0N/A evt.getActionCommand(),
0N/A evt.getModifiers()));
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A class DefaultKeySelectionManager implements JComboBox.KeySelectionManager, UIResource {
0N/A private String prefix = "";
0N/A private String typedString = "";
0N/A
0N/A public int selectionForKey(char aKey,ComboBoxModel aModel) {
0N/A if (lastTime == 0L) {
0N/A prefix = "";
0N/A typedString = "";
0N/A }
0N/A boolean startingFromSelection = true;
0N/A
0N/A int startIndex = comboBox.getSelectedIndex();
0N/A if (time - lastTime < timeFactor) {
0N/A typedString += aKey;
0N/A if((prefix.length() == 1) && (aKey == prefix.charAt(0))) {
0N/A // Subsequent same key presses move the keyboard focus to the next
0N/A // object that starts with the same letter.
0N/A startIndex++;
0N/A } else {
0N/A prefix = typedString;
0N/A }
0N/A } else {
0N/A startIndex++;
0N/A typedString = "" + aKey;
0N/A prefix = typedString;
0N/A }
0N/A lastTime = time;
0N/A
0N/A if (startIndex < 0 || startIndex >= aModel.getSize()) {
0N/A startingFromSelection = false;
0N/A startIndex = 0;
0N/A }
0N/A int index = listBox.getNextMatch(prefix, startIndex,
0N/A Position.Bias.Forward);
0N/A if (index < 0 && startingFromSelection) { // wrap
0N/A index = listBox.getNextMatch(prefix, 0,
0N/A Position.Bias.Forward);
0N/A }
0N/A return index;
0N/A }
0N/A }
0N/A
0N/A}