    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 Object selectedItemReminder = null;
     162
     163     private E prototypeDisplayValue;
     164
     165     // Flag to ensure that infinite loops do not occur with ActionEvents.
     166     private boolean firingActionEvent = false;
     167
     168     // Flag to ensure the we don't get multiple ActionEvents on item selection.
     169     private boolean selectingItem = false;
     170
     171     // Flag to indicate UI update is in progress
     172     private transient boolean updateInProgress;
     173
     174     /**
     175      * Creates a <code>JComboBox</code> that takes its items from an
     176      * existing <code>ComboBoxModel</code>.  Since the
     177      * <code>ComboBoxModel</code> is provided, a combo box created using
     178      * this constructor does not create a default combo box model and
     179      * may impact how the insert, remove and add methods behave.
     180      *
     181      * @param aModel the <code>ComboBoxModel</code> that provides the
     182      *          displayed list of items
     183      * @see DefaultComboBoxModel
     184      */
     185     public JComboBox(ComboBoxModel<E> aModel) {
     186         super();
     187         setModel(aModel);
     188         init();
     189     }
     190
     191     /**
     192      * Creates a <code>JComboBox</code> that contains the elements
     193      * in the specified array.  By default the first item in the array
     194      * (and therefore the data model) becomes selected.
     195      *
     196      * @param items  an array of objects to insert into the combo box
     197      * @see DefaultComboBoxModel
     198      */
     199     public JComboBox(E[] items) {
     200         super();
     201         setModel(new DefaultComboBoxModel<E>(items));
     202         init();
     203     }
     204
     205     /**
     206      * Creates a <code>JComboBox</code> that contains the elements
     207      * in the specified Vector.  By default the first item in the vector
     208      * (and therefore the data model) becomes selected.
     209      *
     210      * @param items  an array of vectors to insert into the combo box
     211      * @see DefaultComboBoxModel
     212      */
     213     public JComboBox(Vector<E> items) {
     214         super();
     215         setModel(new DefaultComboBoxModel<E>(items));
     216         init();
     217     }
     218
     219     /**
     220      * Creates a <code>JComboBox</code> with a default data model.
     221      * The default data model is an empty list of objects.
     222      * Use <code>addItem</code> to add items.  By default the first item
     223      * in the data model becomes selected.
     224      *
     225      * @see DefaultComboBoxModel
     226      */
     227     public JComboBox() {
     228         super();
     229         setModel(new DefaultComboBoxModel<E>());
     230         init();
     231     }
     232
     233     private void init() {
     234         installAncestorListener();
     235         setUIProperty("opaque",true);
     236         updateUI();
     237     }
     238
     239     /**
     240      * Registers ancestor listener so that it will receive
     241      * {@code AncestorEvents} when it or any of its ancestors
     242      * move or are made visible or invisible.
     243      * Events are also sent when the component or its ancestors are added
     244      * or removed from the containment hierarchy.
     245      */
     246     protected void installAncestorListener() {
     247         addAncestorListener(new AncestorListener(){
     248                                 public void ancestorAdded(AncestorEvent event){ hidePopup();}
     249                                 public void ancestorRemoved(AncestorEvent event){ hidePopup();}
     250                                 public void ancestorMoved(AncestorEvent event){
     251                                     if (event.getSource() != JComboBox.this)
     252                                         hidePopup();
     253                                 }});
     254     }
     255
     256     /**
     257      * Sets the L&amp;F object that renders this component.
     258      *
     259      * @param ui  the <code>ComboBoxUI</code> L&amp;F object
     260      * @see UIDefaults#getUI
     261      */
     262     @BeanProperty(hidden = true, visualUpdate = true, description
     263             = "The UI object that implements the Component's LookAndFeel.")
     264     public void setUI(ComboBoxUI ui) {
     265         super.setUI(ui);
     266     }
     267
     268     /**
     269      * Resets the UI property to a value from the current look and feel.
     270      *
     271      * @see JComponent#updateUI
     272      */
     273     public void updateUI() {
     274         if (!updateInProgress) {
     275             updateInProgress = true;
     276             try {
     277                 setUI((ComboBoxUI)UIManager.getUI(this));
     278
     279                 ListCellRenderer<? super E> renderer = getRenderer();
     280                 if (renderer instanceof Component) {
     281                     SwingUtilities.updateComponentTreeUI((Component)renderer);
     282                 }
     283             } finally {
     284                 updateInProgress = false;
     285             }
     286         }
     287     }
     288
     289
     290     /**
     291      * Returns the name of the L&amp;F class that renders this component.
     292      *
     293      * @return the string "ComboBoxUI"
     294      * @see JComponent#getUIClassID
     295      * @see UIDefaults#getUI
     296      */
     297     @BeanProperty(bound = false)
     298     public String getUIClassID() {
     299         return uiClassID;
     300     }
     301
     302
     303     /**
     304      * Returns the L&amp;F object that renders this component.
     305      *
     306      * @return the ComboBoxUI object that renders this component
     307      */
     308     public ComboBoxUI getUI() {
     309         return(ComboBoxUI)ui;
     310     }
     311
     312     /**
     313      * Sets the data model that the <code>JComboBox</code> uses to obtain
     314      * the list of items.
     315      *
     316      * @param aModel the <code>ComboBoxModel</code> that provides the
     317      *  displayed list of items
     318      */
     319     @BeanProperty(description
     320             = "Model that the combo box uses to get data to display.")
     321     public void setModel(ComboBoxModel<E> aModel) {
     322         ComboBoxModel<E> oldModel = dataModel;
     323         if (oldModel != null) {
     324             oldModel.removeListDataListener(this);
     325         }
     326         dataModel = aModel;
     327         dataModel.addListDataListener(this);
     328
     329         // set the current selected item.
     330         selectedItemReminder = dataModel.getSelectedItem();
     331
     332         firePropertyChange( "model", oldModel, dataModel);
     333     }
     334
     335     /**
     336      * Returns the data model currently used by the <code>JComboBox</code>.
     337      *
     338      * @return the <code>ComboBoxModel</code> that provides the displayed
     339      *                  list of items
     340      */
     341     public ComboBoxModel<E> getModel() {
     342         return dataModel;
     343     }
     344
     345     /*
     346      * Properties
     347      */
     348
     349     /**
     350      * Sets the <code>lightWeightPopupEnabled</code> property, which
     351      * provides a hint as to whether or not a lightweight
     352      * <code>Component</code> should be used to contain the
     353      * <code>JComboBox</code>, versus a heavyweight
     354      * <code>Component</code> such as a <code>Panel</code>
     355      * or a <code>Window</code>.  The decision of lightweight
     356      * versus heavyweight is ultimately up to the
     357      * <code>JComboBox</code>.  Lightweight windows are more
     358      * efficient than heavyweight windows, but lightweight
     359      * and heavyweight components do not mix well in a GUI.
     360      * If your application mixes lightweight and heavyweight
     361      * components, you should disable lightweight popups.
     362      * The default value for the <code>lightWeightPopupEnabled</code>
     363      * property is <code>true</code>, unless otherwise specified
     364      * by the look and feel.  Some look and feels always use
     365      * heavyweight popups, no matter what the value of this property.
     366      * <p>
     367      * See the article <a href="http://www.oracle.com/technetwork/articles/java/mixing-components-433992.html">Mixing Heavy and Light Components</a>
     368      * This method fires a property changed event.
     369      *
     370      * @param aFlag if <code>true</code>, lightweight popups are desired
     371      */
     372     @BeanProperty(expert = true, description
     373             = "Set to <code>false</code> to require heavyweight popups.")
     374     public void setLightWeightPopupEnabled(boolean aFlag) {
     375         boolean oldFlag = lightWeightPopupEnabled;
     376         lightWeightPopupEnabled = aFlag;
     377         firePropertyChange("lightWeightPopupEnabled", oldFlag, lightWeightPopupEnabled);
     378     }
     379
     380     /**
     381      * Gets the value of the <code>lightWeightPopupEnabled</code>
     382      * property.
     383      *
     384      * @return the value of the <code>lightWeightPopupEnabled</code>
     385      *    property
     386      * @see #setLightWeightPopupEnabled
     387      */
     388     public boolean isLightWeightPopupEnabled() {
     389         return lightWeightPopupEnabled;
     390     }
     391
     392     /**
     393      * Determines whether the <code>JComboBox</code> field is editable.
     394      * An editable <code>JComboBox</code> allows the user to type into the
     395      * field or selected an item from the list to initialize the field,
     396      * after which it can be edited. (The editing affects only the field,
     397      * the list item remains intact.) A non editable <code>JComboBox</code>
     398      * displays the selected item in the field,
     399      * but the selection cannot be modified.
     400      *
     401      * @param aFlag a boolean value, where true indicates that the
     402      *                  field is editable
     403      */
     404     @BeanProperty(preferred = true, description
     405             = "If true, the user can type a new value in the combo box.")
     406     public void setEditable(boolean aFlag) {
     407         boolean oldFlag = isEditable;
     408         isEditable = aFlag;
     409         firePropertyChange( "editable", oldFlag, isEditable );
     410     }
     411
     412     /**
     413      * Returns true if the <code>JComboBox</code> is editable.
     414      * By default, a combo box is not editable.
     415      *
     416      * @return true if the <code>JComboBox</code> is editable, else false
     417      */
     418     public boolean isEditable() {
     419         return isEditable;
     420     }
     421
     422     /**
     423      * Sets the maximum number of rows the <code>JComboBox</code> displays.
     424      * If the number of objects in the model is greater than count,
     425      * the combo box uses a scrollbar.
     426      *
     427      * @param count an integer specifying the maximum number of items to
     428      *              display in the list before using a scrollbar
     429      */
     430     @BeanProperty(preferred = true, description
     431             = "The maximum number of rows the popup should have")
     432     public void setMaximumRowCount(int count) {
     433         int oldCount = maximumRowCount;
     434         maximumRowCount = count;
     435         firePropertyChange( "maximumRowCount", oldCount, maximumRowCount );
     436     }
     437
     438     /**
     439      * Returns the maximum number of items the combo box can display
     440      * without a scrollbar
     441      *
     442      * @return an integer specifying the maximum number of items that are
     443      *         displayed in the list before using a scrollbar
     444      */
     445     public int getMaximumRowCount() {
     446         return maximumRowCount;
     447     }
     448
     449     /**
     450      * Sets the renderer that paints the list items and the item selected from the list in
     451      * the JComboBox field. The renderer is used if the JComboBox is not
     452      * editable. If it is editable, the editor is used to render and edit
     453      * the selected item.
     454      * <p>
     455      * The default renderer displays a string or an icon.
     456      * Other renderers can handle graphic images and composite items.
     457      * <p>
     458      * To display the selected item,
     459      * <code>aRenderer.getListCellRendererComponent</code>
     460      * is called, passing the list object and an index of -1.
     461      *
     462      * @param aRenderer  the <code>ListCellRenderer</code> that
     463      *                  displays the selected item
     464      * @see #setEditor
     465      */
     466     @BeanProperty(expert = true, description
     467             = "The renderer that paints the item selected in the list.")
     468     public void setRenderer(ListCellRenderer<? super E> aRenderer) {
     469         ListCellRenderer<? super E> oldRenderer = renderer;
     470         renderer = aRenderer;
     471         firePropertyChange( "renderer", oldRenderer, renderer );
     472         invalidate();
     473     }
     474
     475     /**
     476      * Returns the renderer used to display the selected item in the
     477      * <code>JComboBox</code> field.
     478      *
     479      * @return  the <code>ListCellRenderer</code> that displays
     480      *                  the selected item.
     481      */
     482     public ListCellRenderer<? super E> getRenderer() {
     483         return renderer;
     484     }
     485
     486     /**
     487      * Sets the editor used to paint and edit the selected item in the
     488      * <code>JComboBox</code> field.  The editor is used only if the
     489      * receiving <code>JComboBox</code> is editable. If not editable,
     490      * the combo box uses the renderer to paint the selected item.
     491      *
     492      * @param anEditor  the <code>ComboBoxEditor</code> that
     493      *                  displays the selected item
     494      * @see #setRenderer
     495      */
     496     @BeanProperty(expert = true, description
     497             = "The editor that combo box uses to edit the current value")
     498     public void setEditor(ComboBoxEditor anEditor) {
     499         ComboBoxEditor oldEditor = editor;
     500
     501         if ( editor != null ) {
     502             editor.removeActionListener(this);
     503         }
     504         editor = anEditor;
     505         if ( editor != null ) {
     506             editor.addActionListener(this);
     507         }
     508         firePropertyChange( "editor", oldEditor, editor );
     509     }
     510
     511     /**
     512      * Returns the editor used to paint and edit the selected item in the
     513      * <code>JComboBox</code> field.
     514      *
     515      * @return the <code>ComboBoxEditor</code> that displays the selected item
     516      */
     517     public ComboBoxEditor getEditor() {
     518         return editor;
     519     }
     520
     521     //
     522     // Selection
     523     //
     524
     525     /**
     526      * Sets the selected item in the combo box display area to the object in
     527      * the argument.
     528      * If <code>anObject</code> is in the list, the display area shows
     529      * <code>anObject</code> selected.
     530      * <p>
     531      * If <code>anObject</code> is <i>not</i> in the list and the combo box is
     532      * uneditable, it will not change the current selection. For editable
     533      * combo boxes, the selection will change to <code>anObject</code>.
     534      * <p>
     535      * If this constitutes a change in the selected item,
     536      * <code>ItemListener</code>s added to the combo box will be notified with
     537      * one or two <code>ItemEvent</code>s.
     538      * If there is a current selected item, an <code>ItemEvent</code> will be
     539      * fired and the state change will be <code>ItemEvent.DESELECTED</code>.
     540      * If <code>anObject</code> is in the list and is not currently selected
     541      * then an <code>ItemEvent</code> will be fired and the state change will
     542      * be <code>ItemEvent.SELECTED</code>.
     543      * <p>
     544      * <code>ActionListener</code>s added to the combo box will be notified
     545      * with an <code>ActionEvent</code> when this method is called.
     546      *

     547      * @param anObject  the list object to select; use <code>null</code> to
     548                         clear the selection
     549      */
     550     @BeanProperty(bound = false, preferred = true, description
     551             = "Sets the selected item in the JComboBox.")
     552     public void setSelectedItem(Object anObject) {
     553         Object oldSelection = selectedItemReminder;
     554         Object objectToSelect = anObject;
     555         if (oldSelection == null || !oldSelection.equals(anObject)) {
     556
     557             if (anObject != null && !isEditable()) {
     558                 // For non editable combo boxes, an invalid selection
     559                 // will be rejected.
     560                 boolean found = false;
     561                 for (int i = 0; i < dataModel.getSize(); i++) {
     562                     E element = dataModel.getElementAt(i);
     563                     if (anObject.equals(element)) {
     564                         found = true;
     565                         objectToSelect = element;
     566                         break;
     567                     }
     568                 }
     569                 if (!found) {
     570                     return;
     571                 }
     572
     573                 getEditor().setItem(anObject);
     574             }
     575
     576             // Must toggle the state of this flag since this method
     577             // call may result in ListDataEvents being fired.
     578             selectingItem = true;
     579             dataModel.setSelectedItem(objectToSelect);
     580             selectingItem = false;
     581
     582             if (selectedItemReminder != dataModel.getSelectedItem()) {
     583                 // in case a users implementation of ComboBoxModel
     584                 // doesn't fire a ListDataEvent when the selection
     585                 // changes.
     586                 selectedItemChanged();
     587             }
     588         }
     589         fireActionEvent();
     590     }
     591
     592     /**
     593      * Returns the current selected item.
     594      * <p>
     595      * If the combo box is editable, then this value may not have been added
     596      * to the combo box with <code>addItem</code>, <code>insertItemAt</code>
     597      * or the data constructors.
     598      *

     599      * @return the current selected Object
     600      * @see #setSelectedItem
     601      */
     602     public Object getSelectedItem() {
     603         return dataModel.getSelectedItem();
     604     }
     605
     606     /**
     607      * Selects the item at index <code>anIndex</code>.
     608      *
     609      * @param anIndex an integer specifying the list item to select,
     610      *                  where 0 specifies the first item in the list and -1 indicates no selection
     611      * @exception IllegalArgumentException if <code>anIndex</code> &lt; -1 or
     612      *                  <code>anIndex</code> is greater than or equal to size
     613      */
     614     @BeanProperty(bound = false, preferred = true, description
     615             = "The item at index is selected.")
     616     public void setSelectedIndex(int anIndex) {
     617         int size = dataModel.getSize();
     618
     619         if ( anIndex == -1 ) {
     620             setSelectedItem( null );
     621         } else if ( anIndex < -1 || anIndex >= size ) {
     622             throw new IllegalArgumentException("setSelectedIndex: " + anIndex + " out of bounds");
     623         } else {
     624             setSelectedItem(dataModel.getElementAt(anIndex));
     625         }
     626     }
     627
     628     /**
     629      * Returns the first item in the list that matches the given item.
     630      * The result is not always defined if the <code>JComboBox</code>
     631      * allows selected items that are not in the list.
     632      * Returns -1 if there is no selected item or if the user specified
     633      * an item which is not in the list.
     634
     635      * @return an integer specifying the currently selected list item,
     636      *                  where 0 specifies
     637      *                  the first item in the list;
     638      *                  or -1 if no item is selected or if
     639      *                  the currently selected item is not in the list
     640      */
     641     @Transient
     642     public int getSelectedIndex() {
     643         Object sObject = dataModel.getSelectedItem();
     644         int i,c;
     645         E obj;
     646
     647         for ( i=0,c=dataModel.getSize();i<c;i++ ) {
     648             obj = dataModel.getElementAt(i);
     649             if ( obj != null && obj.equals(sObject) )
     650                 return i;
     651         }
     652         return -1;
     653     }
     654
     655     /**
     656      * Returns the "prototypical display" value - an Object used
     657      * for the calculation of the display height and width.
     658      *
     659      * @return the value of the <code>prototypeDisplayValue</code> property
     660      * @see #setPrototypeDisplayValue
     661      * @since 1.4
     662      */
     663     public E getPrototypeDisplayValue() {
     664         return prototypeDisplayValue;
     665     }
     666
     667     /**
     668      * Sets the prototype display value used to calculate the size of the display
     669      * for the UI portion.
     670      * <p>
     671      * If a prototype display value is specified, the preferred size of
     672      * the combo box is calculated by configuring the renderer with the
     673      * prototype display value and obtaining its preferred size. Specifying
     674      * the preferred display value is often useful when the combo box will be
     675      * displaying large amounts of data. If no prototype display value has
     676      * been specified, the renderer must be configured for each value from
     677      * the model and its preferred size obtained, which can be
     678      * relatively expensive.
     679      *
     680      * @param prototypeDisplayValue the prototype display value
     681      * @see #getPrototypeDisplayValue
     682      * @since 1.4
     683      */
     684     @BeanProperty(visualUpdate = true, description
     685             = "The display prototype value, used to compute display width and height.")
     686     public void setPrototypeDisplayValue(E prototypeDisplayValue) {
     687         Object oldValue = this.prototypeDisplayValue;
     688         this.prototypeDisplayValue = prototypeDisplayValue;
     689         firePropertyChange("prototypeDisplayValue", oldValue, prototypeDisplayValue);
     690     }
     691
     692     /**
     693      * Adds an item to the item list.
     694      * This method works only if the <code>JComboBox</code> uses a
     695      * mutable data model.
     696      * <p>
     697      * <strong>Warning:</strong>
     698      * Focus and keyboard navigation problems may arise if you add duplicate
     699      * String objects. A workaround is to add new objects instead of String
     700      * objects and make sure that the toString() method is defined.
     701      * For example:
     702      * <pre>
     703      *   comboBox.addItem(makeObj("Item 1"));
     704      *   comboBox.addItem(makeObj("Item 1"));
     705      *   ...
     706      *   private Object makeObj(final String item)  {
     707      *     return new Object() { public String toString() { return item; } };
     708      *   }
     709      * </pre>
     710      *
     711      * @param item the item to add to the list
     712      * @see MutableComboBoxModel
     713      */
     714     public void addItem(E item) {
     715         checkMutableComboBoxModel();
     716         ((MutableComboBoxModel<E>)dataModel).addElement(item);
     717     }
     718
     719     /**
     720      * Inserts an item into the item list at a given index.
     721      * This method works only if the <code>JComboBox</code> uses a
     722      * mutable data model.
     723      *
     724      * @param item the item to add to the list
     725      * @param index    an integer specifying the position at which
     726      *                  to add the item
     727      * @see MutableComboBoxModel
     728      */
     729     public void insertItemAt(E item, int index) {
     730         checkMutableComboBoxModel();
     731         ((MutableComboBoxModel<E>)dataModel).insertElementAt(item,index);
     732     }
     733
     734     /**
     735      * Removes an item from the item list.
     736      * This method works only if the <code>JComboBox</code> uses a
     737      * mutable data model.
     738      *

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

    1299      * @return an array of <code>Objects</code> containing one
    1300      *          element -- the selected item
    1301      */
    1302     @BeanProperty(bound = false)
    1303     public Object[] getSelectedObjects() {
    1304         Object selectedObject = getSelectedItem();
    1305         if ( selectedObject == null )
    1306             return new Object[0];

    1307         else {
    1308             Object result[] = new Object[1];
    1309             result[0] = selectedObject;
    1310             return result;
    1311         }

    1312     }
    1313
    1314     /**
    1315      * This method is public as an implementation side effect.
    1316      * do not call or override.
    1317      */

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