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