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