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