1/*
2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25package javax.swing;
26
27import java.beans.JavaBean;
28import java.beans.BeanProperty;
29import java.beans.PropertyChangeEvent;
30import java.beans.PropertyChangeListener;
31import java.beans.Transient;
32import java.util.*;
33
34import java.awt.*;
35import java.awt.event.*;
36
37import java.io.Serializable;
38import java.io.ObjectOutputStream;
39import java.io.IOException;
40
41import javax.swing.event.*;
42import javax.swing.plaf.*;
43
44import javax.accessibility.*;
45
46/**
47 * A component that combines a button or editable field and a drop-down list.
48 * The user can select a value from the drop-down list, which appears at the
49 * user's request. If you make the combo box editable, then the combo box
50 * includes an editable field into which the user can type a value.
51 * <p>
52 * <strong>Warning:</strong> Swing is not thread safe. For more
53 * information see <a
54 * href="package-summary.html#threading">Swing's Threading
55 * Policy</a>.
56 * <p>
57 * <strong>Warning:</strong>
58 * Serialized objects of this class will not be compatible with
59 * future Swing releases. The current serialization support is
60 * appropriate for short term storage or RMI between applications running
61 * the same version of Swing.  As of 1.4, support for long term storage
62 * of all JavaBeans&trade;
63 * has been added to the <code>java.beans</code> package.
64 * Please see {@link java.beans.XMLEncoder}.
65 *
66 * <p>
67 * See <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html">How to Use Combo Boxes</a>
68 * in <a href="http://docs.oracle.com/javase/tutorial/"><em>The Java Tutorial</em></a>
69 * for further information.
70 *
71 * @see ComboBoxModel
72 * @see DefaultComboBoxModel
73 *
74 * @param <E> the type of the elements of this combo box
75 *
76 * @author Arnaud Weber
77 * @author Mark Davidson
78 * @since 1.2
79 */
80@JavaBean(defaultProperty = "UI", description = "A combination of a text field and a drop-down list.")
81@SwingContainer(false)
82@SuppressWarnings("serial") // Same-version serialization only
83public class JComboBox<E> extends JComponent
84implements ItemSelectable,ListDataListener,ActionListener, Accessible {
85    /**
86     * @see #getUIClassID
87     * @see #readObject
88     */
89    private static final String uiClassID = "ComboBoxUI";
90
91    /**
92     * This protected field is implementation specific. Do not access directly
93     * or override. Use the accessor methods instead.
94     *
95     * @see #getModel
96     * @see #setModel
97     */
98    protected ComboBoxModel<E>    dataModel;
99    /**
100     * This protected field is implementation specific. Do not access directly
101     * or override. Use the accessor methods instead.
102     *
103     * @see #getRenderer
104     * @see #setRenderer
105     */
106    protected ListCellRenderer<? super E> renderer;
107    /**
108     * This protected field is implementation specific. Do not access directly
109     * or override. Use the accessor methods instead.
110     *
111     * @see #getEditor
112     * @see #setEditor
113     */
114    protected ComboBoxEditor       editor;
115    /**
116     * This protected field is implementation specific. Do not access directly
117     * or override. Use the accessor methods instead.
118     *
119     * @see #getMaximumRowCount
120     * @see #setMaximumRowCount
121     */
122    protected int maximumRowCount = 8;
123
124    /**
125     * This protected field is implementation specific. Do not access directly
126     * or override. Use the accessor methods instead.
127     *
128     * @see #isEditable
129     * @see #setEditable
130     */
131    protected boolean isEditable  = false;
132    /**
133     * This protected field is implementation specific. Do not access directly
134     * or override. Use the accessor methods instead.
135     *
136     * @see #setKeySelectionManager
137     * @see #getKeySelectionManager
138     */
139    protected KeySelectionManager keySelectionManager = null;
140    /**
141     * This protected field is implementation specific. Do not access directly
142     * or override. Use the accessor methods instead.
143     *
144     * @see #setActionCommand
145     * @see #getActionCommand
146     */
147    protected String actionCommand = "comboBoxChanged";
148    /**
149     * This protected field is implementation specific. Do not access directly
150     * or override. Use the accessor methods instead.
151     *
152     * @see #setLightWeightPopupEnabled
153     * @see #isLightWeightPopupEnabled
154     */
155    protected boolean lightWeightPopupEnabled = JPopupMenu.getDefaultLightWeightPopupEnabled();
156
157    /**
158     * This protected field is implementation specific. Do not access directly
159     * or override.
160     */
161    protected Object selectedItemReminder = null;
162
163    private E prototypeDisplayValue;
164
165    // Flag to ensure that infinite loops do not occur with ActionEvents.
166    private boolean firingActionEvent = false;
167
168    // Flag to ensure the we don't get multiple ActionEvents on item selection.
169    private boolean selectingItem = false;
170
171    // Flag to indicate UI update is in progress
172    private transient boolean updateInProgress;
173
174    /**
175     * Creates a <code>JComboBox</code> that takes its items from an
176     * existing <code>ComboBoxModel</code>.  Since the
177     * <code>ComboBoxModel</code> is provided, a combo box created using
178     * this constructor does not create a default combo box model and
179     * may impact how the insert, remove and add methods behave.
180     *
181     * @param aModel the <code>ComboBoxModel</code> that provides the
182     *          displayed list of items
183     * @see DefaultComboBoxModel
184     */
185    public JComboBox(ComboBoxModel<E> aModel) {
186        super();
187        setModel(aModel);
188        init();
189    }
190
191    /**
192     * Creates a <code>JComboBox</code> that contains the elements
193     * in the specified array.  By default the first item in the array
194     * (and therefore the data model) becomes selected.
195     *
196     * @param items  an array of objects to insert into the combo box
197     * @see DefaultComboBoxModel
198     */
199    public JComboBox(E[] items) {
200        super();
201        setModel(new DefaultComboBoxModel<E>(items));
202        init();
203    }
204
205    /**
206     * Creates a <code>JComboBox</code> that contains the elements
207     * in the specified Vector.  By default the first item in the vector
208     * (and therefore the data model) becomes selected.
209     *
210     * @param items  an array of vectors to insert into the combo box
211     * @see DefaultComboBoxModel
212     */
213    public JComboBox(Vector<E> items) {
214        super();
215        setModel(new DefaultComboBoxModel<E>(items));
216        init();
217    }
218
219    /**
220     * Creates a <code>JComboBox</code> with a default data model.
221     * The default data model is an empty list of objects.
222     * Use <code>addItem</code> to add items.  By default the first item
223     * in the data model becomes selected.
224     *
225     * @see DefaultComboBoxModel
226     */
227    public JComboBox() {
228        super();
229        setModel(new DefaultComboBoxModel<E>());
230        init();
231    }
232
233    private void init() {
234        installAncestorListener();
235        setUIProperty("opaque",true);
236        updateUI();
237    }
238
239    /**
240     * Registers ancestor listener so that it will receive
241     * {@code AncestorEvents} when it or any of its ancestors
242     * move or are made visible or invisible.
243     * Events are also sent when the component or its ancestors are added
244     * or removed from the containment hierarchy.
245     */
246    protected void installAncestorListener() {
247        addAncestorListener(new AncestorListener(){
248                                public void ancestorAdded(AncestorEvent event){ hidePopup();}
249                                public void ancestorRemoved(AncestorEvent event){ hidePopup();}
250                                public void ancestorMoved(AncestorEvent event){
251                                    if (event.getSource() != JComboBox.this)
252                                        hidePopup();
253                                }});
254    }
255
256    /**
257     * Sets the L&amp;F object that renders this component.
258     *
259     * @param ui  the <code>ComboBoxUI</code> L&amp;F object
260     * @see UIDefaults#getUI
261     */
262    @BeanProperty(hidden = true, visualUpdate = true, description
263            = "The UI object that implements the Component's LookAndFeel.")
264    public void setUI(ComboBoxUI ui) {
265        super.setUI(ui);
266    }
267
268    /**
269     * Resets the UI property to a value from the current look and feel.
270     *
271     * @see JComponent#updateUI
272     */
273    public void updateUI() {
274        if (!updateInProgress) {
275            updateInProgress = true;
276            try {
277                setUI((ComboBoxUI)UIManager.getUI(this));
278
279                ListCellRenderer<? super E> renderer = getRenderer();
280                if (renderer instanceof Component) {
281                    SwingUtilities.updateComponentTreeUI((Component)renderer);
282                }
283            } finally {
284                updateInProgress = false;
285            }
286        }
287    }
288
289
290    /**
291     * Returns the name of the L&amp;F class that renders this component.
292     *
293     * @return the string "ComboBoxUI"
294     * @see JComponent#getUIClassID
295     * @see UIDefaults#getUI
296     */
297    @BeanProperty(bound = false)
298    public String getUIClassID() {
299        return uiClassID;
300    }
301
302
303    /**
304     * Returns the L&amp;F object that renders this component.
305     *
306     * @return the ComboBoxUI object that renders this component
307     */
308    public ComboBoxUI getUI() {
309        return(ComboBoxUI)ui;
310    }
311
312    /**
313     * Sets the data model that the <code>JComboBox</code> uses to obtain
314     * the list of items.
315     *
316     * @param aModel the <code>ComboBoxModel</code> that provides the
317     *  displayed list of items
318     */
319    @BeanProperty(description
320            = "Model that the combo box uses to get data to display.")
321    public void setModel(ComboBoxModel<E> aModel) {
322        ComboBoxModel<E> oldModel = dataModel;
323        if (oldModel != null) {
324            oldModel.removeListDataListener(this);
325        }
326        dataModel = aModel;
327        dataModel.addListDataListener(this);
328
329        // set the current selected item.
330        selectedItemReminder = dataModel.getSelectedItem();
331
332        firePropertyChange( "model", oldModel, dataModel);
333    }
334
335    /**
336     * Returns the data model currently used by the <code>JComboBox</code>.
337     *
338     * @return the <code>ComboBoxModel</code> that provides the displayed
339     *                  list of items
340     */
341    public ComboBoxModel<E> getModel() {
342        return dataModel;
343    }
344
345    /*
346     * Properties
347     */
348
349    /**
350     * Sets the <code>lightWeightPopupEnabled</code> property, which
351     * provides a hint as to whether or not a lightweight
352     * <code>Component</code> should be used to contain the
353     * <code>JComboBox</code>, versus a heavyweight
354     * <code>Component</code> such as a <code>Panel</code>
355     * or a <code>Window</code>.  The decision of lightweight
356     * versus heavyweight is ultimately up to the
357     * <code>JComboBox</code>.  Lightweight windows are more
358     * efficient than heavyweight windows, but lightweight
359     * and heavyweight components do not mix well in a GUI.
360     * If your application mixes lightweight and heavyweight
361     * components, you should disable lightweight popups.
362     * The default value for the <code>lightWeightPopupEnabled</code>
363     * property is <code>true</code>, unless otherwise specified
364     * by the look and feel.  Some look and feels always use
365     * heavyweight popups, no matter what the value of this property.
366     * <p>
367     * See the article <a href="http://www.oracle.com/technetwork/articles/java/mixing-components-433992.html">Mixing Heavy and Light Components</a>
368     * This method fires a property changed event.
369     *
370     * @param aFlag if <code>true</code>, lightweight popups are desired
371     */
372    @BeanProperty(expert = true, description
373            = "Set to <code>false</code> to require heavyweight popups.")
374    public void setLightWeightPopupEnabled(boolean aFlag) {
375        boolean oldFlag = lightWeightPopupEnabled;
376        lightWeightPopupEnabled = aFlag;
377        firePropertyChange("lightWeightPopupEnabled", oldFlag, lightWeightPopupEnabled);
378    }
379
380    /**
381     * Gets the value of the <code>lightWeightPopupEnabled</code>
382     * property.
383     *
384     * @return the value of the <code>lightWeightPopupEnabled</code>
385     *    property
386     * @see #setLightWeightPopupEnabled
387     */
388    public boolean isLightWeightPopupEnabled() {
389        return lightWeightPopupEnabled;
390    }
391
392    /**
393     * Determines whether the <code>JComboBox</code> field is editable.
394     * An editable <code>JComboBox</code> allows the user to type into the
395     * field or selected an item from the list to initialize the field,
396     * after which it can be edited. (The editing affects only the field,
397     * the list item remains intact.) A non editable <code>JComboBox</code>
398     * displays the selected item in the field,
399     * but the selection cannot be modified.
400     *
401     * @param aFlag a boolean value, where true indicates that the
402     *                  field is editable
403     */
404    @BeanProperty(preferred = true, description
405            = "If true, the user can type a new value in the combo box.")
406    public void setEditable(boolean aFlag) {
407        boolean oldFlag = isEditable;
408        isEditable = aFlag;
409        firePropertyChange( "editable", oldFlag, isEditable );
410    }
411
412    /**
413     * Returns true if the <code>JComboBox</code> is editable.
414     * By default, a combo box is not editable.
415     *
416     * @return true if the <code>JComboBox</code> is editable, else false
417     */
418    public boolean isEditable() {
419        return isEditable;
420    }
421
422    /**
423     * Sets the maximum number of rows the <code>JComboBox</code> displays.
424     * If the number of objects in the model is greater than count,
425     * the combo box uses a scrollbar.
426     *
427     * @param count an integer specifying the maximum number of items to
428     *              display in the list before using a scrollbar
429     */
430    @BeanProperty(preferred = true, description
431            = "The maximum number of rows the popup should have")
432    public void setMaximumRowCount(int count) {
433        int oldCount = maximumRowCount;
434        maximumRowCount = count;
435        firePropertyChange( "maximumRowCount", oldCount, maximumRowCount );
436    }
437
438    /**
439     * Returns the maximum number of items the combo box can display
440     * without a scrollbar
441     *
442     * @return an integer specifying the maximum number of items that are
443     *         displayed in the list before using a scrollbar
444     */
445    public int getMaximumRowCount() {
446        return maximumRowCount;
447    }
448
449    /**
450     * Sets the renderer that paints the list items and the item selected from the list in
451     * the JComboBox field. The renderer is used if the JComboBox is not
452     * editable. If it is editable, the editor is used to render and edit
453     * the selected item.
454     * <p>
455     * The default renderer displays a string or an icon.
456     * Other renderers can handle graphic images and composite items.
457     * <p>
458     * To display the selected item,
459     * <code>aRenderer.getListCellRendererComponent</code>
460     * is called, passing the list object and an index of -1.
461     *
462     * @param aRenderer  the <code>ListCellRenderer</code> that
463     *                  displays the selected item
464     * @see #setEditor
465     */
466    @BeanProperty(expert = true, description
467            = "The renderer that paints the item selected in the list.")
468    public void setRenderer(ListCellRenderer<? super E> aRenderer) {
469        ListCellRenderer<? super E> oldRenderer = renderer;
470        renderer = aRenderer;
471        firePropertyChange( "renderer", oldRenderer, renderer );
472        invalidate();
473    }
474
475    /**
476     * Returns the renderer used to display the selected item in the
477     * <code>JComboBox</code> field.
478     *
479     * @return  the <code>ListCellRenderer</code> that displays
480     *                  the selected item.
481     */
482    public ListCellRenderer<? super E> getRenderer() {
483        return renderer;
484    }
485
486    /**
487     * Sets the editor used to paint and edit the selected item in the
488     * <code>JComboBox</code> field.  The editor is used only if the
489     * receiving <code>JComboBox</code> is editable. If not editable,
490     * the combo box uses the renderer to paint the selected item.
491     *
492     * @param anEditor  the <code>ComboBoxEditor</code> that
493     *                  displays the selected item
494     * @see #setRenderer
495     */
496    @BeanProperty(expert = true, description
497            = "The editor that combo box uses to edit the current value")
498    public void setEditor(ComboBoxEditor anEditor) {
499        ComboBoxEditor oldEditor = editor;
500
501        if ( editor != null ) {
502            editor.removeActionListener(this);
503        }
504        editor = anEditor;
505        if ( editor != null ) {
506            editor.addActionListener(this);
507        }
508        firePropertyChange( "editor", oldEditor, editor );
509    }
510
511    /**
512     * Returns the editor used to paint and edit the selected item in the
513     * <code>JComboBox</code> field.
514     *
515     * @return the <code>ComboBoxEditor</code> that displays the selected item
516     */
517    public ComboBoxEditor getEditor() {
518        return editor;
519    }
520
521    //
522    // Selection
523    //
524
525    /**
526     * Sets the selected item in the combo box display area to the object in
527     * the argument.
528     * If <code>anObject</code> is in the list, the display area shows
529     * <code>anObject</code> selected.
530     * <p>
531     * If <code>anObject</code> is <i>not</i> in the list and the combo box is
532     * uneditable, it will not change the current selection. For editable
533     * combo boxes, the selection will change to <code>anObject</code>.
534     * <p>
535     * If this constitutes a change in the selected item,
536     * <code>ItemListener</code>s added to the combo box will be notified with
537     * one or two <code>ItemEvent</code>s.
538     * If there is a current selected item, an <code>ItemEvent</code> will be
539     * fired and the state change will be <code>ItemEvent.DESELECTED</code>.
540     * If <code>anObject</code> is in the list and is not currently selected
541     * then an <code>ItemEvent</code> will be fired and the state change will
542     * be <code>ItemEvent.SELECTED</code>.
543     * <p>
544     * <code>ActionListener</code>s added to the combo box will be notified
545     * with an <code>ActionEvent</code> when this method is called.
546     *
547     * @param anObject  the list object to select; use <code>null</code> to
548                        clear the selection
549     */
550    @BeanProperty(bound = false, preferred = true, description
551            = "Sets the selected item in the JComboBox.")
552    public void setSelectedItem(Object anObject) {
553        Object oldSelection = selectedItemReminder;
554        Object objectToSelect = anObject;
555        if (oldSelection == null || !oldSelection.equals(anObject)) {
556
557            if (anObject != null && !isEditable()) {
558                // For non editable combo boxes, an invalid selection
559                // will be rejected.
560                boolean found = false;
561                for (int i = 0; i < dataModel.getSize(); i++) {
562                    E element = dataModel.getElementAt(i);
563                    if (anObject.equals(element)) {
564                        found = true;
565                        objectToSelect = element;
566                        break;
567                    }
568                }
569                if (!found) {
570                    return;
571                }
572
573                getEditor().setItem(anObject);
574            }
575
576            // Must toggle the state of this flag since this method
577            // call may result in ListDataEvents being fired.
578            selectingItem = true;
579            dataModel.setSelectedItem(objectToSelect);
580            selectingItem = false;
581
582            if (selectedItemReminder != dataModel.getSelectedItem()) {
583                // in case a users implementation of ComboBoxModel
584                // doesn't fire a ListDataEvent when the selection
585                // changes.
586                selectedItemChanged();
587            }
588        }
589        fireActionEvent();
590    }
591
592    /**
593     * Returns the current selected item.
594     * <p>
595     * If the combo box is editable, then this value may not have been added
596     * to the combo box with <code>addItem</code>, <code>insertItemAt</code>
597     * or the data constructors.
598     *
599     * @return the current selected Object
600     * @see #setSelectedItem
601     */
602    public Object getSelectedItem() {
603        return dataModel.getSelectedItem();
604    }
605
606    /**
607     * Selects the item at index <code>anIndex</code>.
608     *
609     * @param anIndex an integer specifying the list item to select,
610     *                  where 0 specifies the first item in the list and -1 indicates no selection
611     * @exception IllegalArgumentException if <code>anIndex</code> &lt; -1 or
612     *                  <code>anIndex</code> is greater than or equal to size
613     */
614    @BeanProperty(bound = false, preferred = true, description
615            = "The item at index is selected.")
616    public void setSelectedIndex(int anIndex) {
617        int size = dataModel.getSize();
618
619        if ( anIndex == -1 ) {
620            setSelectedItem( null );
621        } else if ( anIndex < -1 || anIndex >= size ) {
622            throw new IllegalArgumentException("setSelectedIndex: " + anIndex + " out of bounds");
623        } else {
624            setSelectedItem(dataModel.getElementAt(anIndex));
625        }
626    }
627
628    /**
629     * Returns the first item in the list that matches the given item.
630     * The result is not always defined if the <code>JComboBox</code>
631     * allows selected items that are not in the list.
632     * Returns -1 if there is no selected item or if the user specified
633     * an item which is not in the list.
634
635     * @return an integer specifying the currently selected list item,
636     *                  where 0 specifies
637     *                  the first item in the list;
638     *                  or -1 if no item is selected or if
639     *                  the currently selected item is not in the list
640     */
641    @Transient
642    public int getSelectedIndex() {
643        Object sObject = dataModel.getSelectedItem();
644        int i,c;
645        E obj;
646
647        for ( i=0,c=dataModel.getSize();i<c;i++ ) {
648            obj = dataModel.getElementAt(i);
649            if ( obj != null && obj.equals(sObject) )
650                return i;
651        }
652        return -1;
653    }
654
655    /**
656     * Returns the "prototypical display" value - an Object used
657     * for the calculation of the display height and width.
658     *
659     * @return the value of the <code>prototypeDisplayValue</code> property
660     * @see #setPrototypeDisplayValue
661     * @since 1.4
662     */
663    public E getPrototypeDisplayValue() {
664        return prototypeDisplayValue;
665    }
666
667    /**
668     * Sets the prototype display value used to calculate the size of the display
669     * for the UI portion.
670     * <p>
671     * If a prototype display value is specified, the preferred size of
672     * the combo box is calculated by configuring the renderer with the
673     * prototype display value and obtaining its preferred size. Specifying
674     * the preferred display value is often useful when the combo box will be
675     * displaying large amounts of data. If no prototype display value has
676     * been specified, the renderer must be configured for each value from
677     * the model and its preferred size obtained, which can be
678     * relatively expensive.
679     *
680     * @param prototypeDisplayValue the prototype display value
681     * @see #getPrototypeDisplayValue
682     * @since 1.4
683     */
684    @BeanProperty(visualUpdate = true, description
685            = "The display prototype value, used to compute display width and height.")
686    public void setPrototypeDisplayValue(E prototypeDisplayValue) {
687        Object oldValue = this.prototypeDisplayValue;
688        this.prototypeDisplayValue = prototypeDisplayValue;
689        firePropertyChange("prototypeDisplayValue", oldValue, prototypeDisplayValue);
690    }
691
692    /**
693     * Adds an item to the item list.
694     * This method works only if the <code>JComboBox</code> uses a
695     * mutable data model.
696     * <p>
697     * <strong>Warning:</strong>
698     * Focus and keyboard navigation problems may arise if you add duplicate
699     * String objects. A workaround is to add new objects instead of String
700     * objects and make sure that the toString() method is defined.
701     * For example:
702     * <pre>
703     *   comboBox.addItem(makeObj("Item 1"));
704     *   comboBox.addItem(makeObj("Item 1"));
705     *   ...
706     *   private Object makeObj(final String item)  {
707     *     return new Object() { public String toString() { return item; } };
708     *   }
709     * </pre>
710     *
711     * @param item the item to add to the list
712     * @see MutableComboBoxModel
713     */
714    public void addItem(E item) {
715        checkMutableComboBoxModel();
716        ((MutableComboBoxModel<E>)dataModel).addElement(item);
717    }
718
719    /**
720     * Inserts an item into the item list at a given index.
721     * This method works only if the <code>JComboBox</code> uses a
722     * mutable data model.
723     *
724     * @param item the item to add to the list
725     * @param index    an integer specifying the position at which
726     *                  to add the item
727     * @see MutableComboBoxModel
728     */
729    public void insertItemAt(E item, int index) {
730        checkMutableComboBoxModel();
731        ((MutableComboBoxModel<E>)dataModel).insertElementAt(item,index);
732    }
733
734    /**
735     * Removes an item from the item list.
736     * This method works only if the <code>JComboBox</code> uses a
737     * mutable data model.
738     *
739     * @param anObject  the object to remove from the item list
740     * @see MutableComboBoxModel
741     */
742    public void removeItem(Object anObject) {
743        checkMutableComboBoxModel();
744        ((MutableComboBoxModel)dataModel).removeElement(anObject);
745    }
746
747    /**
748     * Removes the item at <code>anIndex</code>
749     * This method works only if the <code>JComboBox</code> uses a
750     * mutable data model.
751     *
752     * @param anIndex  an int specifying the index of the item to remove,
753     *                  where 0
754     *                  indicates the first item in the list
755     * @see MutableComboBoxModel
756     */
757    public void removeItemAt(int anIndex) {
758        checkMutableComboBoxModel();
759        ((MutableComboBoxModel<E>)dataModel).removeElementAt( anIndex );
760    }
761
762    /**
763     * Removes all items from the item list.
764     */
765    public void removeAllItems() {
766        checkMutableComboBoxModel();
767        MutableComboBoxModel<E> model = (MutableComboBoxModel<E>)dataModel;
768        int size = model.getSize();
769
770        if ( model instanceof DefaultComboBoxModel ) {
771            ((DefaultComboBoxModel)model).removeAllElements();
772        }
773        else {
774            for ( int i = 0; i < size; ++i ) {
775                E element = model.getElementAt( 0 );
776                model.removeElement( element );
777            }
778        }
779        selectedItemReminder = null;
780        if (isEditable()) {
781            editor.setItem(null);
782        }
783    }
784
785    /**
786     * Checks that the <code>dataModel</code> is an instance of
787     * <code>MutableComboBoxModel</code>.  If not, it throws an exception.
788     * @exception RuntimeException if <code>dataModel</code> is not an
789     *          instance of <code>MutableComboBoxModel</code>.
790     */
791    void checkMutableComboBoxModel() {
792        if ( !(dataModel instanceof MutableComboBoxModel) )
793            throw new RuntimeException("Cannot use this method with a non-Mutable data model.");
794    }
795
796    /**
797     * Causes the combo box to display its popup window.
798     * @see #setPopupVisible
799     */
800    public void showPopup() {
801        setPopupVisible(true);
802    }
803
804    /**
805     * Causes the combo box to close its popup window.
806     * @see #setPopupVisible
807     */
808    public void hidePopup() {
809        setPopupVisible(false);
810    }
811
812    /**
813     * Sets the visibility of the popup.
814     *
815     * @param v if {@code true} shows the popup, otherwise, hides the popup.
816     */
817    public void setPopupVisible(boolean v) {
818        getUI().setPopupVisible(this, v);
819    }
820
821    /**
822     * Determines the visibility of the popup.
823     *
824     * @return true if the popup is visible, otherwise returns false
825     */
826    public boolean isPopupVisible() {
827        return getUI().isPopupVisible(this);
828    }
829
830    /** Selection **/
831
832    /**
833     * Adds an <code>ItemListener</code>.
834     * <p>
835     * <code>aListener</code> will receive one or two <code>ItemEvent</code>s when
836     * the selected item changes.
837     *
838     * @param aListener the <code>ItemListener</code> that is to be notified
839     * @see #setSelectedItem
840     */
841    public void addItemListener(ItemListener aListener) {
842        listenerList.add(ItemListener.class,aListener);
843    }
844
845    /** Removes an <code>ItemListener</code>.
846     *
847     * @param aListener  the <code>ItemListener</code> to remove
848     */
849    public void removeItemListener(ItemListener aListener) {
850        listenerList.remove(ItemListener.class,aListener);
851    }
852
853    /**
854     * Returns an array of all the <code>ItemListener</code>s added
855     * to this JComboBox with addItemListener().
856     *
857     * @return all of the <code>ItemListener</code>s added or an empty
858     *         array if no listeners have been added
859     * @since 1.4
860     */
861    @BeanProperty(bound = false)
862    public ItemListener[] getItemListeners() {
863        return listenerList.getListeners(ItemListener.class);
864    }
865
866    /**
867     * Adds an <code>ActionListener</code>.
868     * <p>
869     * The <code>ActionListener</code> will receive an <code>ActionEvent</code>
870     * when a selection has been made. If the combo box is editable, then
871     * an <code>ActionEvent</code> will be fired when editing has stopped.
872     *
873     * @param l  the <code>ActionListener</code> that is to be notified
874     * @see #setSelectedItem
875     */
876    public void addActionListener(ActionListener l) {
877        listenerList.add(ActionListener.class,l);
878    }
879
880    /** Removes an <code>ActionListener</code>.
881     *
882     * @param l  the <code>ActionListener</code> to remove
883     */
884    public void removeActionListener(ActionListener l) {
885        if ((l != null) && (getAction() == l)) {
886            setAction(null);
887        } else {
888            listenerList.remove(ActionListener.class, l);
889        }
890    }
891
892    /**
893     * Returns an array of all the <code>ActionListener</code>s added
894     * to this JComboBox with addActionListener().
895     *
896     * @return all of the <code>ActionListener</code>s added or an empty
897     *         array if no listeners have been added
898     * @since 1.4
899     */
900    @BeanProperty(bound = false)
901    public ActionListener[] getActionListeners() {
902        return listenerList.getListeners(ActionListener.class);
903    }
904
905    /**
906     * Adds a <code>PopupMenu</code> listener which will listen to notification
907     * messages from the popup portion of the combo box.
908     * <p>
909     * For all standard look and feels shipped with Java, the popup list
910     * portion of combo box is implemented as a <code>JPopupMenu</code>.
911     * A custom look and feel may not implement it this way and will
912     * therefore not receive the notification.
913     *
914     * @param l  the <code>PopupMenuListener</code> to add
915     * @since 1.4
916     */
917    public void addPopupMenuListener(PopupMenuListener l) {
918        listenerList.add(PopupMenuListener.class,l);
919    }
920
921    /**
922     * Removes a <code>PopupMenuListener</code>.
923     *
924     * @param l  the <code>PopupMenuListener</code> to remove
925     * @see #addPopupMenuListener
926     * @since 1.4
927     */
928    public void removePopupMenuListener(PopupMenuListener l) {
929        listenerList.remove(PopupMenuListener.class,l);
930    }
931
932    /**
933     * Returns an array of all the <code>PopupMenuListener</code>s added
934     * to this JComboBox with addPopupMenuListener().
935     *
936     * @return all of the <code>PopupMenuListener</code>s added or an empty
937     *         array if no listeners have been added
938     * @since 1.4
939     */
940    @BeanProperty(bound = false)
941    public PopupMenuListener[] getPopupMenuListeners() {
942        return listenerList.getListeners(PopupMenuListener.class);
943    }
944
945    /**
946     * Notifies <code>PopupMenuListener</code>s that the popup portion of the
947     * combo box will become visible.
948     * <p>
949     * This method is public but should not be called by anything other than
950     * the UI delegate.
951     * @see #addPopupMenuListener
952     * @since 1.4
953     */
954    public void firePopupMenuWillBecomeVisible() {
955        Object[] listeners = listenerList.getListenerList();
956        PopupMenuEvent e=null;
957        for (int i = listeners.length-2; i>=0; i-=2) {
958            if (listeners[i]==PopupMenuListener.class) {
959                if (e == null)
960                    e = new PopupMenuEvent(this);
961                ((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeVisible(e);
962            }
963        }
964    }
965
966    /**
967     * Notifies <code>PopupMenuListener</code>s that the popup portion of the
968     * combo box has become invisible.
969     * <p>
970     * This method is public but should not be called by anything other than
971     * the UI delegate.
972     * @see #addPopupMenuListener
973     * @since 1.4
974     */
975    public void firePopupMenuWillBecomeInvisible() {
976        Object[] listeners = listenerList.getListenerList();
977        PopupMenuEvent e=null;
978        for (int i = listeners.length-2; i>=0; i-=2) {
979            if (listeners[i]==PopupMenuListener.class) {
980                if (e == null)
981                    e = new PopupMenuEvent(this);
982                ((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeInvisible(e);
983            }
984        }
985    }
986
987    /**
988     * Notifies <code>PopupMenuListener</code>s that the popup portion of the
989     * combo box has been canceled.
990     * <p>
991     * This method is public but should not be called by anything other than
992     * the UI delegate.
993     * @see #addPopupMenuListener
994     * @since 1.4
995     */
996    public void firePopupMenuCanceled() {
997        Object[] listeners = listenerList.getListenerList();
998        PopupMenuEvent e=null;
999        for (int i = listeners.length-2; i>=0; i-=2) {
1000            if (listeners[i]==PopupMenuListener.class) {
1001                if (e == null)
1002                    e = new PopupMenuEvent(this);
1003                ((PopupMenuListener)listeners[i+1]).popupMenuCanceled(e);
1004            }
1005        }
1006    }
1007
1008    /**
1009     * Sets the action command that should be included in the event
1010     * sent to action listeners.
1011     *
1012     * @param aCommand  a string containing the "command" that is sent
1013     *                  to action listeners; the same listener can then
1014     *                  do different things depending on the command it
1015     *                  receives
1016     */
1017    public void setActionCommand(String aCommand) {
1018        actionCommand = aCommand;
1019    }
1020
1021    /**
1022     * Returns the action command that is included in the event sent to
1023     * action listeners.
1024     *
1025     * @return  the string containing the "command" that is sent
1026     *          to action listeners.
1027     */
1028    public String getActionCommand() {
1029        return actionCommand;
1030    }
1031
1032    private Action action;
1033    private PropertyChangeListener actionPropertyChangeListener;
1034
1035    /**
1036     * Sets the <code>Action</code> for the <code>ActionEvent</code> source.
1037     * The new <code>Action</code> replaces any previously set
1038     * <code>Action</code> but does not affect <code>ActionListeners</code>
1039     * independently added with <code>addActionListener</code>.
1040     * If the <code>Action</code> is already a registered
1041     * <code>ActionListener</code> for the <code>ActionEvent</code> source,
1042     * it is not re-registered.
1043     * <p>
1044     * Setting the <code>Action</code> results in immediately changing
1045     * all the properties described in <a href="Action.html#buttonActions">
1046     * Swing Components Supporting <code>Action</code></a>.
1047     * Subsequently, the combobox's properties are automatically updated
1048     * as the <code>Action</code>'s properties change.
1049     * <p>
1050     * This method uses three other methods to set
1051     * and help track the <code>Action</code>'s property values.
1052     * It uses the <code>configurePropertiesFromAction</code> method
1053     * to immediately change the combobox's properties.
1054     * To track changes in the <code>Action</code>'s property values,
1055     * this method registers the <code>PropertyChangeListener</code>
1056     * returned by <code>createActionPropertyChangeListener</code>. The
1057     * default {@code PropertyChangeListener} invokes the
1058     * {@code actionPropertyChanged} method when a property in the
1059     * {@code Action} changes.
1060     *
1061     * @param a the <code>Action</code> for the <code>JComboBox</code>,
1062     *                  or <code>null</code>.
1063     * @since 1.3
1064     * @see Action
1065     * @see #getAction
1066     * @see #configurePropertiesFromAction
1067     * @see #createActionPropertyChangeListener
1068     * @see #actionPropertyChanged
1069     */
1070    @BeanProperty(visualUpdate = true, description
1071            = "the Action instance connected with this ActionEvent source")
1072    public void setAction(Action a) {
1073        Action oldValue = getAction();
1074        if (action==null || !action.equals(a)) {
1075            action = a;
1076            if (oldValue!=null) {
1077                removeActionListener(oldValue);
1078                oldValue.removePropertyChangeListener(actionPropertyChangeListener);
1079                actionPropertyChangeListener = null;
1080            }
1081            configurePropertiesFromAction(action);
1082            if (action!=null) {
1083                // Don't add if it is already a listener
1084                if (!isListener(ActionListener.class, action)) {
1085                    addActionListener(action);
1086                }
1087                // Reverse linkage:
1088                actionPropertyChangeListener = createActionPropertyChangeListener(action);
1089                action.addPropertyChangeListener(actionPropertyChangeListener);
1090            }
1091            firePropertyChange("action", oldValue, action);
1092        }
1093    }
1094
1095    private boolean isListener(Class<?> c, ActionListener a) {
1096        boolean isListener = false;
1097        Object[] listeners = listenerList.getListenerList();
1098        for (int i = listeners.length-2; i>=0; i-=2) {
1099            if (listeners[i]==c && listeners[i+1]==a) {
1100                    isListener=true;
1101            }
1102        }
1103        return isListener;
1104    }
1105
1106    /**
1107     * Returns the currently set <code>Action</code> for this
1108     * <code>ActionEvent</code> source, or <code>null</code> if no
1109     * <code>Action</code> is set.
1110     *
1111     * @return the <code>Action</code> for this <code>ActionEvent</code>
1112     *          source; or <code>null</code>
1113     * @since 1.3
1114     * @see Action
1115     * @see #setAction
1116     */
1117    public Action getAction() {
1118        return action;
1119    }
1120
1121    /**
1122     * Sets the properties on this combobox to match those in the specified
1123     * <code>Action</code>.  Refer to <a href="Action.html#buttonActions">
1124     * Swing Components Supporting <code>Action</code></a> for more
1125     * details as to which properties this sets.
1126     *
1127     * @param a the <code>Action</code> from which to get the properties,
1128     *          or <code>null</code>
1129     * @since 1.3
1130     * @see Action
1131     * @see #setAction
1132     */
1133    protected void configurePropertiesFromAction(Action a) {
1134        AbstractAction.setEnabledFromAction(this, a);
1135        AbstractAction.setToolTipTextFromAction(this, a);
1136        setActionCommandFromAction(a);
1137    }
1138
1139    /**
1140     * Creates and returns a <code>PropertyChangeListener</code> that is
1141     * responsible for listening for changes from the specified
1142     * <code>Action</code> and updating the appropriate properties.
1143     * <p>
1144     * <b>Warning:</b> If you subclass this do not create an anonymous
1145     * inner class.  If you do the lifetime of the combobox will be tied to
1146     * that of the <code>Action</code>.
1147     *
1148     * @param a the combobox's action
1149     * @return the {@code PropertyChangeListener}
1150     * @since 1.3
1151     * @see Action
1152     * @see #setAction
1153     */
1154    protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
1155        return new ComboBoxActionPropertyChangeListener(this, a);
1156    }
1157
1158    /**
1159     * Updates the combobox's state in response to property changes in
1160     * associated action. This method is invoked from the
1161     * {@code PropertyChangeListener} returned from
1162     * {@code createActionPropertyChangeListener}. Subclasses do not normally
1163     * need to invoke this. Subclasses that support additional {@code Action}
1164     * properties should override this and
1165     * {@code configurePropertiesFromAction}.
1166     * <p>
1167     * Refer to the table at <a href="Action.html#buttonActions">
1168     * Swing Components Supporting <code>Action</code></a> for a list of
1169     * the properties this method sets.
1170     *
1171     * @param action the <code>Action</code> associated with this combobox
1172     * @param propertyName the name of the property that changed
1173     * @since 1.6
1174     * @see Action
1175     * @see #configurePropertiesFromAction
1176     */
1177    protected void actionPropertyChanged(Action action, String propertyName) {
1178        if (propertyName == Action.ACTION_COMMAND_KEY) {
1179            setActionCommandFromAction(action);
1180        } else if (propertyName == "enabled") {
1181            AbstractAction.setEnabledFromAction(this, action);
1182        } else if (Action.SHORT_DESCRIPTION == propertyName) {
1183            AbstractAction.setToolTipTextFromAction(this, action);
1184        }
1185    }
1186
1187    private void setActionCommandFromAction(Action a) {
1188        setActionCommand((a != null) ?
1189                             (String)a.getValue(Action.ACTION_COMMAND_KEY) :
1190                             null);
1191    }
1192
1193
1194    private static class ComboBoxActionPropertyChangeListener
1195                 extends ActionPropertyChangeListener<JComboBox<?>> {
1196        ComboBoxActionPropertyChangeListener(JComboBox<?> b, Action a) {
1197            super(b, a);
1198        }
1199        protected void actionPropertyChanged(JComboBox<?> cb,
1200                                             Action action,
1201                                             PropertyChangeEvent e) {
1202            if (AbstractAction.shouldReconfigure(e)) {
1203                cb.configurePropertiesFromAction(action);
1204            } else {
1205                cb.actionPropertyChanged(action, e.getPropertyName());
1206            }
1207        }
1208    }
1209
1210    /**
1211     * Notifies all listeners that have registered interest for
1212     * notification on this event type.
1213     * @param e  the event of interest
1214     *
1215     * @see EventListenerList
1216     */
1217    protected void fireItemStateChanged(ItemEvent e) {
1218        // Guaranteed to return a non-null array
1219        Object[] listeners = listenerList.getListenerList();
1220        // Process the listeners last to first, notifying
1221        // those that are interested in this event
1222        for ( int i = listeners.length-2; i>=0; i-=2 ) {
1223            if ( listeners[i]==ItemListener.class ) {
1224                // Lazily create the event:
1225                // if (changeEvent == null)
1226                // changeEvent = new ChangeEvent(this);
1227                ((ItemListener)listeners[i+1]).itemStateChanged(e);
1228            }
1229        }
1230    }
1231
1232    /**
1233     * Notifies all listeners that have registered interest for
1234     * notification on this event type.
1235     *
1236     * @see EventListenerList
1237     */
1238    @SuppressWarnings("deprecation")
1239    protected void fireActionEvent() {
1240        if (!firingActionEvent) {
1241            // Set flag to ensure that an infinite loop is not created
1242            firingActionEvent = true;
1243            ActionEvent e = null;
1244            // Guaranteed to return a non-null array
1245            Object[] listeners = listenerList.getListenerList();
1246            long mostRecentEventTime = EventQueue.getMostRecentEventTime();
1247            int modifiers = 0;
1248            AWTEvent currentEvent = EventQueue.getCurrentEvent();
1249            if (currentEvent instanceof InputEvent) {
1250                modifiers = ((InputEvent)currentEvent).getModifiers();
1251            } else if (currentEvent instanceof ActionEvent) {
1252                modifiers = ((ActionEvent)currentEvent).getModifiers();
1253            }
1254            try {
1255                // Process the listeners last to first, notifying
1256                // those that are interested in this event
1257                for ( int i = listeners.length-2; i>=0; i-=2 ) {
1258                    if ( listeners[i]==ActionListener.class ) {
1259                        // Lazily create the event:
1260                        if ( e == null )
1261                            e = new ActionEvent(this,ActionEvent.ACTION_PERFORMED,
1262                                                getActionCommand(),
1263                                                mostRecentEventTime, modifiers);
1264                        ((ActionListener)listeners[i+1]).actionPerformed(e);
1265                    }
1266                }
1267            } finally {
1268                firingActionEvent = false;
1269            }
1270        }
1271    }
1272
1273    /**
1274     * This protected method is implementation specific. Do not access directly
1275     * or override.
1276     */
1277    protected void selectedItemChanged() {
1278        if (selectedItemReminder != null ) {
1279            fireItemStateChanged(new ItemEvent(this,ItemEvent.ITEM_STATE_CHANGED,
1280                                               selectedItemReminder,
1281                                               ItemEvent.DESELECTED));
1282        }
1283
1284        // set the new selected item.
1285        selectedItemReminder = dataModel.getSelectedItem();
1286
1287        if (selectedItemReminder != null ) {
1288            fireItemStateChanged(new ItemEvent(this,ItemEvent.ITEM_STATE_CHANGED,
1289                                               selectedItemReminder,
1290                                               ItemEvent.SELECTED));
1291        }
1292    }
1293
1294    /**
1295     * Returns an array containing the selected item.
1296     * This method is implemented for compatibility with
1297     * <code>ItemSelectable</code>.
1298     *
1299     * @return an array of <code>Objects</code> containing one
1300     *          element -- the selected item
1301     */
1302    @BeanProperty(bound = false)
1303    public Object[] getSelectedObjects() {
1304        Object selectedObject = getSelectedItem();
1305        if ( selectedObject == null )
1306            return new Object[0];
1307        else {
1308            Object result[] = new Object[1];
1309            result[0] = selectedObject;
1310            return result;
1311        }
1312    }
1313
1314    /**
1315     * This method is public as an implementation side effect.
1316     * do not call or override.
1317     */
1318    public void actionPerformed(ActionEvent e) {
1319        setPopupVisible(false);
1320        getModel().setSelectedItem(getEditor().getItem());
1321        String oldCommand = getActionCommand();
1322        setActionCommand("comboBoxEdited");
1323        fireActionEvent();
1324        setActionCommand(oldCommand);
1325    }
1326
1327    /**
1328     * This method is public as an implementation side effect.
1329     * do not call or override.
1330     */
1331    public void contentsChanged(ListDataEvent e) {
1332        Object oldSelection = selectedItemReminder;
1333        Object newSelection = dataModel.getSelectedItem();
1334        if (oldSelection == null || !oldSelection.equals(newSelection)) {
1335            selectedItemChanged();
1336            if (!selectingItem) {
1337                fireActionEvent();
1338            }
1339        }
1340    }
1341
1342    /**
1343     * This method is public as an implementation side effect.
1344     * do not call or override.
1345     */
1346    public void intervalAdded(ListDataEvent e) {
1347        if (selectedItemReminder != dataModel.getSelectedItem()) {
1348            selectedItemChanged();
1349        }
1350    }
1351
1352    /**
1353     * This method is public as an implementation side effect.
1354     * do not call or override.
1355     */
1356    public void intervalRemoved(ListDataEvent e) {
1357        contentsChanged(e);
1358    }
1359
1360    /**
1361     * Selects the list item that corresponds to the specified keyboard
1362     * character and returns true, if there is an item corresponding
1363     * to that character.  Otherwise, returns false.
1364     *
1365     * @param keyChar a char, typically this is a keyboard key
1366     *                  typed by the user
1367     * @return {@code true} if there is an item corresponding to that character.
1368     *         Otherwise, returns {@code false}.
1369     */
1370    public boolean selectWithKeyChar(char keyChar) {
1371        int index;
1372
1373        if ( keySelectionManager == null )
1374            keySelectionManager = createDefaultKeySelectionManager();
1375
1376        index = keySelectionManager.selectionForKey(keyChar,getModel());
1377        if ( index != -1 ) {
1378            setSelectedIndex(index);
1379            return true;
1380        }
1381        else
1382            return false;
1383    }
1384
1385    /**
1386     * Enables the combo box so that items can be selected. When the
1387     * combo box is disabled, items cannot be selected and values
1388     * cannot be typed into its field (if it is editable).
1389     *
1390     * @param b a boolean value, where true enables the component and
1391     *          false disables it
1392     */
1393    @BeanProperty(preferred = true, description
1394            = "The enabled state of the component.")
1395    public void setEnabled(boolean b) {
1396        super.setEnabled(b);
1397        firePropertyChange( "enabled", !isEnabled(), isEnabled() );
1398    }
1399
1400    /**
1401     * Initializes the editor with the specified item.
1402     *
1403     * @param anEditor the <code>ComboBoxEditor</code> that displays
1404     *                  the list item in the
1405     *                  combo box field and allows it to be edited
1406     * @param anItem   the object to display and edit in the field
1407     */
1408    public void configureEditor(ComboBoxEditor anEditor, Object anItem) {
1409        anEditor.setItem(anItem);
1410    }
1411
1412    /**
1413     * Handles <code>KeyEvent</code>s, looking for the Tab key.
1414     * If the Tab key is found, the popup window is closed.
1415     *
1416     * @param e  the <code>KeyEvent</code> containing the keyboard
1417     *          key that was pressed
1418     */
1419    public void processKeyEvent(KeyEvent e) {
1420        if ( e.getKeyCode() == KeyEvent.VK_TAB ) {
1421            hidePopup();
1422        }
1423        super.processKeyEvent(e);
1424    }
1425
1426    /**
1427     * {@inheritDoc}
1428     */
1429    @Override
1430    protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
1431        if (super.processKeyBinding(ks, e, condition, pressed)) {
1432            return true;
1433        }
1434
1435        if (!isEditable() || condition != WHEN_FOCUSED || getEditor() == null
1436                || !Boolean.TRUE.equals(getClientProperty("JComboBox.isTableCellEditor"))) {
1437            return false;
1438        }
1439
1440        Component editorComponent = getEditor().getEditorComponent();
1441        if (editorComponent instanceof JComponent) {
1442            JComponent component = (JComponent) editorComponent;
1443            return component.processKeyBinding(ks, e, WHEN_FOCUSED, pressed);
1444        }
1445        return false;
1446    }
1447
1448    /**
1449     * Sets the object that translates a keyboard character into a list
1450     * selection. Typically, the first selection with a matching first
1451     * character becomes the selected item.
1452     *
1453     * @param aManager a key selection manager
1454     */
1455    @BeanProperty(bound = false, expert = true, description
1456            = "The objects that changes the selection when a key is pressed.")
1457    public void setKeySelectionManager(KeySelectionManager aManager) {
1458        keySelectionManager = aManager;
1459    }
1460
1461    /**
1462     * Returns the list's key-selection manager.
1463     *
1464     * @return the <code>KeySelectionManager</code> currently in use
1465     */
1466    public KeySelectionManager getKeySelectionManager() {
1467        return keySelectionManager;
1468    }
1469
1470    /* Accessing the model */
1471    /**
1472     * Returns the number of items in the list.
1473     *
1474     * @return an integer equal to the number of items in the list
1475     */
1476    @BeanProperty(bound = false)
1477    public int getItemCount() {
1478        return dataModel.getSize();
1479    }
1480
1481    /**
1482     * Returns the list item at the specified index.  If <code>index</code>
1483     * is out of range (less than zero or greater than or equal to size)
1484     * it will return <code>null</code>.
1485     *
1486     * @param index  an integer indicating the list position, where the first
1487     *               item starts at zero
1488     * @return the item at that list position; or
1489     *                  <code>null</code> if out of range
1490     */
1491    public E getItemAt(int index) {
1492        return dataModel.getElementAt(index);
1493    }
1494
1495    /**
1496     * Returns an instance of the default key-selection manager.
1497     *
1498     * @return the <code>KeySelectionManager</code> currently used by the list
1499     * @see #setKeySelectionManager
1500     */
1501    protected KeySelectionManager createDefaultKeySelectionManager() {
1502        return new DefaultKeySelectionManager();
1503    }
1504
1505
1506    /**
1507     * The interface that defines a <code>KeySelectionManager</code>.
1508     * To qualify as a <code>KeySelectionManager</code>,
1509     * the class needs to implement the method
1510     * that identifies the list index given a character and the
1511     * combo box data model.
1512     */
1513    public interface KeySelectionManager {
1514        /** Given <code>aKey</code> and the model, returns the row
1515         *  that should become selected. Return -1 if no match was
1516         *  found.
1517         *
1518         * @param  aKey  a char value, usually indicating a keyboard key that
1519         *               was pressed
1520         * @param aModel a ComboBoxModel -- the component's data model, containing
1521         *               the list of selectable items
1522         * @return an int equal to the selected row, where 0 is the
1523         *         first item and -1 is none.
1524         */
1525        int selectionForKey(char aKey,ComboBoxModel<?> aModel);
1526    }
1527
1528    class DefaultKeySelectionManager implements KeySelectionManager, Serializable {
1529        public int selectionForKey(char aKey,ComboBoxModel<?> aModel) {
1530            int i,c;
1531            int currentSelection = -1;
1532            Object selectedItem = aModel.getSelectedItem();
1533            String v;
1534            String pattern;
1535
1536            if ( selectedItem != null ) {
1537                for ( i=0,c=aModel.getSize();i<c;i++ ) {
1538                    if ( selectedItem == aModel.getElementAt(i) ) {
1539                        currentSelection  =  i;
1540                        break;
1541                    }
1542                }
1543            }
1544
1545            pattern = ("" + aKey).toLowerCase();
1546            aKey = pattern.charAt(0);
1547
1548            for ( i = ++currentSelection, c = aModel.getSize() ; i < c ; i++ ) {
1549                Object elem = aModel.getElementAt(i);
1550                if (elem != null && elem.toString() != null) {
1551                    v = elem.toString().toLowerCase();
1552                    if ( v.length() > 0 && v.charAt(0) == aKey )
1553                        return i;
1554                }
1555            }
1556
1557            for ( i = 0 ; i < currentSelection ; i ++ ) {
1558                Object elem = aModel.getElementAt(i);
1559                if (elem != null && elem.toString() != null) {
1560                    v = elem.toString().toLowerCase();
1561                    if ( v.length() > 0 && v.charAt(0) == aKey )
1562                        return i;
1563                }
1564            }
1565            return -1;
1566        }
1567    }
1568
1569
1570    /**
1571     * See <code>readObject</code> and <code>writeObject</code> in
1572     * <code>JComponent</code> for more
1573     * information about serialization in Swing.
1574     */
1575    private void writeObject(ObjectOutputStream s) throws IOException {
1576        s.defaultWriteObject();
1577        if (getUIClassID().equals(uiClassID)) {
1578            byte count = JComponent.getWriteObjCounter(this);
1579            JComponent.setWriteObjCounter(this, --count);
1580            if (count == 0 && ui != null) {
1581                ui.installUI(this);
1582            }
1583        }
1584    }
1585
1586
1587    /**
1588     * Returns a string representation of this <code>JComboBox</code>.
1589     * This method is intended to be used only for debugging purposes,
1590     * and the content and format of the returned string may vary between
1591     * implementations. The returned string may be empty but may not
1592     * be <code>null</code>.
1593     *
1594     * @return  a string representation of this <code>JComboBox</code>
1595     */
1596    protected String paramString() {
1597        String selectedItemReminderString = (selectedItemReminder != null ?
1598                                             selectedItemReminder.toString() :
1599                                             "");
1600        String isEditableString = (isEditable ? "true" : "false");
1601        String lightWeightPopupEnabledString = (lightWeightPopupEnabled ?
1602                                                "true" : "false");
1603
1604        return super.paramString() +
1605        ",isEditable=" + isEditableString +
1606        ",lightWeightPopupEnabled=" + lightWeightPopupEnabledString +
1607        ",maximumRowCount=" + maximumRowCount +
1608        ",selectedItemReminder=" + selectedItemReminderString;
1609    }
1610
1611
1612///////////////////
1613// Accessibility support
1614///////////////////
1615
1616    /**
1617     * Gets the AccessibleContext associated with this JComboBox.
1618     * For combo boxes, the AccessibleContext takes the form of an
1619     * AccessibleJComboBox.
1620     * A new AccessibleJComboBox instance is created if necessary.
1621     *
1622     * @return an AccessibleJComboBox that serves as the
1623     *         AccessibleContext of this JComboBox
1624     */
1625    @BeanProperty(bound = false)
1626    public AccessibleContext getAccessibleContext() {
1627        if ( accessibleContext == null ) {
1628            accessibleContext = new AccessibleJComboBox();
1629        }
1630        return accessibleContext;
1631    }
1632
1633    /**
1634     * This class implements accessibility support for the
1635     * <code>JComboBox</code> class.  It provides an implementation of the
1636     * Java Accessibility API appropriate to Combo Box user-interface elements.
1637     * <p>
1638     * <strong>Warning:</strong>
1639     * Serialized objects of this class will not be compatible with
1640     * future Swing releases. The current serialization support is
1641     * appropriate for short term storage or RMI between applications running
1642     * the same version of Swing.  As of 1.4, support for long term storage
1643     * of all JavaBeans&trade;
1644     * has been added to the <code>java.beans</code> package.
1645     * Please see {@link java.beans.XMLEncoder}.
1646     */
1647    @SuppressWarnings("serial") // Same-version serialization only
1648    protected class AccessibleJComboBox extends AccessibleJComponent
1649    implements AccessibleAction, AccessibleSelection {
1650
1651
1652        private JList<?> popupList; // combo box popup list
1653        private Accessible previousSelectedAccessible = null;
1654
1655        /**
1656         * Returns an AccessibleJComboBox instance
1657         * @since 1.4
1658         */
1659        public AccessibleJComboBox() {
1660            // set the combo box editor's accessible name and description
1661            JComboBox.this.addPropertyChangeListener(new AccessibleJComboBoxPropertyChangeListener());
1662            setEditorNameAndDescription();
1663
1664            // Get the popup list
1665            Accessible a = getUI().getAccessibleChild(JComboBox.this, 0);
1666            if (a instanceof javax.swing.plaf.basic.ComboPopup) {
1667                // Listen for changes to the popup menu selection.
1668                popupList = ((javax.swing.plaf.basic.ComboPopup)a).getList();
1669                popupList.addListSelectionListener(
1670                    new AccessibleJComboBoxListSelectionListener());
1671            }
1672            // Listen for popup menu show/hide events
1673            JComboBox.this.addPopupMenuListener(
1674              new AccessibleJComboBoxPopupMenuListener());
1675        }
1676
1677        /*
1678         * JComboBox PropertyChangeListener
1679         */
1680        private class AccessibleJComboBoxPropertyChangeListener
1681            implements PropertyChangeListener {
1682
1683            public void propertyChange(PropertyChangeEvent e) {
1684                if (e.getPropertyName() == "editor") {
1685                    // set the combo box editor's accessible name
1686                    // and description
1687                    setEditorNameAndDescription();
1688                }
1689            }
1690        }
1691
1692        /*
1693         * Sets the combo box editor's accessible name and descripton
1694         */
1695        private void setEditorNameAndDescription() {
1696            ComboBoxEditor editor = JComboBox.this.getEditor();
1697            if (editor != null) {
1698                Component comp = editor.getEditorComponent();
1699                if (comp instanceof Accessible) {
1700                    AccessibleContext ac = comp.getAccessibleContext();
1701                    if (ac != null) { // may be null
1702                        ac.setAccessibleName(getAccessibleName());
1703                        ac.setAccessibleDescription(getAccessibleDescription());
1704                    }
1705                }
1706            }
1707        }
1708
1709        /*
1710         * Listener for combo box popup menu
1711         * TIGER - 4669379 4894434
1712         */
1713        private class AccessibleJComboBoxPopupMenuListener
1714            implements PopupMenuListener {
1715
1716            /**
1717             *  This method is called before the popup menu becomes visible
1718             */
1719            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
1720                // save the initial selection
1721                if (popupList == null) {
1722                    return;
1723                }
1724                int selectedIndex = popupList.getSelectedIndex();
1725                if (selectedIndex < 0) {
1726                    return;
1727                }
1728                previousSelectedAccessible =
1729                    popupList.getAccessibleContext().getAccessibleChild(selectedIndex);
1730            }
1731
1732            /**
1733             * This method is called before the popup menu becomes invisible
1734             * Note that a JPopupMenu can become invisible any time
1735             */
1736            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
1737                // ignore
1738            }
1739
1740            /**
1741             * This method is called when the popup menu is canceled
1742             */
1743            public void popupMenuCanceled(PopupMenuEvent e) {
1744                // ignore
1745            }
1746        }
1747
1748        /*
1749         * Handles changes to the popup list selection.
1750         * TIGER - 4669379 4894434 4933143
1751         */
1752        private class AccessibleJComboBoxListSelectionListener
1753            implements ListSelectionListener {
1754
1755            public void valueChanged(ListSelectionEvent e) {
1756                if (popupList == null) {
1757                    return;
1758                }
1759
1760                // Get the selected popup list item.
1761                int selectedIndex = popupList.getSelectedIndex();
1762                if (selectedIndex < 0) {
1763                    return;
1764                }
1765                Accessible selectedAccessible =
1766                    popupList.getAccessibleContext().getAccessibleChild(selectedIndex);
1767                if (selectedAccessible == null) {
1768                    return;
1769                }
1770
1771                // Fire a FOCUSED lost PropertyChangeEvent for the
1772                // previously selected list item.
1773                PropertyChangeEvent pce;
1774
1775                if (previousSelectedAccessible != null) {
1776                    pce = new PropertyChangeEvent(previousSelectedAccessible,
1777                        AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
1778                        AccessibleState.FOCUSED, null);
1779                    firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
1780                                       null, pce);
1781                }
1782                // Fire a FOCUSED gained PropertyChangeEvent for the
1783                // currently selected list item.
1784                pce = new PropertyChangeEvent(selectedAccessible,
1785                    AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
1786                    null, AccessibleState.FOCUSED);
1787                firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
1788                                   null, pce);
1789
1790                // Fire the ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY event
1791                // for the combo box.
1792                firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
1793                                   previousSelectedAccessible, selectedAccessible);
1794
1795                // Save the previous selection.
1796                previousSelectedAccessible = selectedAccessible;
1797            }
1798        }
1799
1800
1801        /**
1802         * Returns the number of accessible children in the object.  If all
1803         * of the children of this object implement Accessible, than this
1804         * method should return the number of children of this object.
1805         *
1806         * @return the number of accessible children in the object.
1807         */
1808        public int getAccessibleChildrenCount() {
1809            // Always delegate to the UI if it exists
1810            if (ui != null) {
1811                return ui.getAccessibleChildrenCount(JComboBox.this);
1812            } else {
1813                return super.getAccessibleChildrenCount();
1814            }
1815        }
1816
1817        /**
1818         * Returns the nth Accessible child of the object.
1819         * The child at index zero represents the popup.
1820         * If the combo box is editable, the child at index one
1821         * represents the editor.
1822         *
1823         * @param i zero-based index of child
1824         * @return the nth Accessible child of the object
1825         */
1826        public Accessible getAccessibleChild(int i) {
1827            // Always delegate to the UI if it exists
1828            if (ui != null) {
1829                return ui.getAccessibleChild(JComboBox.this, i);
1830            } else {
1831               return super.getAccessibleChild(i);
1832            }
1833        }
1834
1835        /**
1836         * Get the role of this object.
1837         *
1838         * @return an instance of AccessibleRole describing the role of the
1839         * object
1840         * @see AccessibleRole
1841         */
1842        public AccessibleRole getAccessibleRole() {
1843            return AccessibleRole.COMBO_BOX;
1844        }
1845
1846        /**
1847         * Gets the state set of this object.  The AccessibleStateSet of
1848         * an object is composed of a set of unique AccessibleStates.
1849         * A change in the AccessibleStateSet of an object will cause a
1850         * PropertyChangeEvent to be fired for the ACCESSIBLE_STATE_PROPERTY
1851         * property.
1852         *
1853         * @return an instance of AccessibleStateSet containing the
1854         * current state set of the object
1855         * @see AccessibleStateSet
1856         * @see AccessibleState
1857         * @see #addPropertyChangeListener
1858         *
1859         */
1860        public AccessibleStateSet getAccessibleStateSet() {
1861            // TIGER - 4489748
1862            AccessibleStateSet ass = super.getAccessibleStateSet();
1863            if (ass == null) {
1864                ass = new AccessibleStateSet();
1865            }
1866            if (JComboBox.this.isPopupVisible()) {
1867                ass.add(AccessibleState.EXPANDED);
1868            } else {
1869                ass.add(AccessibleState.COLLAPSED);
1870            }
1871            return ass;
1872        }
1873
1874        /**
1875         * Get the AccessibleAction associated with this object.  In the
1876         * implementation of the Java Accessibility API for this class,
1877         * return this object, which is responsible for implementing the
1878         * AccessibleAction interface on behalf of itself.
1879         *
1880         * @return this object
1881         */
1882        public AccessibleAction getAccessibleAction() {
1883            return this;
1884        }
1885
1886        /**
1887         * Return a description of the specified action of the object.
1888         *
1889         * @param i zero-based index of the actions
1890         */
1891        public String getAccessibleActionDescription(int i) {
1892            if (i == 0) {
1893                return UIManager.getString("ComboBox.togglePopupText");
1894            }
1895            else {
1896                return null;
1897            }
1898        }
1899
1900        /**
1901         * Returns the number of Actions available in this object.  The
1902         * default behavior of a combo box is to have one action.
1903         *
1904         * @return 1, the number of Actions in this object
1905         */
1906        public int getAccessibleActionCount() {
1907            return 1;
1908        }
1909
1910        /**
1911         * Perform the specified Action on the object
1912         *
1913         * @param i zero-based index of actions
1914         * @return true if the action was performed; else false.
1915         */
1916        public boolean doAccessibleAction(int i) {
1917            if (i == 0) {
1918                setPopupVisible(!isPopupVisible());
1919                return true;
1920            }
1921            else {
1922                return false;
1923            }
1924        }
1925
1926
1927        /**
1928         * Get the AccessibleSelection associated with this object.  In the
1929         * implementation of the Java Accessibility API for this class,
1930         * return this object, which is responsible for implementing the
1931         * AccessibleSelection interface on behalf of itself.
1932         *
1933         * @return this object
1934         */
1935        public AccessibleSelection getAccessibleSelection() {
1936            return this;
1937        }
1938
1939        /**
1940         * Returns the number of Accessible children currently selected.
1941         * If no children are selected, the return value will be 0.
1942         *
1943         * @return the number of items currently selected.
1944         * @since 1.3
1945         */
1946        public int getAccessibleSelectionCount() {
1947            Object o = JComboBox.this.getSelectedItem();
1948            if (o != null) {
1949                return 1;
1950            } else {
1951                return 0;
1952            }
1953        }
1954
1955        /**
1956         * Returns an Accessible representing the specified selected child
1957         * in the popup.  If there isn't a selection, or there are
1958         * fewer children selected than the integer passed in, the return
1959         * value will be null.
1960         * <p>Note that the index represents the i-th selected child, which
1961         * is different from the i-th child.
1962         *
1963         * @param i the zero-based index of selected children
1964         * @return the i-th selected child
1965         * @see #getAccessibleSelectionCount
1966         * @since 1.3
1967         */
1968        public Accessible getAccessibleSelection(int i) {
1969            // Get the popup
1970            Accessible a =
1971                JComboBox.this.getUI().getAccessibleChild(JComboBox.this, 0);
1972            if (a != null &&
1973                a instanceof javax.swing.plaf.basic.ComboPopup) {
1974
1975                // get the popup list
1976                JList<?> list = ((javax.swing.plaf.basic.ComboPopup)a).getList();
1977
1978                // return the i-th selection in the popup list
1979                AccessibleContext ac = list.getAccessibleContext();
1980                if (ac != null) {
1981                    AccessibleSelection as = ac.getAccessibleSelection();
1982                    if (as != null) {
1983                        return as.getAccessibleSelection(i);
1984                    }
1985                }
1986            }
1987            return null;
1988        }
1989
1990        /**
1991         * Determines if the current child of this object is selected.
1992         *
1993         * @return true if the current child of this object is selected;
1994         *              else false
1995         * @param i the zero-based index of the child in this Accessible
1996         * object.
1997         * @see AccessibleContext#getAccessibleChild
1998         * @since 1.3
1999         */
2000        public boolean isAccessibleChildSelected(int i) {
2001            return JComboBox.this.getSelectedIndex() == i;
2002        }
2003
2004        /**
2005         * Adds the specified Accessible child of the object to the object's
2006         * selection.  If the object supports multiple selections,
2007         * the specified child is added to any existing selection, otherwise
2008         * it replaces any existing selection in the object.  If the
2009         * specified child is already selected, this method has no effect.
2010         *
2011         * @param i the zero-based index of the child
2012         * @see AccessibleContext#getAccessibleChild
2013         * @since 1.3
2014         */
2015        public void addAccessibleSelection(int i) {
2016            // TIGER - 4856195
2017            clearAccessibleSelection();
2018            JComboBox.this.setSelectedIndex(i);
2019        }
2020
2021        /**
2022         * Removes the specified child of the object from the object's
2023         * selection.  If the specified item isn't currently selected, this
2024         * method has no effect.
2025         *
2026         * @param i the zero-based index of the child
2027         * @see AccessibleContext#getAccessibleChild
2028         * @since 1.3
2029         */
2030        public void removeAccessibleSelection(int i) {
2031            if (JComboBox.this.getSelectedIndex() == i) {
2032                clearAccessibleSelection();
2033            }
2034        }
2035
2036        /**
2037         * Clears the selection in the object, so that no children in the
2038         * object are selected.
2039         * @since 1.3
2040         */
2041        public void clearAccessibleSelection() {
2042            JComboBox.this.setSelectedIndex(-1);
2043        }
2044
2045        /**
2046         * Causes every child of the object to be selected
2047         * if the object supports multiple selections.
2048         * @since 1.3
2049         */
2050        public void selectAllAccessibleSelection() {
2051            // do nothing since multiple selection is not supported
2052        }
2053
2054//        public Accessible getAccessibleAt(Point p) {
2055//            Accessible a = getAccessibleChild(1);
2056//            if ( a != null ) {
2057//                return a; // the editor
2058//            }
2059//            else {
2060//                return getAccessibleChild(0); // the list
2061//            }
2062//        }
2063        private EditorAccessibleContext editorAccessibleContext = null;
2064
2065        private class AccessibleEditor implements Accessible {
2066            public AccessibleContext getAccessibleContext() {
2067                if (editorAccessibleContext == null) {
2068                    Component c = JComboBox.this.getEditor().getEditorComponent();
2069                    if (c instanceof Accessible) {
2070                        editorAccessibleContext =
2071                            new EditorAccessibleContext((Accessible)c);
2072                    }
2073                }
2074                return editorAccessibleContext;
2075            }
2076        }
2077
2078        /*
2079         * Wrapper class for the AccessibleContext implemented by the
2080         * combo box editor.  Delegates all method calls except
2081         * getAccessibleIndexInParent to the editor.  The
2082         * getAccessibleIndexInParent method returns the selected
2083         * index in the combo box.
2084         */
2085        private class EditorAccessibleContext extends AccessibleContext {
2086
2087            private AccessibleContext ac;
2088
2089            private EditorAccessibleContext() {
2090            }
2091
2092            /*
2093             * @param a the AccessibleContext implemented by the
2094             * combo box editor
2095             */
2096            EditorAccessibleContext(Accessible a) {
2097                this.ac = a.getAccessibleContext();
2098            }
2099
2100            /**
2101             * Gets the accessibleName property of this object.  The accessibleName
2102             * property of an object is a localized String that designates the purpose
2103             * of the object.  For example, the accessibleName property of a label
2104             * or button might be the text of the label or button itself.  In the
2105             * case of an object that doesn't display its name, the accessibleName
2106             * should still be set.  For example, in the case of a text field used
2107             * to enter the name of a city, the accessibleName for the en_US locale
2108             * could be 'city.'
2109             *
2110             * @return the localized name of the object; null if this
2111             * object does not have a name
2112             *
2113             * @see #setAccessibleName
2114             */
2115            public String getAccessibleName() {
2116                return ac.getAccessibleName();
2117            }
2118
2119            /**
2120             * Sets the localized accessible name of this object.  Changing the
2121             * name will cause a PropertyChangeEvent to be fired for the
2122             * ACCESSIBLE_NAME_PROPERTY property.
2123             *
2124             * @param s the new localized name of the object.
2125             *
2126             * @see #getAccessibleName
2127             * @see #addPropertyChangeListener
2128             */
2129            @BeanProperty(preferred = true, description
2130                    = "Sets the accessible name for the component.")
2131            public void setAccessibleName(String s) {
2132                ac.setAccessibleName(s);
2133            }
2134
2135            /**
2136             * Gets the accessibleDescription property of this object.  The
2137             * accessibleDescription property of this object is a short localized
2138             * phrase describing the purpose of the object.  For example, in the
2139             * case of a 'Cancel' button, the accessibleDescription could be
2140             * 'Ignore changes and close dialog box.'
2141             *
2142             * @return the localized description of the object; null if
2143             * this object does not have a description
2144             *
2145             * @see #setAccessibleDescription
2146             */
2147            public String getAccessibleDescription() {
2148                return ac.getAccessibleDescription();
2149            }
2150
2151            /**
2152             * Sets the accessible description of this object.  Changing the
2153             * name will cause a PropertyChangeEvent to be fired for the
2154             * ACCESSIBLE_DESCRIPTION_PROPERTY property.
2155             *
2156             * @param s the new localized description of the object
2157             *
2158             * @see #setAccessibleName
2159             * @see #addPropertyChangeListener
2160             */
2161            @BeanProperty(preferred = true, description
2162                    = "Sets the accessible description for the component.")
2163            public void setAccessibleDescription(String s) {
2164                ac.setAccessibleDescription(s);
2165            }
2166
2167            /**
2168             * Gets the role of this object.  The role of the object is the generic
2169             * purpose or use of the class of this object.  For example, the role
2170             * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in
2171             * AccessibleRole are provided so component developers can pick from
2172             * a set of predefined roles.  This enables assistive technologies to
2173             * provide a consistent interface to various tweaked subclasses of
2174             * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
2175             * that act like a push button) as well as distinguish between subclasses
2176             * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
2177             * and AccessibleRole.RADIO_BUTTON for radio buttons).
2178             * <p>Note that the AccessibleRole class is also extensible, so
2179             * custom component developers can define their own AccessibleRole's
2180             * if the set of predefined roles is inadequate.
2181             *
2182             * @return an instance of AccessibleRole describing the role of the object
2183             * @see AccessibleRole
2184             */
2185            public AccessibleRole getAccessibleRole() {
2186                return ac.getAccessibleRole();
2187            }
2188
2189            /**
2190             * Gets the state set of this object.  The AccessibleStateSet of an object
2191             * is composed of a set of unique AccessibleStates.  A change in the
2192             * AccessibleStateSet of an object will cause a PropertyChangeEvent to
2193             * be fired for the ACCESSIBLE_STATE_PROPERTY property.
2194             *
2195             * @return an instance of AccessibleStateSet containing the
2196             * current state set of the object
2197             * @see AccessibleStateSet
2198             * @see AccessibleState
2199             * @see #addPropertyChangeListener
2200             */
2201            public AccessibleStateSet getAccessibleStateSet() {
2202                return ac.getAccessibleStateSet();
2203            }
2204
2205            /**
2206             * Gets the Accessible parent of this object.
2207             *
2208             * @return the Accessible parent of this object; null if this
2209             * object does not have an Accessible parent
2210             */
2211            public Accessible getAccessibleParent() {
2212                return ac.getAccessibleParent();
2213            }
2214
2215            /**
2216             * Sets the Accessible parent of this object.  This is meant to be used
2217             * only in the situations where the actual component's parent should
2218             * not be treated as the component's accessible parent and is a method
2219             * that should only be called by the parent of the accessible child.
2220             *
2221             * @param a - Accessible to be set as the parent
2222             */
2223            public void setAccessibleParent(Accessible a) {
2224                ac.setAccessibleParent(a);
2225            }
2226
2227            /**
2228             * Gets the 0-based index of this object in its accessible parent.
2229             *
2230             * @return the 0-based index of this object in its parent; -1 if this
2231             * object does not have an accessible parent.
2232             *
2233             * @see #getAccessibleParent
2234             * @see #getAccessibleChildrenCount
2235             * @see #getAccessibleChild
2236             */
2237            public int getAccessibleIndexInParent() {
2238                return JComboBox.this.getSelectedIndex();
2239            }
2240
2241            /**
2242             * Returns the number of accessible children of the object.
2243             *
2244             * @return the number of accessible children of the object.
2245             */
2246            public int getAccessibleChildrenCount() {
2247                return ac.getAccessibleChildrenCount();
2248            }
2249
2250            /**
2251             * Returns the specified Accessible child of the object.  The Accessible
2252             * children of an Accessible object are zero-based, so the first child
2253             * of an Accessible child is at index 0, the second child is at index 1,
2254             * and so on.
2255             *
2256             * @param i zero-based index of child
2257             * @return the Accessible child of the object
2258             * @see #getAccessibleChildrenCount
2259             */
2260            public Accessible getAccessibleChild(int i) {
2261                return ac.getAccessibleChild(i);
2262            }
2263
2264            /**
2265             * Gets the locale of the component. If the component does not have a
2266             * locale, then the locale of its parent is returned.
2267             *
2268             * @return this component's locale.  If this component does not have
2269             * a locale, the locale of its parent is returned.
2270             *
2271             * @exception IllegalComponentStateException
2272             * If the Component does not have its own locale and has not yet been
2273             * added to a containment hierarchy such that the locale can be
2274             * determined from the containing parent.
2275             */
2276            public Locale getLocale() throws IllegalComponentStateException {
2277                return ac.getLocale();
2278            }
2279
2280            /**
2281             * Adds a PropertyChangeListener to the listener list.
2282             * The listener is registered for all Accessible properties and will
2283             * be called when those properties change.
2284             *
2285             * @see #ACCESSIBLE_NAME_PROPERTY
2286             * @see #ACCESSIBLE_DESCRIPTION_PROPERTY
2287             * @see #ACCESSIBLE_STATE_PROPERTY
2288             * @see #ACCESSIBLE_VALUE_PROPERTY
2289             * @see #ACCESSIBLE_SELECTION_PROPERTY
2290             * @see #ACCESSIBLE_TEXT_PROPERTY
2291             * @see #ACCESSIBLE_VISIBLE_DATA_PROPERTY
2292             *
2293             * @param listener  The PropertyChangeListener to be added
2294             */
2295            public void addPropertyChangeListener(PropertyChangeListener listener) {
2296                ac.addPropertyChangeListener(listener);
2297            }
2298
2299            /**
2300             * Removes a PropertyChangeListener from the listener list.
2301             * This removes a PropertyChangeListener that was registered
2302             * for all properties.
2303             *
2304             * @param listener  The PropertyChangeListener to be removed
2305             */
2306            public void removePropertyChangeListener(PropertyChangeListener listener) {
2307                ac.removePropertyChangeListener(listener);
2308            }
2309
2310            /**
2311             * Gets the AccessibleAction associated with this object that supports
2312             * one or more actions.
2313             *
2314             * @return AccessibleAction if supported by object; else return null
2315             * @see AccessibleAction
2316             */
2317            public AccessibleAction getAccessibleAction() {
2318                return ac.getAccessibleAction();
2319            }
2320
2321            /**
2322             * Gets the AccessibleComponent associated with this object that has a
2323             * graphical representation.
2324             *
2325             * @return AccessibleComponent if supported by object; else return null
2326             * @see AccessibleComponent
2327             */
2328            public AccessibleComponent getAccessibleComponent() {
2329                return ac.getAccessibleComponent();
2330            }
2331
2332            /**
2333             * Gets the AccessibleSelection associated with this object which allows its
2334             * Accessible children to be selected.
2335             *
2336             * @return AccessibleSelection if supported by object; else return null
2337             * @see AccessibleSelection
2338             */
2339            public AccessibleSelection getAccessibleSelection() {
2340                return ac.getAccessibleSelection();
2341            }
2342
2343            /**
2344             * Gets the AccessibleText associated with this object presenting
2345             * text on the display.
2346             *
2347             * @return AccessibleText if supported by object; else return null
2348             * @see AccessibleText
2349             */
2350            public AccessibleText getAccessibleText() {
2351                return ac.getAccessibleText();
2352            }
2353
2354            /**
2355             * Gets the AccessibleEditableText associated with this object
2356             * presenting editable text on the display.
2357             *
2358             * @return AccessibleEditableText if supported by object; else return null
2359             * @see AccessibleEditableText
2360             */
2361            public AccessibleEditableText getAccessibleEditableText() {
2362                return ac.getAccessibleEditableText();
2363            }
2364
2365            /**
2366             * Gets the AccessibleValue associated with this object that supports a
2367             * Numerical value.
2368             *
2369             * @return AccessibleValue if supported by object; else return null
2370             * @see AccessibleValue
2371             */
2372            public AccessibleValue getAccessibleValue() {
2373                return ac.getAccessibleValue();
2374            }
2375
2376            /**
2377             * Gets the AccessibleIcons associated with an object that has
2378             * one or more associated icons
2379             *
2380             * @return an array of AccessibleIcon if supported by object;
2381             * otherwise return null
2382             * @see AccessibleIcon
2383             */
2384            public AccessibleIcon [] getAccessibleIcon() {
2385                return ac.getAccessibleIcon();
2386            }
2387
2388            /**
2389             * Gets the AccessibleRelationSet associated with an object
2390             *
2391             * @return an AccessibleRelationSet if supported by object;
2392             * otherwise return null
2393             * @see AccessibleRelationSet
2394             */
2395            public AccessibleRelationSet getAccessibleRelationSet() {
2396                return ac.getAccessibleRelationSet();
2397            }
2398
2399            /**
2400             * Gets the AccessibleTable associated with an object
2401             *
2402             * @return an AccessibleTable if supported by object;
2403             * otherwise return null
2404             * @see AccessibleTable
2405             */
2406            public AccessibleTable getAccessibleTable() {
2407                return ac.getAccessibleTable();
2408            }
2409
2410            /**
2411             * Support for reporting bound property changes.  If oldValue and
2412             * newValue are not equal and the PropertyChangeEvent listener list
2413             * is not empty, then fire a PropertyChange event to each listener.
2414             * In general, this is for use by the Accessible objects themselves
2415             * and should not be called by an application program.
2416             * @param propertyName  The programmatic name of the property that
2417             * was changed.
2418             * @param oldValue  The old value of the property.
2419             * @param newValue  The new value of the property.
2420             * @see java.beans.PropertyChangeSupport
2421             * @see #addPropertyChangeListener
2422             * @see #removePropertyChangeListener
2423             * @see #ACCESSIBLE_NAME_PROPERTY
2424             * @see #ACCESSIBLE_DESCRIPTION_PROPERTY
2425             * @see #ACCESSIBLE_STATE_PROPERTY
2426             * @see #ACCESSIBLE_VALUE_PROPERTY
2427             * @see #ACCESSIBLE_SELECTION_PROPERTY
2428             * @see #ACCESSIBLE_TEXT_PROPERTY
2429             * @see #ACCESSIBLE_VISIBLE_DATA_PROPERTY
2430             */
2431            public void firePropertyChange(String propertyName,
2432                                           Object oldValue,
2433                                           Object newValue) {
2434                ac.firePropertyChange(propertyName, oldValue, newValue);
2435            }
2436        }
2437
2438    } // innerclass AccessibleJComboBox
2439}
2440