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)
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
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
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
;
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
;
84 * A UI delegate for the {@link JComboBox} component.
86 * @author Olga Rodimina
87 * @author Robert Schuster
89 public class BasicComboBoxUI
extends ComboBoxUI
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
;
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
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
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
;
165 * The button background.
166 * @see #installDefaults()
168 private Color buttonBackground
;
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
)
239 if (c
instanceof JComboBox
)
241 comboBox
= (JComboBox
) c
;
242 comboBox
.setOpaque(true);
243 comboBox
.setLayout(createLayoutManager());
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();
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;
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
);
353 comboBox
.removeKeyListener(keyListener
);
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
387 * @return the MouseListener
389 private MouseListener
createMouseListener()
391 return new MouseHandler();
395 * Creates the {@link FocusListener} that will listen to changes in this
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
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
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
);
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);
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>
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
622 * @param v true if show popup part of the jcomboBox and false to hide.
624 public void setPopupVisible(JComboBox c
, boolean v
)
631 if (comboBox
.isEditable())
632 editor
.requestFocus();
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())
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
,
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
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
)
717 public int getAccessibleChildrenCount(JComponent c
)
719 // FIXME: Need to implement
723 public Accessible
getAccessibleChild(JComponent c
, int i
)
725 // FIXME: Need to implement
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
735 * @return true if the specified key is a navigation key and false otherwis
737 protected boolean isNavigationKey(int keyCode
)
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();
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
777 * @return rectangle bounds in which comboBox's selected Item will be
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());
834 comboBox
.revalidate();
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
848 * @param hasFocus true if combo box has fox and false otherwise
850 public void paintCurrentValueBackground(Graphics g
, Rectangle bounds
,
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;
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
909 displaySize
= getDefaultSize();
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;
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
);
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
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
)
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
)
1010 * Returns preferred layout size of the JComboBox.
1012 * @param parent the Container for which the preferred size should be
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
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
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
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;
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;
1100 setPopupVisible(comboBox
, false);
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());
1137 * KeyHandler handles key events occuring while JComboBox has focus.
1139 public class KeyHandler
extends KeyAdapter
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
;
1206 * Invoked when items are removed from the JComboBox's
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();
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
1254 else if (e
.getPropertyName().equals("editable"))
1256 if (comboBox
.isEditable())
1263 unconfigureEditor();
1267 comboBox
.revalidate();
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();
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())