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