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