Merge from mainline
[official-gcc.git] / libjava / classpath / javax / swing / plaf / basic / BasicComboBoxUI.java
blob288a8d89f7eaf555600425e44515c4f218951f5f
1 /* BasicComboBoxUI.java --
2 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.plaf.basic;
41 import java.awt.Color;
42 import java.awt.Component;
43 import java.awt.Container;
44 import java.awt.Dimension;
45 import java.awt.Font;
46 import java.awt.FontMetrics;
47 import java.awt.Graphics;
48 import java.awt.Insets;
49 import java.awt.LayoutManager;
50 import java.awt.Rectangle;
51 import java.awt.event.FocusEvent;
52 import java.awt.event.FocusListener;
53 import java.awt.event.ItemEvent;
54 import java.awt.event.ItemListener;
55 import java.awt.event.KeyAdapter;
56 import java.awt.event.KeyEvent;
57 import java.awt.event.KeyListener;
58 import java.awt.event.MouseAdapter;
59 import java.awt.event.MouseEvent;
60 import java.awt.event.MouseListener;
61 import java.awt.event.MouseMotionListener;
62 import java.beans.PropertyChangeEvent;
63 import java.beans.PropertyChangeListener;
65 import javax.accessibility.Accessible;
66 import javax.swing.CellRendererPane;
67 import javax.swing.ComboBoxEditor;
68 import javax.swing.ComboBoxModel;
69 import javax.swing.JButton;
70 import javax.swing.JComboBox;
71 import javax.swing.JComponent;
72 import javax.swing.JList;
73 import javax.swing.ListCellRenderer;
74 import javax.swing.LookAndFeel;
75 import javax.swing.SwingUtilities;
76 import javax.swing.UIManager;
77 import javax.swing.event.ListDataEvent;
78 import javax.swing.event.ListDataListener;
79 import javax.swing.plaf.ComboBoxUI;
80 import javax.swing.plaf.ComponentUI;
81 import javax.swing.plaf.UIResource;
83 /**
84 * A UI delegate for the {@link JComboBox} component.
86 * @author Olga Rodimina
87 * @author Robert Schuster
89 public class BasicComboBoxUI extends ComboBoxUI
91 /**
92 * The arrow button that is displayed in the right side of JComboBox. This
93 * button is used to hide and show combo box's list of items.
95 protected JButton arrowButton;
97 /**
98 * The combo box represented by this UI delegate.
100 protected JComboBox comboBox;
103 * The component that is responsible for displaying/editing the selected
104 * item of the combo box.
106 * @see BasicComboBoxEditor#getEditorComponent()
108 protected Component editor;
111 * A listener listening to focus events occurring in the {@link JComboBox}.
113 protected FocusListener focusListener;
116 * A flag indicating whether JComboBox currently has the focus.
118 protected boolean hasFocus;
121 * A listener listening to item events fired by the {@link JComboBox}.
123 protected ItemListener itemListener;
126 * A listener listening to key events that occur while {@link JComboBox} has
127 * the focus.
129 protected KeyListener keyListener;
132 * A listener listening to mouse events occuring in the {@link JComboBox}.
134 private MouseListener mouseListener;
137 * List used when rendering selected item of the combo box. The selection
138 * and foreground colors for combo box renderer are configured from this
139 * list.
141 protected JList listBox;
144 * ListDataListener listening to JComboBox model
146 protected ListDataListener listDataListener;
149 * Popup list containing the combo box's menu items.
151 protected ComboPopup popup;
153 protected KeyListener popupKeyListener;
155 protected MouseListener popupMouseListener;
157 protected MouseMotionListener popupMouseMotionListener;
160 * Listener listening to changes in the bound properties of JComboBox
162 protected PropertyChangeListener propertyChangeListener;
164 /**
165 * The button background.
166 * @see #installDefaults()
168 private Color buttonBackground;
170 /**
171 * The button shadow.
172 * @see #installDefaults()
174 private Color buttonShadow;
177 * The button dark shadow.
178 * @see #installDefaults()
180 private Color buttonDarkShadow;
183 * The button highlight.
184 * @see #installDefaults()
186 private Color buttonHighlight;
188 /* Size of the largest item in the comboBox
189 * This is package-private to avoid an accessor method.
191 Dimension displaySize;
193 // FIXME: This field isn't used anywhere at this moment.
194 protected CellRendererPane currentValuePane;
197 * The current minimum size if isMinimumSizeDirty is false.
198 * Setup by getMinimumSize() and invalidated by the various listeners.
200 protected Dimension cachedMinimumSize;
203 * Indicates whether or not the cachedMinimumSize field is valid or not.
205 protected boolean isMinimumSizeDirty = true;
208 * Creates a new <code>BasicComboBoxUI</code> object.
210 public BasicComboBoxUI()
212 // Nothing to do here.
216 * A factory method to create a UI delegate for the given
217 * {@link JComponent}, which should be a {@link JComboBox}.
219 * @param c The {@link JComponent} a UI is being created for.
221 * @return A UI delegate for the {@link JComponent}.
223 public static ComponentUI createUI(JComponent c)
225 return new BasicComboBoxUI();
229 * Installs the UI for the given {@link JComponent}.
231 * @param c the JComponent to install a UI for.
233 * @see #uninstallUI(JComponent)
235 public void installUI(JComponent c)
237 super.installUI(c);
239 if (c instanceof JComboBox)
241 comboBox = (JComboBox) c;
242 comboBox.setOpaque(true);
243 comboBox.setLayout(createLayoutManager());
244 installDefaults();
245 installComponents();
246 installListeners();
247 installKeyboardActions();
252 * Uninstalls the UI for the given {@link JComponent}.
254 * @param c The JComponent that is having this UI removed.
256 * @see #installUI(JComponent)
258 public void uninstallUI(JComponent c)
260 uninstallKeyboardActions();
261 uninstallListeners();
262 uninstallComponents();
263 uninstallDefaults();
264 comboBox = null;
268 * Installs the defaults that are defined in the {@link BasicLookAndFeel}
269 * for this {@link JComboBox}.
271 * @see #uninstallDefaults()
273 protected void installDefaults()
275 LookAndFeel.installColorsAndFont(comboBox, "ComboBox.background",
276 "ComboBox.foreground", "ComboBox.font");
278 // fetch the button color scheme
279 buttonBackground = UIManager.getColor("ComboBox.buttonBackground");
280 buttonShadow = UIManager.getColor("ComboBox.buttonShadow");
281 buttonDarkShadow = UIManager.getColor("ComboBox.buttonDarkShadow");
282 buttonHighlight = UIManager.getColor("ComboBox.buttonHighlight");
286 * Creates and installs the listeners for this UI.
288 * @see #uninstallListeners()
290 protected void installListeners()
292 // install combo box's listeners
293 propertyChangeListener = createPropertyChangeListener();
294 comboBox.addPropertyChangeListener(propertyChangeListener);
296 focusListener = createFocusListener();
297 editor.addFocusListener(focusListener);
299 itemListener = createItemListener();
300 comboBox.addItemListener(itemListener);
302 keyListener = createKeyListener();
303 comboBox.addKeyListener(keyListener);
305 mouseListener = createMouseListener();
306 arrowButton.addMouseListener(mouseListener);
308 // install listeners that listen to combo box model
309 listDataListener = createListDataListener();
310 comboBox.getModel().addListDataListener(listDataListener);
314 * Uninstalls the defaults and sets any objects created during
315 * install to <code>null</code>.
317 * @see #installDefaults()
319 protected void uninstallDefaults()
321 if (comboBox.getFont() instanceof UIResource)
322 comboBox.setFont(null);
324 if (comboBox.getForeground() instanceof UIResource)
325 comboBox.setForeground(null);
327 if (comboBox.getBackground() instanceof UIResource)
328 comboBox.setBackground(null);
330 buttonBackground = null;
331 buttonShadow = null;
332 buttonDarkShadow = null;
333 buttonHighlight = null;
337 * Detaches all the listeners we attached in {@link #installListeners}.
339 * @see #installListeners()
341 protected void uninstallListeners()
343 comboBox.removePropertyChangeListener(propertyChangeListener);
344 propertyChangeListener = null;
346 comboBox.removeFocusListener(focusListener);
347 listBox.removeFocusListener(focusListener);
348 focusListener = null;
350 comboBox.removeItemListener(itemListener);
351 itemListener = null;
353 comboBox.removeKeyListener(keyListener);
354 keyListener = null;
356 arrowButton.removeMouseListener(mouseListener);
357 mouseListener = null;
359 comboBox.getModel().removeListDataListener(listDataListener);
360 listDataListener = null;
364 * Creates the popup that will contain list of combo box's items.
366 * @return popup containing list of combo box's items
368 protected ComboPopup createPopup()
370 return new BasicComboPopup(comboBox);
374 * Creates a {@link KeyListener} to listen to key events.
376 * @return KeyListener that listens to key events.
378 protected KeyListener createKeyListener()
380 return new KeyHandler();
384 * Creates a {@link MouseListener} that will listen to mouse events occurring
385 * in the combo box.
387 * @return the MouseListener
389 private MouseListener createMouseListener()
391 return new MouseHandler();
395 * Creates the {@link FocusListener} that will listen to changes in this
396 * JComboBox's focus.
398 * @return the FocusListener.
400 protected FocusListener createFocusListener()
402 return new FocusHandler();
406 * Creates a {@link ListDataListener} to listen to the combo box's data model.
408 * @return The new listener.
410 protected ListDataListener createListDataListener()
412 return new ListDataHandler();
416 * Creates an {@link ItemListener} that will listen to the changes in
417 * the JComboBox's selection.
419 * @return The ItemListener
421 protected ItemListener createItemListener()
423 return new ItemHandler();
427 * Creates a {@link PropertyChangeListener} to listen to the changes in
428 * the JComboBox's bound properties.
430 * @return The PropertyChangeListener
432 protected PropertyChangeListener createPropertyChangeListener()
434 return new PropertyChangeHandler();
438 * Creates and returns a layout manager for the combo box. Subclasses can
439 * override this method to provide a different layout.
441 * @return a layout manager for the combo box.
443 protected LayoutManager createLayoutManager()
445 return new ComboBoxLayoutManager();
449 * Creates a component that will be responsible for rendering the
450 * selected component in the combo box.
452 * @return A renderer for the combo box.
454 protected ListCellRenderer createRenderer()
456 return new BasicComboBoxRenderer();
460 * Creates the component that will be responsible for displaying/editing
461 * the selected item in the combo box. This editor is used only when combo
462 * box is editable.
464 * @return A new component that will be responsible for displaying/editing
465 * the selected item in the combo box.
467 protected ComboBoxEditor createEditor()
469 return new BasicComboBoxEditor.UIResource();
473 * Installs the components for this JComboBox. ArrowButton, main
474 * part of combo box (upper part) and popup list of items are created and
475 * configured here.
477 protected void installComponents()
479 // create drop down list of items
480 popup = createPopup();
481 listBox = popup.getList();
483 // set editor and renderer for the combo box. Editor is used
484 // only if combo box becomes editable, otherwise renderer is used
485 // to paint the selected item; combobox is not editable by default.
486 comboBox.setRenderer(createRenderer());
488 // create and install arrow button
489 arrowButton = createArrowButton();
490 configureArrowButton();
491 comboBox.add(arrowButton);
493 ComboBoxEditor currentEditor = comboBox.getEditor();
494 if (currentEditor == null || currentEditor instanceof UIResource)
496 currentEditor = createEditor();
497 comboBox.setEditor(currentEditor);
499 editor = currentEditor.getEditorComponent();
501 comboBox.revalidate();
505 * Uninstalls components from this {@link JComboBox}.
507 * @see #installComponents()
509 protected void uninstallComponents()
511 // uninstall arrow button
512 unconfigureArrowButton();
513 comboBox.remove(arrowButton);
514 arrowButton = null;
516 listBox = null;
517 popup = null;
519 comboBox.setRenderer(null);
521 // if the editor is not an instanceof UIResource, it was not set by the
522 // UI delegate, so don't clear it...
523 ComboBoxEditor currentEditor = comboBox.getEditor();
524 if (currentEditor instanceof UIResource)
526 comboBox.setEditor(null);
527 editor = null;
532 * Adds the current editor to the combo box.
534 public void addEditor()
536 comboBox.add(editor);
540 * Removes the current editor from the combo box.
542 public void removeEditor()
544 comboBox.remove(editor);
548 * Configures the editor for this combo box.
550 protected void configureEditor()
552 editor.setFont(comboBox.getFont());
553 comboBox.getEditor().setItem(comboBox.getSelectedItem());
554 // FIXME: Need to implement. Set font and add listeners.
558 * Unconfigures the editor for this combo nox. This method is not implemented.
560 protected void unconfigureEditor()
562 // FIXME: Need to implement
566 * Configures the arrow button.
568 * @see #configureArrowButton()
570 public void configureArrowButton()
572 arrowButton.setEnabled(comboBox.isEnabled());
573 arrowButton.setFont(comboBox.getFont());
574 arrowButton.setFocusable(false);
578 * Unconfigures the arrow button.
580 * @see #configureArrowButton()
582 * @specnote The specification says this method is implementation specific
583 * and should not be used or overridden.
585 public void unconfigureArrowButton()
587 // Nothing to do here yet.
591 * Creates an arrow button for this {@link JComboBox}. The arrow button is
592 * displayed at the right end of the combo box and is used to display/hide
593 * the drop down list of items.
595 * @return A new button.
597 protected JButton createArrowButton()
599 return new BasicArrowButton(BasicArrowButton.SOUTH, buttonBackground,
600 buttonShadow, buttonDarkShadow, buttonHighlight);
604 * Returns <code>true</code> if the popup is visible, and <code>false</code>
605 * otherwise.
607 * @param c The JComboBox to check
609 * @return <code>true</code> if popup part of the JComboBox is visible and
610 * <code>false</code> otherwise.
612 public boolean isPopupVisible(JComboBox c)
614 return popup.isVisible();
618 * Displays/hides the {@link JComboBox}'s list of items on the screen.
620 * @param c The combo box, for which list of items should be
621 * displayed/hidden
622 * @param v true if show popup part of the jcomboBox and false to hide.
624 public void setPopupVisible(JComboBox c, boolean v)
626 if (v)
627 popup.show();
628 else
629 popup.hide();
631 if (comboBox.isEditable())
632 editor.requestFocus();
633 else
634 comboBox.requestFocus();
638 * JComboBox is focus traversable if it is editable and not otherwise.
640 * @param c combo box for which to check whether it is focus traversable
642 * @return true if focus tranversable and false otherwise
644 public boolean isFocusTraversable(JComboBox c)
646 if (!comboBox.isEditable())
647 return true;
649 return false;
653 * Paints given menu item using specified graphics context
655 * @param g The graphics context used to paint this combo box
656 * @param c comboBox which needs to be painted.
658 public void paint(Graphics g, JComponent c)
660 Rectangle rect = rectangleForCurrentValue();
661 paintCurrentValueBackground(g, rect, hasFocus);
662 paintCurrentValue(g, rect, hasFocus);
666 * Returns preferred size for the combo box.
668 * @param c comboBox for which to get preferred size
670 * @return The preferred size for the given combo box
672 public Dimension getPreferredSize(JComponent c)
674 // note: overriding getMinimumSize() (for example in the MetalComboBoxUI
675 // class) affects the getPreferredSize() result, so it seems logical that
676 // this method is implemented by delegating to the getMinimumSize() method
677 return getMinimumSize(c);
681 * Returns the minimum size for this {@link JComboBox} for this
682 * look and feel. Also makes sure cachedMinimimSize is setup correctly.
684 * @param c The {@link JComponent} to find the minimum size for.
686 * @return The dimensions of the minimum size.
688 public Dimension getMinimumSize(JComponent c)
690 if (isMinimumSizeDirty)
692 Dimension d = getDisplaySize();
693 int arrowButtonWidth = d.height;
694 cachedMinimumSize = new Dimension(d.width + arrowButtonWidth,
695 d.height);
696 isMinimumSizeDirty = false;
698 return new Dimension(cachedMinimumSize);
701 /** The value returned by the getMaximumSize() method. */
702 private static final Dimension MAXIMUM_SIZE = new Dimension(32767, 32767);
705 * Returns the maximum size for this {@link JComboBox} for this
706 * look and feel.
708 * @param c The {@link JComponent} to find the maximum size for
710 * @return The maximum size (<code>Dimension(32767, 32767)</code>).
712 public Dimension getMaximumSize(JComponent c)
714 return MAXIMUM_SIZE;
717 public int getAccessibleChildrenCount(JComponent c)
719 // FIXME: Need to implement
720 return 0;
723 public Accessible getAccessibleChild(JComponent c, int i)
725 // FIXME: Need to implement
726 return null;
730 * Returns true if the specified key is a navigation key and false otherwise
732 * @param keyCode a key for which to check whether it is navigation key or
733 * not.
735 * @return true if the specified key is a navigation key and false otherwis
737 protected boolean isNavigationKey(int keyCode)
739 return false;
743 * Selects next possible item relative to the current selection
744 * to be next selected item in the combo box.
746 protected void selectNextPossibleValue()
748 int index = comboBox.getSelectedIndex();
749 if (index != comboBox.getItemCount() - 1)
750 comboBox.setSelectedIndex(index + 1);
754 * Selects previous item relative to current selection to be
755 * next selected item.
757 protected void selectPreviousPossibleValue()
759 int index = comboBox.getSelectedIndex();
760 if (index != 0)
761 comboBox.setSelectedIndex(index - 1);
765 * Displays combo box popup if the popup is not currently shown
766 * on the screen and hides it if it is currently shown
768 protected void toggleOpenClose()
770 setPopupVisible(comboBox, ! isPopupVisible(comboBox));
774 * Returns the bounds in which comboBox's selected item will be
775 * displayed.
777 * @return rectangle bounds in which comboBox's selected Item will be
778 * displayed
780 protected Rectangle rectangleForCurrentValue()
782 Rectangle cbBounds = SwingUtilities.getLocalBounds(comboBox);
783 Rectangle abBounds = arrowButton.getBounds();
784 Rectangle rectForCurrentValue = new Rectangle(cbBounds.x, cbBounds.y,
785 cbBounds.width - abBounds.width, cbBounds.height);
786 return rectForCurrentValue;
790 * Returns the insets of the current border.
792 * @return Insets representing space between combo box and its border
794 protected Insets getInsets()
796 return new Insets(0, 0, 0, 0);
800 * Paints currently selected value in the main part of the combo
801 * box (part without popup).
803 * @param g graphics context
804 * @param bounds Rectangle representing the size of the area in which
805 * selected item should be drawn
806 * @param hasFocus true if combo box has focus and false otherwise
808 public void paintCurrentValue(Graphics g, Rectangle bounds, boolean hasFocus)
810 if (! comboBox.isEditable())
812 Object currentValue = comboBox.getSelectedItem();
813 boolean isPressed = arrowButton.getModel().isPressed();
815 /* Gets the component to be drawn for the current value.
816 * If there is currently no selected item we will take an empty
817 * String as replacement.
819 Component comp = comboBox.getRenderer().getListCellRendererComponent(
820 listBox, (currentValue != null ? currentValue : ""), -1,
821 isPressed, hasFocus);
822 if (! comboBox.isEnabled())
824 comp.setBackground(UIManager.getColor(
825 "ComboBox.disabledBackground"));
826 comp.setForeground(UIManager.getColor(
827 "ComboBox.disabledForeground"));
828 comp.setEnabled(false);
830 comp.setBounds(0, 0, bounds.width, bounds.height);
831 comp.setFont(comboBox.getFont());
832 comp.paint(g);
834 comboBox.revalidate();
836 else
837 comboBox.getEditor().setItem(comboBox.getSelectedItem());
841 * Paints the background of part of the combo box, where currently
842 * selected value is displayed. If the combo box has focus this method
843 * should also paint focus rectangle around the combo box.
845 * @param g graphics context
846 * @param bounds Rectangle representing the size of the largest item in the
847 * comboBox
848 * @param hasFocus true if combo box has fox and false otherwise
850 public void paintCurrentValueBackground(Graphics g, Rectangle bounds,
851 boolean hasFocus)
853 // background is painted by renderer, so it seems that nothing
854 // should be done here.
858 * Returns the default size for the display area of a combo box that does
859 * not contain any elements. This method returns the width and height of
860 * a single space in the current font, plus a margin of 1 pixel.
862 * @return The default display size.
864 * @see #getDisplaySize()
866 protected Dimension getDefaultSize()
868 // There is nothing in the spec to say how this method should be
869 // implemented...so I've done some guessing, written some Mauve tests,
870 // and written something that gives dimensions that are close to the
871 // reference implementation.
872 FontMetrics fm = comboBox.getFontMetrics(comboBox.getFont());
873 int w = fm.charWidth(' ') + 2;
874 int h = fm.getHeight() + 2;
875 return new Dimension(w, h);
879 * Returns the size of the display area for the combo box. This size will be
880 * the size of the combo box, not including the arrowButton.
882 * @return The size of the display area for the combo box.
884 protected Dimension getDisplaySize()
886 if (!comboBox.isEditable())
888 Object prototype = comboBox.getPrototypeDisplayValue();
889 if (prototype != null)
891 // calculate result based on prototype
892 ListCellRenderer renderer = comboBox.getRenderer();
893 Component comp = renderer.getListCellRendererComponent(listBox,
894 prototype, -1, false, false);
895 Dimension compSize = comp.getPreferredSize();
896 compSize.width += 2; // add 1 pixel margin around area
897 compSize.height += 2;
898 return compSize;
900 else
902 ComboBoxModel model = comboBox.getModel();
903 int numItems = model.getSize();
905 // if combo box doesn't have any items then simply
906 // return its default size
907 if (numItems == 0)
909 displaySize = getDefaultSize();
910 return displaySize;
913 Dimension size = new Dimension(0, 0);
915 // ComboBox's display size should be equal to the
916 // size of the largest item in the combo box.
917 ListCellRenderer renderer = comboBox.getRenderer();
919 for (int i = 0; i < numItems; i++)
921 Object item = model.getElementAt(i);
922 Component comp = renderer.getListCellRendererComponent(listBox,
923 item, -1, false, false);
925 Dimension compSize = comp.getPreferredSize();
926 if (compSize.width + 2 > size.width)
927 size.width = compSize.width + 2;
928 if (compSize.height + 2 > size.height)
929 size.height = compSize.height + 2;
931 displaySize = size;
932 return displaySize;
935 else // an editable combo,
937 Component comp = comboBox.getEditor().getEditorComponent();
938 Dimension prefSize = comp.getPreferredSize();
939 int width = prefSize.width;
940 int height = prefSize.height + 2;
941 Object prototype = comboBox.getPrototypeDisplayValue();
942 if (prototype != null)
944 FontMetrics fm = comboBox.getFontMetrics(comboBox.getFont());
945 width = Math.max(width, fm.stringWidth(prototype.toString()) + 2);
947 displaySize = new Dimension(width, height);
948 return displaySize;
953 * Installs the keyboard actions for the {@link JComboBox} as specified
954 * by the look and feel.
956 protected void installKeyboardActions()
958 // FIXME: Need to implement.
962 * Uninstalls the keyboard actions for the {@link JComboBox} there were
963 * installed by in {@link #installListeners}.
965 protected void uninstallKeyboardActions()
967 // FIXME: Need to implement.
971 * A {@link LayoutManager} used to position the sub-components of the
972 * {@link JComboBox}.
974 * @see BasicComboBoxUI#createLayoutManager()
976 public class ComboBoxLayoutManager implements LayoutManager
979 * Creates a new ComboBoxLayoutManager object.
981 public ComboBoxLayoutManager()
983 // Nothing to do here.
987 * Adds a component to the layout. This method does nothing, since the
988 * layout manager doesn't need to track the components.
990 * @param name the name to associate the component with (ignored).
991 * @param comp the component (ignored).
993 public void addLayoutComponent(String name, Component comp)
995 // Do nothing
999 * Removes a component from the layout. This method does nothing, since
1000 * the layout manager doesn't need to track the components.
1002 * @param comp the component.
1004 public void removeLayoutComponent(Component comp)
1006 // Do nothing
1010 * Returns preferred layout size of the JComboBox.
1012 * @param parent the Container for which the preferred size should be
1013 * calculated.
1015 * @return The preferred size for the given container
1017 public Dimension preferredLayoutSize(Container parent)
1019 return getPreferredSize((JComponent) parent);
1023 * Returns the minimum layout size.
1025 * @param parent the container.
1027 * @return The minimum size.
1029 public Dimension minimumLayoutSize(Container parent)
1031 return preferredLayoutSize(parent);
1035 * Arranges the components in the container. It puts arrow
1036 * button right end part of the comboBox. If the comboBox is editable
1037 * then editor is placed to the left of arrow button, starting from the
1038 * beginning.
1040 * @param parent Container that should be layed out.
1042 public void layoutContainer(Container parent)
1044 // Position editor component to the left of arrow button if combo box is
1045 // editable
1046 int arrowSize = comboBox.getHeight();
1047 int editorWidth = comboBox.getBounds().width - arrowSize;
1049 if (comboBox.isEditable())
1050 editor.setBounds(0, 0, editorWidth, comboBox.getBounds().height);
1052 arrowButton.setBounds(editorWidth, 0, arrowSize, arrowSize);
1053 comboBox.revalidate();
1058 * Handles focus changes occuring in the combo box. This class is
1059 * responsible for repainting combo box whenever focus is gained or lost
1060 * and also for hiding popup list of items whenever combo box loses its
1061 * focus.
1063 public class FocusHandler extends Object implements FocusListener
1066 * Creates a new FocusHandler object.
1068 public FocusHandler()
1070 // Nothing to do here.
1074 * Invoked when combo box gains focus. It repaints main
1075 * part of combo box accordingly.
1077 * @param e the FocusEvent
1079 public void focusGained(FocusEvent e)
1081 // Lets assume every change invalidates the minimumsize.
1082 isMinimumSizeDirty = true;
1084 hasFocus = true;
1085 comboBox.repaint();
1089 * Invoked when the combo box loses focus. It repaints the main part
1090 * of the combo box accordingly and hides the popup list of items.
1092 * @param e the FocusEvent
1094 public void focusLost(FocusEvent e)
1096 // Lets assume every change invalidates the minimumsize.
1097 isMinimumSizeDirty = true;
1099 hasFocus = false;
1100 setPopupVisible(comboBox, false);
1101 comboBox.repaint();
1106 * Handles {@link ItemEvent}s fired by the {@link JComboBox} when its
1107 * selected item changes.
1109 public class ItemHandler extends Object implements ItemListener
1112 * Creates a new ItemHandler object.
1114 public ItemHandler()
1116 // Nothing to do here.
1120 * Invoked when selected item becomes deselected or when
1121 * new item becomes selected.
1123 * @param e the ItemEvent representing item's state change.
1125 public void itemStateChanged(ItemEvent e)
1127 // Lets assume every change invalidates the minimumsize.
1128 isMinimumSizeDirty = true;
1130 if (e.getStateChange() == ItemEvent.SELECTED && comboBox.isEditable())
1131 comboBox.getEditor().setItem(e.getItem());
1132 comboBox.repaint();
1137 * KeyHandler handles key events occuring while JComboBox has focus.
1139 public class KeyHandler extends KeyAdapter
1141 public KeyHandler()
1143 // Nothing to do here.
1147 * Invoked whenever key is pressed while JComboBox is in focus.
1149 public void keyPressed(KeyEvent e)
1151 // FIXME: This method calls JComboBox.selectWithKeyChar if the key that was
1152 // pressed is not a navigation key.
1157 * Handles the changes occurring in the JComboBox's data model.
1159 public class ListDataHandler extends Object implements ListDataListener
1162 * Creates a new ListDataHandler object.
1164 public ListDataHandler()
1166 // Nothing to do here.
1170 * Invoked if the content's of JComboBox's data model are changed.
1172 * @param e ListDataEvent describing the change.
1174 public void contentsChanged(ListDataEvent e)
1176 // if the item is selected or deselected
1178 // Lets assume every change invalidates the minimumsize.
1179 isMinimumSizeDirty = true;
1183 * Invoked when items are added to the JComboBox's data model.
1185 * @param e ListDataEvent describing the change.
1187 public void intervalAdded(ListDataEvent e)
1189 // Lets assume every change invalidates the minimumsize.
1190 isMinimumSizeDirty = true;
1192 ComboBoxModel model = comboBox.getModel();
1193 ListCellRenderer renderer = comboBox.getRenderer();
1195 if (displaySize == null)
1196 displaySize = getDisplaySize();
1197 if (displaySize.width < getDefaultSize().width)
1198 displaySize.width = getDefaultSize().width;
1199 if (displaySize.height < getDefaultSize().height)
1200 displaySize.height = getDefaultSize().height;
1202 comboBox.repaint();
1206 * Invoked when items are removed from the JComboBox's
1207 * data model.
1209 * @param e ListDataEvent describing the change.
1211 public void intervalRemoved(ListDataEvent e)
1213 // Lets assume every change invalidates the minimumsize.
1214 isMinimumSizeDirty = true;
1216 // recalculate display size of the JComboBox.
1217 displaySize = getDisplaySize();
1218 comboBox.repaint();
1223 * Handles {@link PropertyChangeEvent}s fired by the {@link JComboBox}.
1225 public class PropertyChangeHandler extends Object
1226 implements PropertyChangeListener
1229 * Creates a new instance.
1231 public PropertyChangeHandler()
1233 // Nothing to do here.
1237 * Invoked whenever bound property of JComboBox changes.
1239 * @param e the event.
1241 public void propertyChange(PropertyChangeEvent e)
1243 // Lets assume every change invalidates the minimumsize.
1244 isMinimumSizeDirty = true;
1246 if (e.getPropertyName().equals("enabled"))
1248 arrowButton.setEnabled(comboBox.isEnabled());
1250 if (comboBox.isEditable())
1251 comboBox.getEditor().getEditorComponent().setEnabled(comboBox
1252 .isEnabled());
1254 else if (e.getPropertyName().equals("editable"))
1256 if (comboBox.isEditable())
1258 configureEditor();
1259 addEditor();
1261 else
1263 unconfigureEditor();
1264 removeEditor();
1267 comboBox.revalidate();
1268 comboBox.repaint();
1270 else if (e.getPropertyName().equals("dataModel"))
1272 // remove ListDataListener from old model and add it to new model
1273 ComboBoxModel oldModel = (ComboBoxModel) e.getOldValue();
1274 if (oldModel != null)
1275 oldModel.removeListDataListener(listDataListener);
1277 if ((ComboBoxModel) e.getNewValue() != null)
1278 comboBox.getModel().addListDataListener(listDataListener);
1280 else if (e.getPropertyName().equals("font"))
1282 Font font = (Font) e.getNewValue();
1283 editor.setFont(font);
1284 listBox.setFont(font);
1285 arrowButton.setFont(font);
1286 comboBox.revalidate();
1287 comboBox.repaint();
1290 // FIXME: Need to handle changes in other bound properties.
1295 * A handler for mouse events occurring in the combo box. An instance of
1296 * this class is returned by the <code>createMouseListener()</code> method.
1298 private class MouseHandler extends MouseAdapter
1301 * Invoked when mouse is pressed over the combo box. It toggles the
1302 * visibility of the popup list.
1304 * @param e the event
1306 public void mousePressed(MouseEvent e)
1308 if (comboBox.isEnabled())
1309 toggleOpenClose();