    rev 48858 : Work in progress for JDK-6303622
    Use generic in Swing components like JComboBox
    1. Added generic return type and parameter type for JComboBox.
    2. Modified JList related classes as well.
    3. Reverted the changes made to "getSelectedValues" as suggested by Joe.
    4. Modified files that were failing on Linux and Mac as well.

       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  */
      25 package javax.swing;
      26
      27 import java.beans.JavaBean;
      28 import java.beans.BeanProperty;
      29 import java.beans.PropertyChangeEvent;
      30 import java.beans.PropertyChangeListener;
      31 import java.beans.Transient;
      32 import java.util.*;
      33
      34 import java.awt.*;
      35 import java.awt.event.*;
      36
      37 import java.io.Serializable;
      38 import java.io.ObjectOutputStream;
      39 import java.io.IOException;
      40
      41 import javax.swing.event.*;
      42 import javax.swing.plaf.*;
      43
      44 import 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
      83 public class JComboBox<E> extends JComponent
      84 implements 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 E 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 <E> the type of the elements of this comboBox.
     548      * @param anObject  the list object to select; use <code>null</code> to
     549                         clear the selection
     550      */
     551     @BeanProperty(bound = false, preferred = true, description
     552             = "Sets the selected item in the JComboBox.")
     553     public void setSelectedItem(E anObject) {
     554         E oldSelection = selectedItemReminder;
     555         E objectToSelect = anObject;
     556         if (oldSelection == null || !oldSelection.equals(anObject)) {
     557
     558             if (anObject != null && !isEditable()) {
     559                 // For non editable combo boxes, an invalid selection
     560                 // will be rejected.
     561                 boolean found = false;
     562                 for (int i = 0; i < dataModel.getSize(); i++) {
     563                     E element = dataModel.getElementAt(i);
     564                     if (anObject.equals(element)) {
     565                         found = true;
     566                         objectToSelect = element;
     567                         break;
     568                     }
     569                 }
     570                 if (!found) {
     571                     return;
     572                 }
     573
     574                 getEditor().setItem(anObject);
     575             }
     576
     577             // Must toggle the state of this flag since this method
     578             // call may result in ListDataEvents being fired.
     579             selectingItem = true;
     580             dataModel.setSelectedItem(objectToSelect);
     581             selectingItem = false;
     582
     583             if (selectedItemReminder != dataModel.getSelectedItem()) {
     584                 // in case a users implementation of ComboBoxModel
     585                 // doesn't fire a ListDataEvent when the selection
     586                 // changes.
     587                 selectedItemChanged();
     588             }
     589         }
     590         fireActionEvent();
     591     }
     592
     593     /**
     594      * Returns the current selected item.
     595      * <p>
     596      * If the combo box is editable, then this value may not have been added
     597      * to the combo box with <code>addItem</code>, <code>insertItemAt</code>
     598      * or the data constructors.
     599      *
     600      * @param <E> the type of the elements of comboBox.
     601      * @return the current selected Object
     602      * @see #setSelectedItem
     603      */
     604     public E getSelectedItem() {
     605         return dataModel.getSelectedItem();
     606     }
     607
     608     /**
     609      * Selects the item at index <code>anIndex</code>.
     610      *
     611      * @param anIndex an integer specifying the list item to select,
     612      *                  where 0 specifies the first item in the list and -1 indicates no selection
     613      * @exception IllegalArgumentException if <code>anIndex</code> &lt; -1 or
     614      *                  <code>anIndex</code> is greater than or equal to size
     615      */
     616     @BeanProperty(bound = false, preferred = true, description
     617             = "The item at index is selected.")
     618     public void setSelectedIndex(int anIndex) {
     619         int size = dataModel.getSize();
     620
     621         if ( anIndex == -1 ) {
     622             setSelectedItem( null );
     623         } else if ( anIndex < -1 || anIndex >= size ) {
     624             throw new IllegalArgumentException("setSelectedIndex: " + anIndex + " out of bounds");
     625         } else {
     626             setSelectedItem(dataModel.getElementAt(anIndex));
     627         }
     628     }
     629
     630     /**
     631      * Returns the first item in the list that matches the given item.
     632      * The result is not always defined if the <code>JComboBox</code>
     633      * allows selected items that are not in the list.
     634      * Returns -1 if there is no selected item or if the user specified
     635      * an item which is not in the list.
     636
     637      * @return an integer specifying the currently selected list item,
     638      *                  where 0 specifies
     639      *                  the first item in the list;
     640      *                  or -1 if no item is selected or if
     641      *                  the currently selected item is not in the list
     642      */
     643     @Transient
     644     public int getSelectedIndex() {
     645         E sObject = dataModel.getSelectedItem();

     646
     647         for ( int i=0,c=dataModel.getSize();i<c;i++ ) {
     648             E 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 <E> the type of the elements of this comboBox.
     740      * @param anObject  the object to remove from the item list
     741      * @see MutableComboBoxModel
     742      */
     743     public void removeItem(E anObject) {
     744         checkMutableComboBoxModel();
     745         ((MutableComboBoxModel<E>)dataModel).removeElement(anObject);
     746     }
     747
     748     /**
     749      * Removes the item at <code>anIndex</code>
     750      * This method works only if the <code>JComboBox</code> uses a
     751      * mutable data model.
     752      *
     753      * @param anIndex  an int specifying the index of the item to remove,
     754      *                  where 0
     755      *                  indicates the first item in the list
     756      * @see MutableComboBoxModel
     757      */
     758     public void removeItemAt(int anIndex) {
     759         checkMutableComboBoxModel();
     760         ((MutableComboBoxModel<E>)dataModel).removeElementAt( anIndex );
     761     }
     762
     763     /**
     764      * Removes all items from the item list.
     765      */
     766     public void removeAllItems() {
     767         checkMutableComboBoxModel();
     768         MutableComboBoxModel<E> model = (MutableComboBoxModel<E>)dataModel;
     769         int size = model.getSize();
     770
     771         if ( model instanceof DefaultComboBoxModel ) {
     772             ((DefaultComboBoxModel)model).removeAllElements();
     773         }
     774         else {
     775             for ( int i = 0; i < size; ++i ) {
     776                 E element = model.getElementAt( 0 );
     777                 model.removeElement( element );
     778             }
     779         }
     780         selectedItemReminder = null;
     781         if (isEditable()) {
     782             editor.setItem(null);
     783         }
     784     }
     785
     786     /**
     787      * Checks that the <code>dataModel</code> is an instance of
     788      * <code>MutableComboBoxModel</code>.  If not, it throws an exception.
     789      * @exception RuntimeException if <code>dataModel</code> is not an
     790      *          instance of <code>MutableComboBoxModel</code>.
     791      */
     792     void checkMutableComboBoxModel() {
     793         if ( !(dataModel instanceof MutableComboBoxModel) )
     794             throw new RuntimeException("Cannot use this method with a non-Mutable data model.");
     795     }
     796
     797     /**
     798      * Causes the combo box to display its popup window.
     799      * @see #setPopupVisible
     800      */
     801     public void showPopup() {
     802         setPopupVisible(true);
     803     }
     804
     805     /**
     806      * Causes the combo box to close its popup window.
     807      * @see #setPopupVisible
     808      */
     809     public void hidePopup() {
     810         setPopupVisible(false);
     811     }
     812
     813     /**
     814      * Sets the visibility of the popup.
     815      *
     816      * @param v if {@code true} shows the popup, otherwise, hides the popup.
     817      */
     818     public void setPopupVisible(boolean v) {
     819         getUI().setPopupVisible(this, v);
     820     }
     821
     822     /**
     823      * Determines the visibility of the popup.
     824      *
     825      * @return true if the popup is visible, otherwise returns false
     826      */
     827     public boolean isPopupVisible() {
     828         return getUI().isPopupVisible(this);
     829     }
     830
     831     /** Selection **/
     832
     833     /**
     834      * Adds an <code>ItemListener</code>.
     835      * <p>
     836      * <code>aListener</code> will receive one or two <code>ItemEvent</code>s when
     837      * the selected item changes.
     838      *
     839      * @param aListener the <code>ItemListener</code> that is to be notified
     840      * @see #setSelectedItem
     841      */
     842     public void addItemListener(ItemListener aListener) {
     843         listenerList.add(ItemListener.class,aListener);
     844     }
     845
     846     /** Removes an <code>ItemListener</code>.
     847      *
     848      * @param aListener  the <code>ItemListener</code> to remove
     849      */
     850     public void removeItemListener(ItemListener aListener) {
     851         listenerList.remove(ItemListener.class,aListener);
     852     }
     853
     854     /**
     855      * Returns an array of all the <code>ItemListener</code>s added
     856      * to this JComboBox with addItemListener().
     857      *
     858      * @return all of the <code>ItemListener</code>s added or an empty
     859      *         array if no listeners have been added
     860      * @since 1.4
     861      */
     862     @BeanProperty(bound = false)
     863     public ItemListener[] getItemListeners() {
     864         return listenerList.getListeners(ItemListener.class);
     865     }
     866
     867     /**
     868      * Adds an <code>ActionListener</code>.
     869      * <p>
     870      * The <code>ActionListener</code> will receive an <code>ActionEvent</code>
     871      * when a selection has been made. If the combo box is editable, then
     872      * an <code>ActionEvent</code> will be fired when editing has stopped.
     873      *
     874      * @param l  the <code>ActionListener</code> that is to be notified
     875      * @see #setSelectedItem
     876      */
     877     public void addActionListener(ActionListener l) {
     878         listenerList.add(ActionListener.class,l);
     879     }
     880
     881     /** Removes an <code>ActionListener</code>.
     882      *
     883      * @param l  the <code>ActionListener</code> to remove
     884      */
     885     public void removeActionListener(ActionListener l) {
     886         if ((l != null) && (getAction() == l)) {
     887             setAction(null);
     888         } else {
     889             listenerList.remove(ActionListener.class, l);
     890         }
     891     }
     892
     893     /**
     894      * Returns an array of all the <code>ActionListener</code>s added
     895      * to this JComboBox with addActionListener().
     896      *
     897      * @return all of the <code>ActionListener</code>s added or an empty
     898      *         array if no listeners have been added
     899      * @since 1.4
     900      */
     901     @BeanProperty(bound = false)
     902     public ActionListener[] getActionListeners() {
     903         return listenerList.getListeners(ActionListener.class);
     904     }
     905
     906     /**
     907      * Adds a <code>PopupMenu</code> listener which will listen to notification
     908      * messages from the popup portion of the combo box.
     909      * <p>
     910      * For all standard look and feels shipped with Java, the popup list
     911      * portion of combo box is implemented as a <code>JPopupMenu</code>.
     912      * A custom look and feel may not implement it this way and will
     913      * therefore not receive the notification.
     914      *
     915      * @param l  the <code>PopupMenuListener</code> to add
     916      * @since 1.4
     917      */
     918     public void addPopupMenuListener(PopupMenuListener l) {
     919         listenerList.add(PopupMenuListener.class,l);
     920     }
     921
     922     /**
     923      * Removes a <code>PopupMenuListener</code>.
     924      *
     925      * @param l  the <code>PopupMenuListener</code> to remove
     926      * @see #addPopupMenuListener
     927      * @since 1.4
     928      */
     929     public void removePopupMenuListener(PopupMenuListener l) {
     930         listenerList.remove(PopupMenuListener.class,l);
     931     }
     932
     933     /**
     934      * Returns an array of all the <code>PopupMenuListener</code>s added
     935      * to this JComboBox with addPopupMenuListener().
     936      *
     937      * @return all of the <code>PopupMenuListener</code>s added or an empty
     938      *         array if no listeners have been added
     939      * @since 1.4
     940      */
     941     @BeanProperty(bound = false)
     942     public PopupMenuListener[] getPopupMenuListeners() {
     943         return listenerList.getListeners(PopupMenuListener.class);
     944     }
     945
     946     /**
     947      * Notifies <code>PopupMenuListener</code>s that the popup portion of the
     948      * combo box will become visible.
     949      * <p>
     950      * This method is public but should not be called by anything other than
     951      * the UI delegate.
     952      * @see #addPopupMenuListener
     953      * @since 1.4
     954      */
     955     public void firePopupMenuWillBecomeVisible() {
     956         Object[] listeners = listenerList.getListenerList();
     957         PopupMenuEvent e=null;
     958         for (int i = listeners.length-2; i>=0; i-=2) {
     959             if (listeners[i]==PopupMenuListener.class) {
     960                 if (e == null)
     961                     e = new PopupMenuEvent(this);
     962                 ((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeVisible(e);
     963             }
     964         }
     965     }
     966
     967     /**
     968      * Notifies <code>PopupMenuListener</code>s that the popup portion of the
     969      * combo box has become invisible.
     970      * <p>
     971      * This method is public but should not be called by anything other than
     972      * the UI delegate.
     973      * @see #addPopupMenuListener
     974      * @since 1.4
     975      */
     976     public void firePopupMenuWillBecomeInvisible() {
     977         Object[] listeners = listenerList.getListenerList();
     978         PopupMenuEvent e=null;
     979         for (int i = listeners.length-2; i>=0; i-=2) {
     980             if (listeners[i]==PopupMenuListener.class) {
     981                 if (e == null)
     982                     e = new PopupMenuEvent(this);
     983                 ((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeInvisible(e);
     984             }
     985         }
     986     }
     987
     988     /**
     989      * Notifies <code>PopupMenuListener</code>s that the popup portion of the
     990      * combo box has been canceled.
     991      * <p>
     992      * This method is public but should not be called by anything other than
     993      * the UI delegate.
     994      * @see #addPopupMenuListener
     995      * @since 1.4
     996      */
     997     public void firePopupMenuCanceled() {
     998         Object[] listeners = listenerList.getListenerList();
     999         PopupMenuEvent e=null;
    1000         for (int i = listeners.length-2; i>=0; i-=2) {
    1001             if (listeners[i]==PopupMenuListener.class) {
    1002                 if (e == null)
    1003                     e = new PopupMenuEvent(this);
    1004                 ((PopupMenuListener)listeners[i+1]).popupMenuCanceled(e);
    1005             }
    1006         }
    1007     }
    1008
    1009     /**
    1010      * Sets the action command that should be included in the event
    1011      * sent to action listeners.
    1012      *
    1013      * @param aCommand  a string containing the "command" that is sent
    1014      *                  to action listeners; the same listener can then
    1015      *                  do different things depending on the command it
    1016      *                  receives
    1017      */
    1018     public void setActionCommand(String aCommand) {
    1019         actionCommand = aCommand;
    1020     }
    1021
    1022     /**
    1023      * Returns the action command that is included in the event sent to
    1024      * action listeners.
    1025      *
    1026      * @return  the string containing the "command" that is sent
    1027      *          to action listeners.
    1028      */
    1029     public String getActionCommand() {
    1030         return actionCommand;
    1031     }
    1032
    1033     private Action action;
    1034     private PropertyChangeListener actionPropertyChangeListener;
    1035
    1036     /**
    1037      * Sets the <code>Action</code> for the <code>ActionEvent</code> source.
    1038      * The new <code>Action</code> replaces any previously set
    1039      * <code>Action</code> but does not affect <code>ActionListeners</code>
    1040      * independently added with <code>addActionListener</code>.
    1041      * If the <code>Action</code> is already a registered
    1042      * <code>ActionListener</code> for the <code>ActionEvent</code> source,
    1043      * it is not re-registered.
    1044      * <p>
    1045      * Setting the <code>Action</code> results in immediately changing
    1046      * all the properties described in <a href="Action.html#buttonActions">
    1047      * Swing Components Supporting <code>Action</code></a>.
    1048      * Subsequently, the combobox's properties are automatically updated
    1049      * as the <code>Action</code>'s properties change.
    1050      * <p>
    1051      * This method uses three other methods to set
    1052      * and help track the <code>Action</code>'s property values.
    1053      * It uses the <code>configurePropertiesFromAction</code> method
    1054      * to immediately change the combobox's properties.
    1055      * To track changes in the <code>Action</code>'s property values,
    1056      * this method registers the <code>PropertyChangeListener</code>
    1057      * returned by <code>createActionPropertyChangeListener</code>. The
    1058      * default {@code PropertyChangeListener} invokes the
    1059      * {@code actionPropertyChanged} method when a property in the
    1060      * {@code Action} changes.
    1061      *
    1062      * @param a the <code>Action</code> for the <code>JComboBox</code>,
    1063      *                  or <code>null</code>.
    1064      * @since 1.3
    1065      * @see Action
    1066      * @see #getAction
    1067      * @see #configurePropertiesFromAction
    1068      * @see #createActionPropertyChangeListener
    1069      * @see #actionPropertyChanged
    1070      */
    1071     @BeanProperty(visualUpdate = true, description
    1072             = "the Action instance connected with this ActionEvent source")
    1073     public void setAction(Action a) {
    1074         Action oldValue = getAction();
    1075         if (action==null || !action.equals(a)) {
    1076             action = a;
    1077             if (oldValue!=null) {
    1078                 removeActionListener(oldValue);
    1079                 oldValue.removePropertyChangeListener(actionPropertyChangeListener);
    1080                 actionPropertyChangeListener = null;
    1081             }
    1082             configurePropertiesFromAction(action);
    1083             if (action!=null) {
    1084                 // Don't add if it is already a listener
    1085                 if (!isListener(ActionListener.class, action)) {
    1086                     addActionListener(action);
    1087                 }
    1088                 // Reverse linkage:
    1089                 actionPropertyChangeListener = createActionPropertyChangeListener(action);
    1090                 action.addPropertyChangeListener(actionPropertyChangeListener);
    1091             }
    1092             firePropertyChange("action", oldValue, action);
    1093         }
    1094     }
    1095
    1096     private boolean isListener(Class<?> c, ActionListener a) {
    1097         boolean isListener = false;
    1098         Object[] listeners = listenerList.getListenerList();
    1099         for (int i = listeners.length-2; i>=0; i-=2) {
    1100             if (listeners[i]==c && listeners[i+1]==a) {
    1101                     isListener=true;
    1102             }
    1103         }
    1104         return isListener;
    1105     }
    1106
    1107     /**
    1108      * Returns the currently set <code>Action</code> for this
    1109      * <code>ActionEvent</code> source, or <code>null</code> if no
    1110      * <code>Action</code> is set.
    1111      *
    1112      * @return the <code>Action</code> for this <code>ActionEvent</code>
    1113      *          source; or <code>null</code>
    1114      * @since 1.3
    1115      * @see Action
    1116      * @see #setAction
    1117      */
    1118     public Action getAction() {
    1119         return action;
    1120     }
    1121
    1122     /**
    1123      * Sets the properties on this combobox to match those in the specified
    1124      * <code>Action</code>.  Refer to <a href="Action.html#buttonActions">
    1125      * Swing Components Supporting <code>Action</code></a> for more
    1126      * details as to which properties this sets.
    1127      *
    1128      * @param a the <code>Action</code> from which to get the properties,
    1129      *          or <code>null</code>
    1130      * @since 1.3
    1131      * @see Action
    1132      * @see #setAction
    1133      */
    1134     protected void configurePropertiesFromAction(Action a) {
    1135         AbstractAction.setEnabledFromAction(this, a);
    1136         AbstractAction.setToolTipTextFromAction(this, a);
    1137         setActionCommandFromAction(a);
    1138     }
    1139
    1140     /**
    1141      * Creates and returns a <code>PropertyChangeListener</code> that is
    1142      * responsible for listening for changes from the specified
    1143      * <code>Action</code> and updating the appropriate properties.
    1144      * <p>
    1145      * <b>Warning:</b> If you subclass this do not create an anonymous
    1146      * inner class.  If you do the lifetime of the combobox will be tied to
    1147      * that of the <code>Action</code>.
    1148      *
    1149      * @param a the combobox's action
    1150      * @return the {@code PropertyChangeListener}
    1151      * @since 1.3
    1152      * @see Action
    1153      * @see #setAction
    1154      */
    1155     protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
    1156         return new ComboBoxActionPropertyChangeListener(this, a);
    1157     }
    1158
    1159     /**
    1160      * Updates the combobox's state in response to property changes in
    1161      * associated action. This method is invoked from the
    1162      * {@code PropertyChangeListener} returned from
    1163      * {@code createActionPropertyChangeListener}. Subclasses do not normally
    1164      * need to invoke this. Subclasses that support additional {@code Action}
    1165      * properties should override this and
    1166      * {@code configurePropertiesFromAction}.
    1167      * <p>
    1168      * Refer to the table at <a href="Action.html#buttonActions">
    1169      * Swing Components Supporting <code>Action</code></a> for a list of
    1170      * the properties this method sets.
    1171      *
    1172      * @param action the <code>Action</code> associated with this combobox
    1173      * @param propertyName the name of the property that changed
    1174      * @since 1.6
    1175      * @see Action
    1176      * @see #configurePropertiesFromAction
    1177      */
    1178     protected void actionPropertyChanged(Action action, String propertyName) {
    1179         if (propertyName == Action.ACTION_COMMAND_KEY) {
    1180             setActionCommandFromAction(action);
    1181         } else if (propertyName == "enabled") {
    1182             AbstractAction.setEnabledFromAction(this, action);
    1183         } else if (Action.SHORT_DESCRIPTION == propertyName) {
    1184             AbstractAction.setToolTipTextFromAction(this, action);
    1185         }
    1186     }
    1187
    1188     private void setActionCommandFromAction(Action a) {
    1189         setActionCommand((a != null) ?
    1190                              (String)a.getValue(Action.ACTION_COMMAND_KEY) :
    1191                              null);
    1192     }
    1193
    1194
    1195     private static class ComboBoxActionPropertyChangeListener
    1196                  extends ActionPropertyChangeListener<JComboBox<?>> {
    1197         ComboBoxActionPropertyChangeListener(JComboBox<?> b, Action a) {
    1198             super(b, a);
    1199         }
    1200         protected void actionPropertyChanged(JComboBox<?> cb,
    1201                                              Action action,
    1202                                              PropertyChangeEvent e) {
    1203             if (AbstractAction.shouldReconfigure(e)) {
    1204                 cb.configurePropertiesFromAction(action);
    1205             } else {
    1206                 cb.actionPropertyChanged(action, e.getPropertyName());
    1207             }
    1208         }
    1209     }
    1210
    1211     /**
    1212      * Notifies all listeners that have registered interest for
    1213      * notification on this event type.
    1214      * @param e  the event of interest
    1215      *
    1216      * @see EventListenerList
    1217      */
    1218     protected void fireItemStateChanged(ItemEvent e) {
    1219         // Guaranteed to return a non-null array
    1220         Object[] listeners = listenerList.getListenerList();
    1221         // Process the listeners last to first, notifying
    1222         // those that are interested in this event
    1223         for ( int i = listeners.length-2; i>=0; i-=2 ) {
    1224             if ( listeners[i]==ItemListener.class ) {
    1225                 // Lazily create the event:
    1226                 // if (changeEvent == null)
    1227                 // changeEvent = new ChangeEvent(this);
    1228                 ((ItemListener)listeners[i+1]).itemStateChanged(e);
    1229             }
    1230         }
    1231     }
    1232
    1233     /**
    1234      * Notifies all listeners that have registered interest for
    1235      * notification on this event type.
    1236      *
    1237      * @see EventListenerList
    1238      */
    1239     @SuppressWarnings("deprecation")
    1240     protected void fireActionEvent() {
    1241         if (!firingActionEvent) {
    1242             // Set flag to ensure that an infinite loop is not created
    1243             firingActionEvent = true;
    1244             ActionEvent e = null;
    1245             // Guaranteed to return a non-null array
    1246             Object[] listeners = listenerList.getListenerList();
    1247             long mostRecentEventTime = EventQueue.getMostRecentEventTime();
    1248             int modifiers = 0;
    1249             AWTEvent currentEvent = EventQueue.getCurrentEvent();
    1250             if (currentEvent instanceof InputEvent) {
    1251                 modifiers = ((InputEvent)currentEvent).getModifiers();
    1252             } else if (currentEvent instanceof ActionEvent) {
    1253                 modifiers = ((ActionEvent)currentEvent).getModifiers();
    1254             }
    1255             try {
    1256                 // Process the listeners last to first, notifying
    1257                 // those that are interested in this event
    1258                 for ( int i = listeners.length-2; i>=0; i-=2 ) {
    1259                     if ( listeners[i]==ActionListener.class ) {
    1260                         // Lazily create the event:
    1261                         if ( e == null )
    1262                             e = new ActionEvent(this,ActionEvent.ACTION_PERFORMED,
    1263                                                 getActionCommand(),
    1264                                                 mostRecentEventTime, modifiers);
    1265                         ((ActionListener)listeners[i+1]).actionPerformed(e);
    1266                     }
    1267                 }
    1268             } finally {
    1269                 firingActionEvent = false;
    1270             }
    1271         }
    1272     }
    1273
    1274     /**
    1275      * This protected method is implementation specific. Do not access directly
    1276      * or override.
    1277      */
    1278     protected void selectedItemChanged() {
    1279         if (selectedItemReminder != null ) {
    1280             fireItemStateChanged(new ItemEvent(this,ItemEvent.ITEM_STATE_CHANGED,
    1281                                                selectedItemReminder,
    1282                                                ItemEvent.DESELECTED));
    1283         }
    1284
    1285         // set the new selected item.
    1286         selectedItemReminder = dataModel.getSelectedItem();
    1287
    1288         if (selectedItemReminder != null ) {
    1289             fireItemStateChanged(new ItemEvent(this,ItemEvent.ITEM_STATE_CHANGED,
    1290                                                selectedItemReminder,
    1291                                                ItemEvent.SELECTED));
    1292         }
    1293     }
    1294
    1295     /**
    1296      * Returns an array containing the selected item.
    1297      * This method is implemented for compatibility with
    1298      * <code>ItemSelectable</code>.
    1299      *
    1300      * @param <E> the type of the elements of this comboBox.
    1301      * @return an array of <code>Objects</code> containing one
    1302      *          element -- the selected item
    1303      */
    1304     @BeanProperty(bound = false)
    1305     public Object[] getSelectedObjects() {
    1306         E selectedObject = getSelectedItem();
    1307         Object[] result = null;
    1308         if ( selectedObject == null ){
    1309             result = new Object[0];
    1310         }
    1311         else {
    1312             result = new Object[1];
    1313             result[0] = selectedObject;

    1314         }
    1315
    1316         return result;
    1317     }
    1318
    1319     /**
    1320      * This method is public as an implementation side effect.
    1321      * do not call or override.
    1322      */
    1323     @SuppressWarnings("unchecked")
    1324     public void actionPerformed(ActionEvent e) {
    1325         setPopupVisible(false);
    1326         getModel().setSelectedItem((E)getEditor().getItem());
    1327         String oldCommand = getActionCommand();
    1328         setActionCommand("comboBoxEdited");
    1329         fireActionEvent();
    1330         setActionCommand(oldCommand);
    1331     }
    1332
    1333     /**
    1334      * This method is public as an implementation side effect.
    1335      * do not call or override.
    1336      */
    1337     public void contentsChanged(ListDataEvent e) {
    1338         E oldSelection = selectedItemReminder;
    1339         E newSelection = dataModel.getSelectedItem();
    1340         if (oldSelection == null || !oldSelection.equals(newSelection)) {
    1341             selectedItemChanged();
    1342             if (!selectingItem) {
    1343                 fireActionEvent();
    1344             }
    1345         }
    1346     }
    1347
    1348     /**
    1349      * This method is public as an implementation side effect.
    1350      * do not call or override.
    1351      */
    1352     public void intervalAdded(ListDataEvent e) {
    1353         if (selectedItemReminder != dataModel.getSelectedItem()) {
    1354             selectedItemChanged();
    1355         }
    1356     }
    1357
    1358     /**
    1359      * This method is public as an implementation side effect.
    1360      * do not call or override.
    1361      */
    1362     public void intervalRemoved(ListDataEvent e) {
    1363         contentsChanged(e);
    1364     }
    1365
    1366     /**
    1367      * Selects the list item that corresponds to the specified keyboard
    1368      * character and returns true, if there is an item corresponding
    1369      * to that character.  Otherwise, returns false.
    1370      *
    1371      * @param keyChar a char, typically this is a keyboard key
    1372      *                  typed by the user
    1373      * @return {@code true} if there is an item corresponding to that character.
    1374      *         Otherwise, returns {@code false}.
    1375      */
    1376     public boolean selectWithKeyChar(char keyChar) {
    1377         int index;
    1378
    1379         if ( keySelectionManager == null )
    1380             keySelectionManager = createDefaultKeySelectionManager();
    1381
    1382         index = keySelectionManager.selectionForKey(keyChar,getModel());
    1383         if ( index != -1 ) {
    1384             setSelectedIndex(index);
    1385             return true;
    1386         }
    1387         else
    1388             return false;
    1389     }
    1390
    1391     /**
    1392      * Enables the combo box so that items can be selected. When the
    1393      * combo box is disabled, items cannot be selected and values
    1394      * cannot be typed into its field (if it is editable).
    1395      *
    1396      * @param b a boolean value, where true enables the component and
    1397      *          false disables it
    1398      */
    1399     @BeanProperty(preferred = true, description
    1400             = "The enabled state of the component.")
    1401     public void setEnabled(boolean b) {
    1402         super.setEnabled(b);
    1403         firePropertyChange( "enabled", !isEnabled(), isEnabled() );
    1404     }
    1405
    1406     /**
    1407      * Initializes the editor with the specified item.
    1408      *
    1409      * @param anEditor the <code>ComboBoxEditor</code> that displays
    1410      *                  the list item in the
    1411      *                  combo box field and allows it to be edited
    1412      * @param anItem   the object to display and edit in the field
    1413      */
    1414     public void configureEditor(ComboBoxEditor anEditor, Object anItem) {
    1415         anEditor.setItem(anItem);
    1416     }
    1417
    1418     /**
    1419      * Handles <code>KeyEvent</code>s, looking for the Tab key.
    1420      * If the Tab key is found, the popup window is closed.
    1421      *
    1422      * @param e  the <code>KeyEvent</code> containing the keyboard
    1423      *          key that was pressed
    1424      */
    1425     public void processKeyEvent(KeyEvent e) {
    1426         if ( e.getKeyCode() == KeyEvent.VK_TAB ) {
    1427             hidePopup();
    1428         }
    1429         super.processKeyEvent(e);
    1430     }
    1431
    1432     /**
    1433      * {@inheritDoc}
    1434      */
    1435     @Override
    1436     protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
    1437         if (super.processKeyBinding(ks, e, condition, pressed)) {
    1438             return true;
    1439         }
    1440
    1441         if (!isEditable() || condition != WHEN_FOCUSED || getEditor() == null
    1442                 || !Boolean.TRUE.equals(getClientProperty("JComboBox.isTableCellEditor"))) {
    1443             return false;
    1444         }
    1445
    1446         Component editorComponent = getEditor().getEditorComponent();
    1447         if (editorComponent instanceof JComponent) {
    1448             JComponent component = (JComponent) editorComponent;
    1449             return component.processKeyBinding(ks, e, WHEN_FOCUSED, pressed);
    1450         }
    1451         return false;
    1452     }
    1453
    1454     /**
    1455      * Sets the object that translates a keyboard character into a list
    1456      * selection. Typically, the first selection with a matching first
    1457      * character becomes the selected item.
    1458      *
    1459      * @param aManager a key selection manager
    1460      */
    1461     @BeanProperty(bound = false, expert = true, description
    1462             = "The objects that changes the selection when a key is pressed.")
    1463     public void setKeySelectionManager(KeySelectionManager aManager) {
    1464         keySelectionManager = aManager;
    1465     }
    1466
    1467     /**
    1468      * Returns the list's key-selection manager.
    1469      *
    1470      * @return the <code>KeySelectionManager</code> currently in use
    1471      */
    1472     public KeySelectionManager getKeySelectionManager() {
    1473         return keySelectionManager;
    1474     }
    1475
    1476     /* Accessing the model */
    1477     /**
    1478      * Returns the number of items in the list.
    1479      *
    1480      * @return an integer equal to the number of items in the list
    1481      */
    1482     @BeanProperty(bound = false)
    1483     public int getItemCount() {
    1484         return dataModel.getSize();
    1485     }
    1486
    1487     /**
    1488      * Returns the list item at the specified index.  If <code>index</code>
    1489      * is out of range (less than zero or greater than or equal to size)
    1490      * it will return <code>null</code>.
    1491      *
    1492      * @param index  an integer indicating the list position, where the first
    1493      *               item starts at zero
    1494      * @return the item at that list position; or
    1495      *                  <code>null</code> if out of range
    1496      */
    1497     public E getItemAt(int index) {
    1498         return dataModel.getElementAt(index);
    1499     }
    1500
    1501     /**
    1502      * Returns an instance of the default key-selection manager.
    1503      *
    1504      * @return the <code>KeySelectionManager</code> currently used by the list
    1505      * @see #setKeySelectionManager
    1506      */
    1507     protected KeySelectionManager createDefaultKeySelectionManager() {
    1508         return new DefaultKeySelectionManager();
    1509     }
    1510
    1511
    1512     /**
    1513      * The interface that defines a <code>KeySelectionManager</code>.
    1514      * To qualify as a <code>KeySelectionManager</code>,
    1515      * the class needs to implement the method
    1516      * that identifies the list index given a character and the
    1517      * combo box data model.
    1518      */
    1519     public interface KeySelectionManager {
    1520         /** Given <code>aKey</code> and the model, returns the row
    1521          *  that should become selected. Return -1 if no match was
    1522          *  found.
    1523          *
    1524          * @param  aKey  a char value, usually indicating a keyboard key that
    1525          *               was pressed
    1526          * @param aModel a ComboBoxModel -- the component's data model, containing
    1527          *               the list of selectable items
    1528          * @return an int equal to the selected row, where 0 is the
    1529          *         first item and -1 is none.
    1530          */
    1531         int selectionForKey(char aKey,ComboBoxModel<?> aModel);
    1532     }
    1533
    1534     class DefaultKeySelectionManager implements KeySelectionManager, Serializable {
    1535         public int selectionForKey(char aKey,ComboBoxModel<?> aModel) {
    1536             int i,c;
    1537             int currentSelection = -1;
    1538             Object selectedItem = aModel.getSelectedItem();
    1539             String v;
    1540             String pattern;
    1541
    1542             if ( selectedItem != null ) {
    1543                 for ( i=0,c=aModel.getSize();i<c;i++ ) {
    1544                     if ( selectedItem == aModel.getElementAt(i) ) {
    1545                         currentSelection  =  i;
    1546                         break;
    1547                     }
    1548                 }
    1549             }
    1550
    1551             pattern = ("" + aKey).toLowerCase();
    1552             aKey = pattern.charAt(0);
    1553
    1554             for ( i = ++currentSelection, c = aModel.getSize() ; i < c ; i++ ) {
    1555                 Object elem = aModel.getElementAt(i);
    1556                 if (elem != null && elem.toString() != null) {
    1557                     v = elem.toString().toLowerCase();
    1558                     if ( v.length() > 0 && v.charAt(0) == aKey )
    1559                         return i;
    1560                 }
    1561             }
    1562
    1563             for ( i = 0 ; i < currentSelection ; i ++ ) {
    1564                 Object elem = aModel.getElementAt(i);
    1565                 if (elem != null && elem.toString() != null) {
    1566                     v = elem.toString().toLowerCase();
    1567                     if ( v.length() > 0 && v.charAt(0) == aKey )
    1568                         return i;
    1569                 }
    1570             }
    1571             return -1;
    1572         }
    1573     }
    1574
    1575
    1576     /**
    1577      * See <code>readObject</code> and <code>writeObject</code> in
    1578      * <code>JComponent</code> for more
    1579      * information about serialization in Swing.
    1580      */
    1581     private void writeObject(ObjectOutputStream s) throws IOException {
    1582         s.defaultWriteObject();
    1583         if (getUIClassID().equals(uiClassID)) {
    1584             byte count = JComponent.getWriteObjCounter(this);
    1585             JComponent.setWriteObjCounter(this, --count);
    1586             if (count == 0 && ui != null) {
    1587                 ui.installUI(this);
    1588             }
    1589         }
    1590     }
    1591
    1592
    1593     /**
    1594      * Returns a string representation of this <code>JComboBox</code>.
    1595      * This method is intended to be used only for debugging purposes,
    1596      * and the content and format of the returned string may vary between
    1597      * implementations. The returned string may be empty but may not
    1598      * be <code>null</code>.
    1599      *
    1600      * @return  a string representation of this <code>JComboBox</code>
    1601      */
    1602     protected String paramString() {
    1603         String selectedItemReminderString = (selectedItemReminder != null ?
    1604                                              selectedItemReminder.toString() :
    1605                                              "");
    1606         String isEditableString = (isEditable ? "true" : "false");
    1607         String lightWeightPopupEnabledString = (lightWeightPopupEnabled ?
    1608                                                 "true" : "false");
    1609
    1610         return super.paramString() +
    1611         ",isEditable=" + isEditableString +
    1612         ",lightWeightPopupEnabled=" + lightWeightPopupEnabledString +
    1613         ",maximumRowCount=" + maximumRowCount +
    1614         ",selectedItemReminder=" + selectedItemReminderString;
    1615     }
    1616
    1617
    1618 ///////////////////
    1619 // Accessibility support
    1620 ///////////////////
    1621
    1622     /**
    1623      * Gets the AccessibleContext associated with this JComboBox.
    1624      * For combo boxes, the AccessibleContext takes the form of an
    1625      * AccessibleJComboBox.
    1626      * A new AccessibleJComboBox instance is created if necessary.
    1627      *
    1628      * @return an AccessibleJComboBox that serves as the
    1629      *         AccessibleContext of this JComboBox
    1630      */
    1631     @BeanProperty(bound = false)
    1632     public AccessibleContext getAccessibleContext() {
    1633         if ( accessibleContext == null ) {
    1634             accessibleContext = new AccessibleJComboBox();
    1635         }
    1636         return accessibleContext;
    1637     }
    1638
    1639     /**
    1640      * This class implements accessibility support for the
    1641      * <code>JComboBox</code> class.  It provides an implementation of the
    1642      * Java Accessibility API appropriate to Combo Box user-interface elements.
    1643      * <p>
    1644      * <strong>Warning:</strong>
    1645      * Serialized objects of this class will not be compatible with
    1646      * future Swing releases. The current serialization support is
    1647      * appropriate for short term storage or RMI between applications running
    1648      * the same version of Swing.  As of 1.4, support for long term storage
    1649      * of all JavaBeans&trade;
    1650      * has been added to the <code>java.beans</code> package.
    1651      * Please see {@link java.beans.XMLEncoder}.
    1652      */
    1653     @SuppressWarnings("serial") // Same-version serialization only
    1654     protected class AccessibleJComboBox extends AccessibleJComponent
    1655     implements AccessibleAction, AccessibleSelection {
    1656
    1657
    1658         private JList<?> popupList; // combo box popup list
    1659         private Accessible previousSelectedAccessible = null;
    1660
    1661         /**
    1662          * Returns an AccessibleJComboBox instance
    1663          * @since 1.4
    1664          */
    1665         public AccessibleJComboBox() {
    1666             // set the combo box editor's accessible name and description
    1667             JComboBox.this.addPropertyChangeListener(new AccessibleJComboBoxPropertyChangeListener());
    1668             setEditorNameAndDescription();
    1669
    1670             // Get the popup list
    1671             Accessible a = getUI().getAccessibleChild(JComboBox.this, 0);
    1672             if (a instanceof javax.swing.plaf.basic.ComboPopup) {
    1673                 // Listen for changes to the popup menu selection.
    1674                 popupList = ((javax.swing.plaf.basic.ComboPopup)a).getList();
    1675                 popupList.addListSelectionListener(
    1676                     new AccessibleJComboBoxListSelectionListener());
    1677             }
    1678             // Listen for popup menu show/hide events
    1679             JComboBox.this.addPopupMenuListener(
    1680               new AccessibleJComboBoxPopupMenuListener());
    1681         }
    1682
    1683         /*
    1684          * JComboBox PropertyChangeListener
    1685          */
    1686         private class AccessibleJComboBoxPropertyChangeListener
    1687             implements PropertyChangeListener {
    1688
    1689             public void propertyChange(PropertyChangeEvent e) {
    1690                 if (e.getPropertyName() == "editor") {
    1691                     // set the combo box editor's accessible name
    1692                     // and description
    1693                     setEditorNameAndDescription();
    1694                 }
    1695             }
    1696         }
    1697
    1698         /*
    1699          * Sets the combo box editor's accessible name and descripton
    1700          */
    1701         private void setEditorNameAndDescription() {
    1702             ComboBoxEditor editor = JComboBox.this.getEditor();
    1703             if (editor != null) {
    1704                 Component comp = editor.getEditorComponent();
    1705                 if (comp instanceof Accessible) {
    1706                     AccessibleContext ac = comp.getAccessibleContext();
    1707                     if (ac != null) { // may be null
    1708                         ac.setAccessibleName(getAccessibleName());
    1709                         ac.setAccessibleDescription(getAccessibleDescription());
    1710                     }
    1711                 }
    1712             }
    1713         }
    1714
    1715         /*
    1716          * Listener for combo box popup menu
    1717          * TIGER - 4669379 4894434
    1718          */
    1719         private class AccessibleJComboBoxPopupMenuListener
    1720             implements PopupMenuListener {
    1721
    1722             /**
    1723              *  This method is called before the popup menu becomes visible
    1724              */
    1725             public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
    1726                 // save the initial selection
    1727                 if (popupList == null) {
    1728                     return;
    1729                 }
    1730                 int selectedIndex = popupList.getSelectedIndex();
    1731                 if (selectedIndex < 0) {
    1732                     return;
    1733                 }
    1734                 previousSelectedAccessible =
    1735                     popupList.getAccessibleContext().getAccessibleChild(selectedIndex);
    1736             }
    1737
    1738             /**
    1739              * This method is called before the popup menu becomes invisible
    1740              * Note that a JPopupMenu can become invisible any time
    1741              */
    1742             public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
    1743                 // ignore
    1744             }
    1745
    1746             /**
    1747              * This method is called when the popup menu is canceled
    1748              */
    1749             public void popupMenuCanceled(PopupMenuEvent e) {
    1750                 // ignore
    1751             }
    1752         }
    1753
    1754         /*
    1755          * Handles changes to the popup list selection.
    1756          * TIGER - 4669379 4894434 4933143
    1757          */
    1758         private class AccessibleJComboBoxListSelectionListener
    1759             implements ListSelectionListener {
    1760
    1761             public void valueChanged(ListSelectionEvent e) {
    1762                 if (popupList == null) {
    1763                     return;
    1764                 }
    1765
    1766                 // Get the selected popup list item.
    1767                 int selectedIndex = popupList.getSelectedIndex();
    1768                 if (selectedIndex < 0) {
    1769                     return;
    1770                 }
    1771                 Accessible selectedAccessible =
    1772                     popupList.getAccessibleContext().getAccessibleChild(selectedIndex);
    1773                 if (selectedAccessible == null) {
    1774                     return;
    1775                 }
    1776
    1777                 // Fire a FOCUSED lost PropertyChangeEvent for the
    1778                 // previously selected list item.
    1779                 PropertyChangeEvent pce;
    1780
    1781                 if (previousSelectedAccessible != null) {
    1782                     pce = new PropertyChangeEvent(previousSelectedAccessible,
    1783                         AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
    1784                         AccessibleState.FOCUSED, null);
    1785                     firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
    1786                                        null, pce);
    1787                 }
    1788                 // Fire a FOCUSED gained PropertyChangeEvent for the
    1789                 // currently selected list item.
    1790                 pce = new PropertyChangeEvent(selectedAccessible,
    1791                     AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
    1792                     null, AccessibleState.FOCUSED);
    1793                 firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
    1794                                    null, pce);
    1795
    1796                 // Fire the ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY event
    1797                 // for the combo box.
    1798                 firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
    1799                                    previousSelectedAccessible, selectedAccessible);
    1800
    1801                 // Save the previous selection.
    1802                 previousSelectedAccessible = selectedAccessible;
    1803             }
    1804         }
    1805
    1806
    1807         /**
    1808          * Returns the number of accessible children in the object.  If all
    1809          * of the children of this object implement Accessible, than this
    1810          * method should return the number of children of this object.
    1811          *
    1812          * @return the number of accessible children in the object.
    1813          */
    1814         public int getAccessibleChildrenCount() {
    1815             // Always delegate to the UI if it exists
    1816             if (ui != null) {
    1817                 return ui.getAccessibleChildrenCount(JComboBox.this);
    1818             } else {
    1819                 return super.getAccessibleChildrenCount();
    1820             }
    1821         }
    1822
    1823         /**
    1824          * Returns the nth Accessible child of the object.
    1825          * The child at index zero represents the popup.
    1826          * If the combo box is editable, the child at index one
    1827          * represents the editor.
    1828          *
    1829          * @param i zero-based index of child
    1830          * @return the nth Accessible child of the object
    1831          */
    1832         public Accessible getAccessibleChild(int i) {
    1833             // Always delegate to the UI if it exists
    1834             if (ui != null) {
    1835                 return ui.getAccessibleChild(JComboBox.this, i);
    1836             } else {
    1837                return super.getAccessibleChild(i);
    1838             }
    1839         }
    1840
    1841         /**
    1842          * Get the role of this object.
    1843          *
    1844          * @return an instance of AccessibleRole describing the role of the
    1845          * object
    1846          * @see AccessibleRole
    1847          */
    1848         public AccessibleRole getAccessibleRole() {
    1849             return AccessibleRole.COMBO_BOX;
    1850         }
    1851
    1852         /**
    1853          * Gets the state set of this object.  The AccessibleStateSet of
    1854          * an object is composed of a set of unique AccessibleStates.
    1855          * A change in the AccessibleStateSet of an object will cause a
    1856          * PropertyChangeEvent to be fired for the ACCESSIBLE_STATE_PROPERTY
    1857          * property.
    1858          *
    1859          * @return an instance of AccessibleStateSet containing the
    1860          * current state set of the object
    1861          * @see AccessibleStateSet
    1862          * @see AccessibleState
    1863          * @see #addPropertyChangeListener
    1864          *
    1865          */
    1866         public AccessibleStateSet getAccessibleStateSet() {
    1867             // TIGER - 4489748
    1868             AccessibleStateSet ass = super.getAccessibleStateSet();
    1869             if (ass == null) {
    1870                 ass = new AccessibleStateSet();
    1871             }
    1872             if (JComboBox.this.isPopupVisible()) {
    1873                 ass.add(AccessibleState.EXPANDED);
    1874             } else {
    1875                 ass.add(AccessibleState.COLLAPSED);
    1876             }
    1877             return ass;
    1878         }
    1879
    1880         /**
    1881          * Get the AccessibleAction associated with this object.  In the
    1882          * implementation of the Java Accessibility API for this class,
    1883          * return this object, which is responsible for implementing the
    1884          * AccessibleAction interface on behalf of itself.
    1885          *
    1886          * @return this object
    1887          */
    1888         public AccessibleAction getAccessibleAction() {
    1889             return this;
    1890         }
    1891
    1892         /**
    1893          * Return a description of the specified action of the object.
    1894          *
    1895          * @param i zero-based index of the actions
    1896          */
    1897         public String getAccessibleActionDescription(int i) {
    1898             if (i == 0) {
    1899                 return UIManager.getString("ComboBox.togglePopupText");
    1900             }
    1901             else {
    1902                 return null;
    1903             }
    1904         }
    1905
    1906         /**
    1907          * Returns the number of Actions available in this object.  The
    1908          * default behavior of a combo box is to have one action.
    1909          *
    1910          * @return 1, the number of Actions in this object
    1911          */
    1912         public int getAccessibleActionCount() {
    1913             return 1;
    1914         }
    1915
    1916         /**
    1917          * Perform the specified Action on the object
    1918          *
    1919          * @param i zero-based index of actions
    1920          * @return true if the action was performed; else false.
    1921          */
    1922         public boolean doAccessibleAction(int i) {
    1923             if (i == 0) {
    1924                 setPopupVisible(!isPopupVisible());
    1925                 return true;
    1926             }
    1927             else {
    1928                 return false;
    1929             }
    1930         }
    1931
    1932
    1933         /**
    1934          * Get the AccessibleSelection associated with this object.  In the
    1935          * implementation of the Java Accessibility API for this class,
    1936          * return this object, which is responsible for implementing the
    1937          * AccessibleSelection interface on behalf of itself.
    1938          *
    1939          * @return this object
    1940          */
    1941         public AccessibleSelection getAccessibleSelection() {
    1942             return this;
    1943         }
    1944
    1945         /**
    1946          * Returns the number of Accessible children currently selected.
    1947          * If no children are selected, the return value will be 0.
    1948          *
    1949          * @return the number of items currently selected.
    1950          * @since 1.3
    1951          */
    1952         public int getAccessibleSelectionCount() {
    1953             E o = JComboBox.this.getSelectedItem();
    1954             if (o != null) {
    1955                 return 1;
    1956             } else {
    1957                 return 0;
    1958             }
    1959         }
    1960
    1961         /**
    1962          * Returns an Accessible representing the specified selected child
    1963          * in the popup.  If there isn't a selection, or there are
    1964          * fewer children selected than the integer passed in, the return
    1965          * value will be null.
    1966          * <p>Note that the index represents the i-th selected child, which
    1967          * is different from the i-th child.
    1968          *
    1969          * @param i the zero-based index of selected children
    1970          * @return the i-th selected child
    1971          * @see #getAccessibleSelectionCount
    1972          * @since 1.3
    1973          */
    1974         public Accessible getAccessibleSelection(int i) {
    1975             // Get the popup
    1976             Accessible a =
    1977                 JComboBox.this.getUI().getAccessibleChild(JComboBox.this, 0);
    1978             if (a != null &&
    1979                 a instanceof javax.swing.plaf.basic.ComboPopup) {
    1980
    1981                 // get the popup list
    1982                 JList<?> list = ((javax.swing.plaf.basic.ComboPopup)a).getList();
    1983
    1984                 // return the i-th selection in the popup list
    1985                 AccessibleContext ac = list.getAccessibleContext();
    1986                 if (ac != null) {
    1987                     AccessibleSelection as = ac.getAccessibleSelection();
    1988                     if (as != null) {
    1989                         return as.getAccessibleSelection(i);
    1990                     }
    1991                 }
    1992             }
    1993             return null;
    1994         }
    1995
    1996         /**
    1997          * Determines if the current child of this object is selected.
    1998          *
    1999          * @return true if the current child of this object is selected;
    2000          *              else false
    2001          * @param i the zero-based index of the child in this Accessible
    2002          * object.
    2003          * @see AccessibleContext#getAccessibleChild
    2004          * @since 1.3
    2005          */
    2006         public boolean isAccessibleChildSelected(int i) {
    2007             return JComboBox.this.getSelectedIndex() == i;
    2008         }
    2009
    2010         /**
    2011          * Adds the specified Accessible child of the object to the object's
    2012          * selection.  If the object supports multiple selections,
    2013          * the specified child is added to any existing selection, otherwise
    2014          * it replaces any existing selection in the object.  If the
    2015          * specified child is already selected, this method has no effect.
    2016          *
    2017          * @param i the zero-based index of the child
    2018          * @see AccessibleContext#getAccessibleChild
    2019          * @since 1.3
    2020          */
    2021         public void addAccessibleSelection(int i) {
    2022             // TIGER - 4856195
    2023             clearAccessibleSelection();
    2024             JComboBox.this.setSelectedIndex(i);
    2025         }
    2026
    2027         /**
    2028          * Removes the specified child of the object from the object's
    2029          * selection.  If the specified item isn't currently selected, this
    2030          * method has no effect.
    2031          *
    2032          * @param i the zero-based index of the child
    2033          * @see AccessibleContext#getAccessibleChild
    2034          * @since 1.3
    2035          */
    2036         public void removeAccessibleSelection(int i) {
    2037             if (JComboBox.this.getSelectedIndex() == i) {
    2038                 clearAccessibleSelection();
    2039             }
    2040         }
    2041
    2042         /**
    2043          * Clears the selection in the object, so that no children in the
    2044          * object are selected.
    2045          * @since 1.3
    2046          */
    2047         public void clearAccessibleSelection() {
    2048             JComboBox.this.setSelectedIndex(-1);
    2049         }
    2050
    2051         /**
    2052          * Causes every child of the object to be selected
    2053          * if the object supports multiple selections.
    2054          * @since 1.3
    2055          */
    2056         public void selectAllAccessibleSelection() {
    2057             // do nothing since multiple selection is not supported
    2058         }
    2059
    2060 //        public Accessible getAccessibleAt(Point p) {
    2061 //            Accessible a = getAccessibleChild(1);
    2062 //            if ( a != null ) {
    2063 //                return a; // the editor
    2064 //            }
    2065 //            else {
    2066 //                return getAccessibleChild(0); // the list
    2067 //            }
    2068 //        }
    2069         private EditorAccessibleContext editorAccessibleContext = null;
    2070
    2071         private class AccessibleEditor implements Accessible {
    2072             public AccessibleContext getAccessibleContext() {
    2073                 if (editorAccessibleContext == null) {
    2074                     Component c = JComboBox.this.getEditor().getEditorComponent();
    2075                     if (c instanceof Accessible) {
    2076                         editorAccessibleContext =
    2077                             new EditorAccessibleContext((Accessible)c);
    2078                     }
    2079                 }
    2080                 return editorAccessibleContext;
    2081             }
    2082         }
    2083
    2084         /*
    2085          * Wrapper class for the AccessibleContext implemented by the
    2086          * combo box editor.  Delegates all method calls except
    2087          * getAccessibleIndexInParent to the editor.  The
    2088          * getAccessibleIndexInParent method returns the selected
    2089          * index in the combo box.
    2090          */
    2091         private class EditorAccessibleContext extends AccessibleContext {
    2092
    2093             private AccessibleContext ac;
    2094
    2095             private EditorAccessibleContext() {
    2096             }
    2097
    2098             /*
    2099              * @param a the AccessibleContext implemented by the
    2100              * combo box editor
    2101              */
    2102             EditorAccessibleContext(Accessible a) {
    2103                 this.ac = a.getAccessibleContext();
    2104             }
    2105
    2106             /**
    2107              * Gets the accessibleName property of this object.  The accessibleName
    2108              * property of an object is a localized String that designates the purpose
    2109              * of the object.  For example, the accessibleName property of a label
    2110              * or button might be the text of the label or button itself.  In the
    2111              * case of an object that doesn't display its name, the accessibleName
    2112              * should still be set.  For example, in the case of a text field used
    2113              * to enter the name of a city, the accessibleName for the en_US locale
    2114              * could be 'city.'
    2115              *
    2116              * @return the localized name of the object; null if this
    2117              * object does not have a name
    2118              *
    2119              * @see #setAccessibleName
    2120              */
    2121             public String getAccessibleName() {
    2122                 return ac.getAccessibleName();
    2123             }
    2124
    2125             /**
    2126              * Sets the localized accessible name of this object.  Changing the
    2127              * name will cause a PropertyChangeEvent to be fired for the
    2128              * ACCESSIBLE_NAME_PROPERTY property.
    2129              *
    2130              * @param s the new localized name of the object.
    2131              *
    2132              * @see #getAccessibleName
    2133              * @see #addPropertyChangeListener
    2134              */
    2135             @BeanProperty(preferred = true, description
    2136                     = "Sets the accessible name for the component.")
    2137             public void setAccessibleName(String s) {
    2138                 ac.setAccessibleName(s);
    2139             }
    2140
    2141             /**
    2142              * Gets the accessibleDescription property of this object.  The
    2143              * accessibleDescription property of this object is a short localized
    2144              * phrase describing the purpose of the object.  For example, in the
    2145              * case of a 'Cancel' button, the accessibleDescription could be
    2146              * 'Ignore changes and close dialog box.'
    2147              *
    2148              * @return the localized description of the object; null if
    2149              * this object does not have a description
    2150              *
    2151              * @see #setAccessibleDescription
    2152              */
    2153             public String getAccessibleDescription() {
    2154                 return ac.getAccessibleDescription();
    2155             }
    2156
    2157             /**
    2158              * Sets the accessible description of this object.  Changing the
    2159              * name will cause a PropertyChangeEvent to be fired for the
    2160              * ACCESSIBLE_DESCRIPTION_PROPERTY property.
    2161              *
    2162              * @param s the new localized description of the object
    2163              *
    2164              * @see #setAccessibleName
    2165              * @see #addPropertyChangeListener
    2166              */
    2167             @BeanProperty(preferred = true, description
    2168                     = "Sets the accessible description for the component.")
    2169             public void setAccessibleDescription(String s) {
    2170                 ac.setAccessibleDescription(s);
    2171             }
    2172
    2173             /**
    2174              * Gets the role of this object.  The role of the object is the generic
    2175              * purpose or use of the class of this object.  For example, the role
    2176              * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in
    2177              * AccessibleRole are provided so component developers can pick from
    2178              * a set of predefined roles.  This enables assistive technologies to
    2179              * provide a consistent interface to various tweaked subclasses of
    2180              * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
    2181              * that act like a push button) as well as distinguish between subclasses
    2182              * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
    2183              * and AccessibleRole.RADIO_BUTTON for radio buttons).
    2184              * <p>Note that the AccessibleRole class is also extensible, so
    2185              * custom component developers can define their own AccessibleRole's
    2186              * if the set of predefined roles is inadequate.
    2187              *
    2188              * @return an instance of AccessibleRole describing the role of the object
    2189              * @see AccessibleRole
    2190              */
    2191             public AccessibleRole getAccessibleRole() {
    2192                 return ac.getAccessibleRole();
    2193             }
    2194
    2195             /**
    2196              * Gets the state set of this object.  The AccessibleStateSet of an object
    2197              * is composed of a set of unique AccessibleStates.  A change in the
    2198              * AccessibleStateSet of an object will cause a PropertyChangeEvent to
    2199              * be fired for the ACCESSIBLE_STATE_PROPERTY property.
    2200              *
    2201              * @return an instance of AccessibleStateSet containing the
    2202              * current state set of the object
    2203              * @see AccessibleStateSet
    2204              * @see AccessibleState
    2205              * @see #addPropertyChangeListener
    2206              */
    2207             public AccessibleStateSet getAccessibleStateSet() {
    2208                 return ac.getAccessibleStateSet();
    2209             }
    2210
    2211             /**
    2212              * Gets the Accessible parent of this object.
    2213              *
    2214              * @return the Accessible parent of this object; null if this
    2215              * object does not have an Accessible parent
    2216              */
    2217             public Accessible getAccessibleParent() {
    2218                 return ac.getAccessibleParent();
    2219             }
    2220
    2221             /**
    2222              * Sets the Accessible parent of this object.  This is meant to be used
    2223              * only in the situations where the actual component's parent should
    2224              * not be treated as the component's accessible parent and is a method
    2225              * that should only be called by the parent of the accessible child.
    2226              *
    2227              * @param a - Accessible to be set as the parent
    2228              */
    2229             public void setAccessibleParent(Accessible a) {
    2230                 ac.setAccessibleParent(a);
    2231             }
    2232
    2233             /**
    2234              * Gets the 0-based index of this object in its accessible parent.
    2235              *
    2236              * @return the 0-based index of this object in its parent; -1 if this
    2237              * object does not have an accessible parent.
    2238              *
    2239              * @see #getAccessibleParent
    2240              * @see #getAccessibleChildrenCount
    2241              * @see #getAccessibleChild
    2242              */
    2243             public int getAccessibleIndexInParent() {
    2244                 return JComboBox.this.getSelectedIndex();
    2245             }
    2246
    2247             /**
    2248              * Returns the number of accessible children of the object.
    2249              *
    2250              * @return the number of accessible children of the object.
    2251              */
    2252             public int getAccessibleChildrenCount() {
    2253                 return ac.getAccessibleChildrenCount();
    2254             }
    2255
    2256             /**
    2257              * Returns the specified Accessible child of the object.  The Accessible
    2258              * children of an Accessible object are zero-based, so the first child
    2259              * of an Accessible child is at index 0, the second child is at index 1,
    2260              * and so on.
    2261              *
    2262              * @param i zero-based index of child
    2263              * @return the Accessible child of the object
    2264              * @see #getAccessibleChildrenCount
    2265              */
    2266             public Accessible getAccessibleChild(int i) {
    2267                 return ac.getAccessibleChild(i);
    2268             }
    2269
    2270             /**
    2271              * Gets the locale of the component. If the component does not have a
    2272              * locale, then the locale of its parent is returned.
    2273              *
    2274              * @return this component's locale.  If this component does not have
    2275              * a locale, the locale of its parent is returned.
    2276              *
    2277              * @exception IllegalComponentStateException
    2278              * If the Component does not have its own locale and has not yet been
    2279              * added to a containment hierarchy such that the locale can be
    2280              * determined from the containing parent.
    2281              */
    2282             public Locale getLocale() throws IllegalComponentStateException {
    2283                 return ac.getLocale();
    2284             }
    2285
    2286             /**
    2287              * Adds a PropertyChangeListener to the listener list.
    2288              * The listener is registered for all Accessible properties and will
    2289              * be called when those properties change.
    2290              *
    2291              * @see #ACCESSIBLE_NAME_PROPERTY
    2292              * @see #ACCESSIBLE_DESCRIPTION_PROPERTY
    2293              * @see #ACCESSIBLE_STATE_PROPERTY
    2294              * @see #ACCESSIBLE_VALUE_PROPERTY
    2295              * @see #ACCESSIBLE_SELECTION_PROPERTY
    2296              * @see #ACCESSIBLE_TEXT_PROPERTY
    2297              * @see #ACCESSIBLE_VISIBLE_DATA_PROPERTY
    2298              *
    2299              * @param listener  The PropertyChangeListener to be added
    2300              */
    2301             public void addPropertyChangeListener(PropertyChangeListener listener) {
    2302                 ac.addPropertyChangeListener(listener);
    2303             }
    2304
    2305             /**
    2306              * Removes a PropertyChangeListener from the listener list.
    2307              * This removes a PropertyChangeListener that was registered
    2308              * for all properties.
    2309              *
    2310              * @param listener  The PropertyChangeListener to be removed
    2311              */
    2312             public void removePropertyChangeListener(PropertyChangeListener listener) {
    2313                 ac.removePropertyChangeListener(listener);
    2314             }
    2315
    2316             /**
    2317              * Gets the AccessibleAction associated with this object that supports
    2318              * one or more actions.
    2319              *
    2320              * @return AccessibleAction if supported by object; else return null
    2321              * @see AccessibleAction
    2322              */
    2323             public AccessibleAction getAccessibleAction() {
    2324                 return ac.getAccessibleAction();
    2325             }
    2326
    2327             /**
    2328              * Gets the AccessibleComponent associated with this object that has a
    2329              * graphical representation.
    2330              *
    2331              * @return AccessibleComponent if supported by object; else return null
    2332              * @see AccessibleComponent
    2333              */
    2334             public AccessibleComponent getAccessibleComponent() {
    2335                 return ac.getAccessibleComponent();
    2336             }
    2337
    2338             /**
    2339              * Gets the AccessibleSelection associated with this object which allows its
    2340              * Accessible children to be selected.
    2341              *
    2342              * @return AccessibleSelection if supported by object; else return null
    2343              * @see AccessibleSelection
    2344              */
    2345             public AccessibleSelection getAccessibleSelection() {
    2346                 return ac.getAccessibleSelection();
    2347             }
    2348
    2349             /**
    2350              * Gets the AccessibleText associated with this object presenting
    2351              * text on the display.
    2352              *
    2353              * @return AccessibleText if supported by object; else return null
    2354              * @see AccessibleText
    2355              */
    2356             public AccessibleText getAccessibleText() {
    2357                 return ac.getAccessibleText();
    2358             }
    2359
    2360             /**
    2361              * Gets the AccessibleEditableText associated with this object
    2362              * presenting editable text on the display.
    2363              *
    2364              * @return AccessibleEditableText if supported by object; else return null
    2365              * @see AccessibleEditableText
    2366              */
    2367             public AccessibleEditableText getAccessibleEditableText() {
    2368                 return ac.getAccessibleEditableText();
    2369             }
    2370
    2371             /**
    2372              * Gets the AccessibleValue associated with this object that supports a
    2373              * Numerical value.
    2374              *
    2375              * @return AccessibleValue if supported by object; else return null
    2376              * @see AccessibleValue
    2377              */
    2378             public AccessibleValue getAccessibleValue() {
    2379                 return ac.getAccessibleValue();
    2380             }
    2381
    2382             /**
    2383              * Gets the AccessibleIcons associated with an object that has
    2384              * one or more associated icons
    2385              *
    2386              * @return an array of AccessibleIcon if supported by object;
    2387              * otherwise return null
    2388              * @see AccessibleIcon
    2389              */
    2390             public AccessibleIcon [] getAccessibleIcon() {
    2391                 return ac.getAccessibleIcon();
    2392             }
    2393
    2394             /**
    2395              * Gets the AccessibleRelationSet associated with an object
    2396              *
    2397              * @return an AccessibleRelationSet if supported by object;
    2398              * otherwise return null
    2399              * @see AccessibleRelationSet
    2400              */
    2401             public AccessibleRelationSet getAccessibleRelationSet() {
    2402                 return ac.getAccessibleRelationSet();
    2403             }
    2404
    2405             /**
    2406              * Gets the AccessibleTable associated with an object
    2407              *
    2408              * @return an AccessibleTable if supported by object;
    2409              * otherwise return null
    2410              * @see AccessibleTable
    2411              */
    2412             public AccessibleTable getAccessibleTable() {
    2413                 return ac.getAccessibleTable();
    2414             }
    2415
    2416             /**
    2417              * Support for reporting bound property changes.  If oldValue and
    2418              * newValue are not equal and the PropertyChangeEvent listener list
    2419              * is not empty, then fire a PropertyChange event to each listener.
    2420              * In general, this is for use by the Accessible objects themselves
    2421              * and should not be called by an application program.
    2422              * @param propertyName  The programmatic name of the property that
    2423              * was changed.
    2424              * @param oldValue  The old value of the property.
    2425              * @param newValue  The new value of the property.
    2426              * @see java.beans.PropertyChangeSupport
    2427              * @see #addPropertyChangeListener
    2428              * @see #removePropertyChangeListener
    2429              * @see #ACCESSIBLE_NAME_PROPERTY
    2430              * @see #ACCESSIBLE_DESCRIPTION_PROPERTY
    2431              * @see #ACCESSIBLE_STATE_PROPERTY
    2432              * @see #ACCESSIBLE_VALUE_PROPERTY
    2433              * @see #ACCESSIBLE_SELECTION_PROPERTY
    2434              * @see #ACCESSIBLE_TEXT_PROPERTY
    2435              * @see #ACCESSIBLE_VISIBLE_DATA_PROPERTY
    2436              */
    2437             public void firePropertyChange(String propertyName,
    2438                                            Object oldValue,
    2439                                            Object newValue) {
    2440                 ac.firePropertyChange(propertyName, oldValue, newValue);
    2441             }
    2442         }
    2443
    2444     } // innerclass AccessibleJComboBox
    2445 }
    --- EOF ---