src/java.desktop/share/classes/javax/swing/JComboBox.java

Print this page


   1 /*
   2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package javax.swing;
  26 


  27 import java.beans.PropertyChangeEvent;
  28 import java.beans.PropertyChangeListener;
  29 import java.beans.Transient;
  30 import java.util.*;
  31 
  32 import java.awt.*;
  33 import java.awt.event.*;
  34 
  35 import java.io.Serializable;
  36 import java.io.ObjectOutputStream;
  37 import java.io.IOException;
  38 
  39 import javax.swing.event.*;
  40 import javax.swing.plaf.*;
  41 
  42 import javax.accessibility.*;
  43 
  44 /**
  45  * A component that combines a button or editable field and a drop-down list.
  46  * The user can select a value from the drop-down list, which appears at the


  54  * <p>
  55  * <strong>Warning:</strong>
  56  * Serialized objects of this class will not be compatible with
  57  * future Swing releases. The current serialization support is
  58  * appropriate for short term storage or RMI between applications running
  59  * the same version of Swing.  As of 1.4, support for long term storage
  60  * of all JavaBeans&trade;
  61  * has been added to the <code>java.beans</code> package.
  62  * Please see {@link java.beans.XMLEncoder}.
  63  *
  64  * <p>
  65  * See <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html">How to Use Combo Boxes</a>
  66  * in <a href="http://docs.oracle.com/javase/tutorial/"><em>The Java Tutorial</em></a>
  67  * for further information.
  68  *
  69  * @see ComboBoxModel
  70  * @see DefaultComboBoxModel
  71  *
  72  * @param <E> the type of the elements of this combo box
  73  *
  74  * @beaninfo
  75  *   attribute: isContainer false
  76  * description: A combination of a text field and a drop-down list.
  77  *
  78  * @author Arnaud Weber
  79  * @author Mark Davidson
  80  * @since 1.2
  81  */


  82 @SuppressWarnings("serial") // Same-version serialization only
  83 public class JComboBox<E> extends JComponent
  84 implements ItemSelectable,ListDataListener,ActionListener, Accessible {
  85     /**
  86      * @see #getUIClassID
  87      * @see #readObject
  88      */
  89     private static final String uiClassID = "ComboBoxUI";
  90 
  91     /**
  92      * This protected field is implementation specific. Do not access directly
  93      * or override. Use the accessor methods instead.
  94      *
  95      * @see #getModel
  96      * @see #setModel
  97      */
  98     protected ComboBoxModel<E>    dataModel;
  99     /**
 100      * This protected field is implementation specific. Do not access directly
 101      * or override. Use the accessor methods instead.


 238      * {@code AncestorEvents} when it or any of its ancestors
 239      * move or are made visible or invisible.
 240      * Events are also sent when the component or its ancestors are added
 241      * or removed from the containment hierarchy.
 242      */
 243     protected void installAncestorListener() {
 244         addAncestorListener(new AncestorListener(){
 245                                 public void ancestorAdded(AncestorEvent event){ hidePopup();}
 246                                 public void ancestorRemoved(AncestorEvent event){ hidePopup();}
 247                                 public void ancestorMoved(AncestorEvent event){
 248                                     if (event.getSource() != JComboBox.this)
 249                                         hidePopup();
 250                                 }});
 251     }
 252 
 253     /**
 254      * Sets the L&amp;F object that renders this component.
 255      *
 256      * @param ui  the <code>ComboBoxUI</code> L&amp;F object
 257      * @see UIDefaults#getUI
 258      *
 259      * @beaninfo
 260      *        bound: true
 261      *       hidden: true
 262      *    attribute: visualUpdate true
 263      *  description: The UI object that implements the Component's LookAndFeel.
 264      */


 265     public void setUI(ComboBoxUI ui) {
 266         super.setUI(ui);
 267     }
 268 
 269     /**
 270      * Resets the UI property to a value from the current look and feel.
 271      *
 272      * @see JComponent#updateUI
 273      */
 274     public void updateUI() {
 275         setUI((ComboBoxUI)UIManager.getUI(this));
 276 
 277         ListCellRenderer<? super E> renderer = getRenderer();
 278         if (renderer instanceof Component) {
 279             SwingUtilities.updateComponentTreeUI((Component)renderer);
 280         }
 281     }
 282 
 283 
 284     /**
 285      * Returns the name of the L&amp;F class that renders this component.
 286      *
 287      * @return the string "ComboBoxUI"
 288      * @see JComponent#getUIClassID
 289      * @see UIDefaults#getUI
 290      */

 291     public String getUIClassID() {
 292         return uiClassID;
 293     }
 294 
 295 
 296     /**
 297      * Returns the L&amp;F object that renders this component.
 298      *
 299      * @return the ComboBoxUI object that renders this component
 300      */
 301     public ComboBoxUI getUI() {
 302         return(ComboBoxUI)ui;
 303     }
 304 
 305     /**
 306      * Sets the data model that the <code>JComboBox</code> uses to obtain
 307      * the list of items.
 308      *
 309      * @param aModel the <code>ComboBoxModel</code> that provides the
 310      *  displayed list of items
 311      *
 312      * @beaninfo
 313      *        bound: true
 314      *  description: Model that the combo box uses to get data to display.
 315      */


 316     public void setModel(ComboBoxModel<E> aModel) {
 317         ComboBoxModel<E> oldModel = dataModel;
 318         if (oldModel != null) {
 319             oldModel.removeListDataListener(this);
 320         }
 321         dataModel = aModel;
 322         dataModel.addListDataListener(this);
 323 
 324         // set the current selected item.
 325         selectedItemReminder = dataModel.getSelectedItem();
 326 
 327         firePropertyChange( "model", oldModel, dataModel);
 328     }
 329 
 330     /**
 331      * Returns the data model currently used by the <code>JComboBox</code>.
 332      *
 333      * @return the <code>ComboBoxModel</code> that provides the displayed
 334      *                  list of items
 335      */


 346      * provides a hint as to whether or not a lightweight
 347      * <code>Component</code> should be used to contain the
 348      * <code>JComboBox</code>, versus a heavyweight
 349      * <code>Component</code> such as a <code>Panel</code>
 350      * or a <code>Window</code>.  The decision of lightweight
 351      * versus heavyweight is ultimately up to the
 352      * <code>JComboBox</code>.  Lightweight windows are more
 353      * efficient than heavyweight windows, but lightweight
 354      * and heavyweight components do not mix well in a GUI.
 355      * If your application mixes lightweight and heavyweight
 356      * components, you should disable lightweight popups.
 357      * The default value for the <code>lightWeightPopupEnabled</code>
 358      * property is <code>true</code>, unless otherwise specified
 359      * by the look and feel.  Some look and feels always use
 360      * heavyweight popups, no matter what the value of this property.
 361      * <p>
 362      * See the article <a href="http://www.oracle.com/technetwork/articles/java/mixing-components-433992.html">Mixing Heavy and Light Components</a>
 363      * This method fires a property changed event.
 364      *
 365      * @param aFlag if <code>true</code>, lightweight popups are desired
 366      *
 367      * @beaninfo
 368      *        bound: true
 369      *       expert: true
 370      *  description: Set to <code>false</code> to require heavyweight popups.
 371      */


 372     public void setLightWeightPopupEnabled(boolean aFlag) {
 373         boolean oldFlag = lightWeightPopupEnabled;
 374         lightWeightPopupEnabled = aFlag;
 375         firePropertyChange("lightWeightPopupEnabled", oldFlag, lightWeightPopupEnabled);
 376     }
 377 
 378     /**
 379      * Gets the value of the <code>lightWeightPopupEnabled</code>
 380      * property.
 381      *
 382      * @return the value of the <code>lightWeightPopupEnabled</code>
 383      *    property
 384      * @see #setLightWeightPopupEnabled
 385      */
 386     public boolean isLightWeightPopupEnabled() {
 387         return lightWeightPopupEnabled;
 388     }
 389 
 390     /**
 391      * Determines whether the <code>JComboBox</code> field is editable.
 392      * An editable <code>JComboBox</code> allows the user to type into the
 393      * field or selected an item from the list to initialize the field,
 394      * after which it can be edited. (The editing affects only the field,
 395      * the list item remains intact.) A non editable <code>JComboBox</code>
 396      * displays the selected item in the field,
 397      * but the selection cannot be modified.
 398      *
 399      * @param aFlag a boolean value, where true indicates that the
 400      *                  field is editable
 401      *
 402      * @beaninfo
 403      *        bound: true
 404      *    preferred: true
 405      *  description: If true, the user can type a new value in the combo box.
 406      */


 407     public void setEditable(boolean aFlag) {
 408         boolean oldFlag = isEditable;
 409         isEditable = aFlag;
 410         firePropertyChange( "editable", oldFlag, isEditable );
 411     }
 412 
 413     /**
 414      * Returns true if the <code>JComboBox</code> is editable.
 415      * By default, a combo box is not editable.
 416      *
 417      * @return true if the <code>JComboBox</code> is editable, else false
 418      */
 419     public boolean isEditable() {
 420         return isEditable;
 421     }
 422 
 423     /**
 424      * Sets the maximum number of rows the <code>JComboBox</code> displays.
 425      * If the number of objects in the model is greater than count,
 426      * the combo box uses a scrollbar.
 427      *
 428      * @param count an integer specifying the maximum number of items to
 429      *              display in the list before using a scrollbar
 430      * @beaninfo
 431      *        bound: true
 432      *    preferred: true
 433      *  description: The maximum number of rows the popup should have
 434      */


 435     public void setMaximumRowCount(int count) {
 436         int oldCount = maximumRowCount;
 437         maximumRowCount = count;
 438         firePropertyChange( "maximumRowCount", oldCount, maximumRowCount );
 439     }
 440 
 441     /**
 442      * Returns the maximum number of items the combo box can display
 443      * without a scrollbar
 444      *
 445      * @return an integer specifying the maximum number of items that are
 446      *         displayed in the list before using a scrollbar
 447      */
 448     public int getMaximumRowCount() {
 449         return maximumRowCount;
 450     }
 451 
 452     /**
 453      * Sets the renderer that paints the list items and the item selected from the list in
 454      * the JComboBox field. The renderer is used if the JComboBox is not
 455      * editable. If it is editable, the editor is used to render and edit
 456      * the selected item.
 457      * <p>
 458      * The default renderer displays a string or an icon.
 459      * Other renderers can handle graphic images and composite items.
 460      * <p>
 461      * To display the selected item,
 462      * <code>aRenderer.getListCellRendererComponent</code>
 463      * is called, passing the list object and an index of -1.
 464      *
 465      * @param aRenderer  the <code>ListCellRenderer</code> that
 466      *                  displays the selected item
 467      * @see #setEditor
 468      * @beaninfo
 469      *      bound: true
 470      *     expert: true
 471      *  description: The renderer that paints the item selected in the list.
 472      */


 473     public void setRenderer(ListCellRenderer<? super E> aRenderer) {
 474         ListCellRenderer<? super E> oldRenderer = renderer;
 475         renderer = aRenderer;
 476         firePropertyChange( "renderer", oldRenderer, renderer );
 477         invalidate();
 478     }
 479 
 480     /**
 481      * Returns the renderer used to display the selected item in the
 482      * <code>JComboBox</code> field.
 483      *
 484      * @return  the <code>ListCellRenderer</code> that displays
 485      *                  the selected item.
 486      */
 487     public ListCellRenderer<? super E> getRenderer() {
 488         return renderer;
 489     }
 490 
 491     /**
 492      * Sets the editor used to paint and edit the selected item in the
 493      * <code>JComboBox</code> field.  The editor is used only if the
 494      * receiving <code>JComboBox</code> is editable. If not editable,
 495      * the combo box uses the renderer to paint the selected item.
 496      *
 497      * @param anEditor  the <code>ComboBoxEditor</code> that
 498      *                  displays the selected item
 499      * @see #setRenderer
 500      * @beaninfo
 501      *     bound: true
 502      *    expert: true
 503      *  description: The editor that combo box uses to edit the current value
 504      */


 505     public void setEditor(ComboBoxEditor anEditor) {
 506         ComboBoxEditor oldEditor = editor;
 507 
 508         if ( editor != null ) {
 509             editor.removeActionListener(this);
 510         }
 511         editor = anEditor;
 512         if ( editor != null ) {
 513             editor.addActionListener(this);
 514         }
 515         firePropertyChange( "editor", oldEditor, editor );
 516     }
 517 
 518     /**
 519      * Returns the editor used to paint and edit the selected item in the
 520      * <code>JComboBox</code> field.
 521      *
 522      * @return the <code>ComboBoxEditor</code> that displays the selected item
 523      */
 524     public ComboBoxEditor getEditor() {


 536      * <code>anObject</code> selected.
 537      * <p>
 538      * If <code>anObject</code> is <i>not</i> in the list and the combo box is
 539      * uneditable, it will not change the current selection. For editable
 540      * combo boxes, the selection will change to <code>anObject</code>.
 541      * <p>
 542      * If this constitutes a change in the selected item,
 543      * <code>ItemListener</code>s added to the combo box will be notified with
 544      * one or two <code>ItemEvent</code>s.
 545      * If there is a current selected item, an <code>ItemEvent</code> will be
 546      * fired and the state change will be <code>ItemEvent.DESELECTED</code>.
 547      * If <code>anObject</code> is in the list and is not currently selected
 548      * then an <code>ItemEvent</code> will be fired and the state change will
 549      * be <code>ItemEvent.SELECTED</code>.
 550      * <p>
 551      * <code>ActionListener</code>s added to the combo box will be notified
 552      * with an <code>ActionEvent</code> when this method is called.
 553      *
 554      * @param anObject  the list object to select; use <code>null</code> to
 555                         clear the selection
 556      * @beaninfo
 557      *    preferred:   true
 558      *    description: Sets the selected item in the JComboBox.
 559      */


 560     public void setSelectedItem(Object anObject) {
 561         Object oldSelection = selectedItemReminder;
 562         Object objectToSelect = anObject;
 563         if (oldSelection == null || !oldSelection.equals(anObject)) {
 564 
 565             if (anObject != null && !isEditable()) {
 566                 // For non editable combo boxes, an invalid selection
 567                 // will be rejected.
 568                 boolean found = false;
 569                 for (int i = 0; i < dataModel.getSize(); i++) {
 570                     E element = dataModel.getElementAt(i);
 571                     if (anObject.equals(element)) {
 572                         found = true;
 573                         objectToSelect = element;
 574                         break;
 575                     }
 576                 }
 577                 if (!found) {
 578                     return;
 579                 }


 601      * Returns the current selected item.
 602      * <p>
 603      * If the combo box is editable, then this value may not have been added
 604      * to the combo box with <code>addItem</code>, <code>insertItemAt</code>
 605      * or the data constructors.
 606      *
 607      * @return the current selected Object
 608      * @see #setSelectedItem
 609      */
 610     public Object getSelectedItem() {
 611         return dataModel.getSelectedItem();
 612     }
 613 
 614     /**
 615      * Selects the item at index <code>anIndex</code>.
 616      *
 617      * @param anIndex an integer specifying the list item to select,
 618      *                  where 0 specifies the first item in the list and -1 indicates no selection
 619      * @exception IllegalArgumentException if <code>anIndex</code> &lt; -1 or
 620      *                  <code>anIndex</code> is greater than or equal to size
 621      * @beaninfo
 622      *   preferred: true
 623      *  description: The item at index is selected.
 624      */


 625     public void setSelectedIndex(int anIndex) {
 626         int size = dataModel.getSize();
 627 
 628         if ( anIndex == -1 ) {
 629             setSelectedItem( null );
 630         } else if ( anIndex < -1 || anIndex >= size ) {
 631             throw new IllegalArgumentException("setSelectedIndex: " + anIndex + " out of bounds");
 632         } else {
 633             setSelectedItem(dataModel.getElementAt(anIndex));
 634         }
 635     }
 636 
 637     /**
 638      * Returns the first item in the list that matches the given item.
 639      * The result is not always defined if the <code>JComboBox</code>
 640      * allows selected items that are not in the list.
 641      * Returns -1 if there is no selected item or if the user specified
 642      * an item which is not in the list.
 643 
 644      * @return an integer specifying the currently selected list item,


 672     public E getPrototypeDisplayValue() {
 673         return prototypeDisplayValue;
 674     }
 675 
 676     /**
 677      * Sets the prototype display value used to calculate the size of the display
 678      * for the UI portion.
 679      * <p>
 680      * If a prototype display value is specified, the preferred size of
 681      * the combo box is calculated by configuring the renderer with the
 682      * prototype display value and obtaining its preferred size. Specifying
 683      * the preferred display value is often useful when the combo box will be
 684      * displaying large amounts of data. If no prototype display value has
 685      * been specified, the renderer must be configured for each value from
 686      * the model and its preferred size obtained, which can be
 687      * relatively expensive.
 688      *
 689      * @param prototypeDisplayValue the prototype display value
 690      * @see #getPrototypeDisplayValue
 691      * @since 1.4
 692      * @beaninfo
 693      *       bound: true
 694      *   attribute: visualUpdate true
 695      * description: The display prototype value, used to compute display width and height.
 696      */


 697     public void setPrototypeDisplayValue(E prototypeDisplayValue) {
 698         Object oldValue = this.prototypeDisplayValue;
 699         this.prototypeDisplayValue = prototypeDisplayValue;
 700         firePropertyChange("prototypeDisplayValue", oldValue, prototypeDisplayValue);
 701     }
 702 
 703     /**
 704      * Adds an item to the item list.
 705      * This method works only if the <code>JComboBox</code> uses a
 706      * mutable data model.
 707      * <p>
 708      * <strong>Warning:</strong>
 709      * Focus and keyboard navigation problems may arise if you add duplicate
 710      * String objects. A workaround is to add new objects instead of String
 711      * objects and make sure that the toString() method is defined.
 712      * For example:
 713      * <pre>
 714      *   comboBox.addItem(makeObj("Item 1"));
 715      *   comboBox.addItem(makeObj("Item 1"));
 716      *   ...


 852     public void addItemListener(ItemListener aListener) {
 853         listenerList.add(ItemListener.class,aListener);
 854     }
 855 
 856     /** Removes an <code>ItemListener</code>.
 857      *
 858      * @param aListener  the <code>ItemListener</code> to remove
 859      */
 860     public void removeItemListener(ItemListener aListener) {
 861         listenerList.remove(ItemListener.class,aListener);
 862     }
 863 
 864     /**
 865      * Returns an array of all the <code>ItemListener</code>s added
 866      * to this JComboBox with addItemListener().
 867      *
 868      * @return all of the <code>ItemListener</code>s added or an empty
 869      *         array if no listeners have been added
 870      * @since 1.4
 871      */

 872     public ItemListener[] getItemListeners() {
 873         return listenerList.getListeners(ItemListener.class);
 874     }
 875 
 876     /**
 877      * Adds an <code>ActionListener</code>.
 878      * <p>
 879      * The <code>ActionListener</code> will receive an <code>ActionEvent</code>
 880      * when a selection has been made. If the combo box is editable, then
 881      * an <code>ActionEvent</code> will be fired when editing has stopped.
 882      *
 883      * @param l  the <code>ActionListener</code> that is to be notified
 884      * @see #setSelectedItem
 885      */
 886     public void addActionListener(ActionListener l) {
 887         listenerList.add(ActionListener.class,l);
 888     }
 889 
 890     /** Removes an <code>ActionListener</code>.
 891      *
 892      * @param l  the <code>ActionListener</code> to remove
 893      */
 894     public void removeActionListener(ActionListener l) {
 895         if ((l != null) && (getAction() == l)) {
 896             setAction(null);
 897         } else {
 898             listenerList.remove(ActionListener.class, l);
 899         }
 900     }
 901 
 902     /**
 903      * Returns an array of all the <code>ActionListener</code>s added
 904      * to this JComboBox with addActionListener().
 905      *
 906      * @return all of the <code>ActionListener</code>s added or an empty
 907      *         array if no listeners have been added
 908      * @since 1.4
 909      */

 910     public ActionListener[] getActionListeners() {
 911         return listenerList.getListeners(ActionListener.class);
 912     }
 913 
 914     /**
 915      * Adds a <code>PopupMenu</code> listener which will listen to notification
 916      * messages from the popup portion of the combo box.
 917      * <p>
 918      * For all standard look and feels shipped with Java, the popup list
 919      * portion of combo box is implemented as a <code>JPopupMenu</code>.
 920      * A custom look and feel may not implement it this way and will
 921      * therefore not receive the notification.
 922      *
 923      * @param l  the <code>PopupMenuListener</code> to add
 924      * @since 1.4
 925      */
 926     public void addPopupMenuListener(PopupMenuListener l) {
 927         listenerList.add(PopupMenuListener.class,l);
 928     }
 929 
 930     /**
 931      * Removes a <code>PopupMenuListener</code>.
 932      *
 933      * @param l  the <code>PopupMenuListener</code> to remove
 934      * @see #addPopupMenuListener
 935      * @since 1.4
 936      */
 937     public void removePopupMenuListener(PopupMenuListener l) {
 938         listenerList.remove(PopupMenuListener.class,l);
 939     }
 940 
 941     /**
 942      * Returns an array of all the <code>PopupMenuListener</code>s added
 943      * to this JComboBox with addPopupMenuListener().
 944      *
 945      * @return all of the <code>PopupMenuListener</code>s added or an empty
 946      *         array if no listeners have been added
 947      * @since 1.4
 948      */

 949     public PopupMenuListener[] getPopupMenuListeners() {
 950         return listenerList.getListeners(PopupMenuListener.class);
 951     }
 952 
 953     /**
 954      * Notifies <code>PopupMenuListener</code>s that the popup portion of the
 955      * combo box will become visible.
 956      * <p>
 957      * This method is public but should not be called by anything other than
 958      * the UI delegate.
 959      * @see #addPopupMenuListener
 960      * @since 1.4
 961      */
 962     public void firePopupMenuWillBecomeVisible() {
 963         Object[] listeners = listenerList.getListenerList();
 964         PopupMenuEvent e=null;
 965         for (int i = listeners.length-2; i>=0; i-=2) {
 966             if (listeners[i]==PopupMenuListener.class) {
 967                 if (e == null)
 968                     e = new PopupMenuEvent(this);


1057      * <p>
1058      * This method uses three other methods to set
1059      * and help track the <code>Action</code>'s property values.
1060      * It uses the <code>configurePropertiesFromAction</code> method
1061      * to immediately change the combobox's properties.
1062      * To track changes in the <code>Action</code>'s property values,
1063      * this method registers the <code>PropertyChangeListener</code>
1064      * returned by <code>createActionPropertyChangeListener</code>. The
1065      * default {@code PropertyChangeListener} invokes the
1066      * {@code actionPropertyChanged} method when a property in the
1067      * {@code Action} changes.
1068      *
1069      * @param a the <code>Action</code> for the <code>JComboBox</code>,
1070      *                  or <code>null</code>.
1071      * @since 1.3
1072      * @see Action
1073      * @see #getAction
1074      * @see #configurePropertiesFromAction
1075      * @see #createActionPropertyChangeListener
1076      * @see #actionPropertyChanged
1077      * @beaninfo
1078      *        bound: true
1079      *    attribute: visualUpdate true
1080      *  description: the Action instance connected with this ActionEvent source
1081      */


1082     public void setAction(Action a) {
1083         Action oldValue = getAction();
1084         if (action==null || !action.equals(a)) {
1085             action = a;
1086             if (oldValue!=null) {
1087                 removeActionListener(oldValue);
1088                 oldValue.removePropertyChangeListener(actionPropertyChangeListener);
1089                 actionPropertyChangeListener = null;
1090             }
1091             configurePropertiesFromAction(action);
1092             if (action!=null) {
1093                 // Don't add if it is already a listener
1094                 if (!isListener(ActionListener.class, action)) {
1095                     addActionListener(action);
1096                 }
1097                 // Reverse linkage:
1098                 actionPropertyChangeListener = createActionPropertyChangeListener(action);
1099                 action.addPropertyChangeListener(actionPropertyChangeListener);
1100             }
1101             firePropertyChange("action", oldValue, action);


1288         }
1289 
1290         // set the new selected item.
1291         selectedItemReminder = dataModel.getSelectedItem();
1292 
1293         if (selectedItemReminder != null ) {
1294             fireItemStateChanged(new ItemEvent(this,ItemEvent.ITEM_STATE_CHANGED,
1295                                                selectedItemReminder,
1296                                                ItemEvent.SELECTED));
1297         }
1298     }
1299 
1300     /**
1301      * Returns an array containing the selected item.
1302      * This method is implemented for compatibility with
1303      * <code>ItemSelectable</code>.
1304      *
1305      * @return an array of <code>Objects</code> containing one
1306      *          element -- the selected item
1307      */

1308     public Object[] getSelectedObjects() {
1309         Object selectedObject = getSelectedItem();
1310         if ( selectedObject == null )
1311             return new Object[0];
1312         else {
1313             Object result[] = new Object[1];
1314             result[0] = selectedObject;
1315             return result;
1316         }
1317     }
1318 
1319     /**
1320      * This method is public as an implementation side effect.
1321      * do not call or override.
1322      */
1323     public void actionPerformed(ActionEvent e) {
1324         setPopupVisible(false);
1325         getModel().setSelectedItem(getEditor().getItem());
1326         String oldCommand = getActionCommand();
1327         setActionCommand("comboBoxEdited");


1377 
1378         if ( keySelectionManager == null )
1379             keySelectionManager = createDefaultKeySelectionManager();
1380 
1381         index = keySelectionManager.selectionForKey(keyChar,getModel());
1382         if ( index != -1 ) {
1383             setSelectedIndex(index);
1384             return true;
1385         }
1386         else
1387             return false;
1388     }
1389 
1390     /**
1391      * Enables the combo box so that items can be selected. When the
1392      * combo box is disabled, items cannot be selected and values
1393      * cannot be typed into its field (if it is editable).
1394      *
1395      * @param b a boolean value, where true enables the component and
1396      *          false disables it
1397      * @beaninfo
1398      *        bound: true
1399      *    preferred: true
1400      *  description: Whether the combo box is enabled.
1401      */


1402     public void setEnabled(boolean b) {
1403         super.setEnabled(b);
1404         firePropertyChange( "enabled", !isEnabled(), isEnabled() );
1405     }
1406 
1407     /**
1408      * Initializes the editor with the specified item.
1409      *
1410      * @param anEditor the <code>ComboBoxEditor</code> that displays
1411      *                  the list item in the
1412      *                  combo box field and allows it to be edited
1413      * @param anItem   the object to display and edit in the field
1414      */
1415     public void configureEditor(ComboBoxEditor anEditor, Object anItem) {
1416         anEditor.setItem(anItem);
1417     }
1418 
1419     /**
1420      * Handles <code>KeyEvent</code>s, looking for the Tab key.
1421      * If the Tab key is found, the popup window is closed.


1441 
1442         if (!isEditable() || condition != WHEN_FOCUSED || getEditor() == null
1443                 || !Boolean.TRUE.equals(getClientProperty("JComboBox.isTableCellEditor"))) {
1444             return false;
1445         }
1446 
1447         Component editorComponent = getEditor().getEditorComponent();
1448         if (editorComponent instanceof JComponent) {
1449             JComponent component = (JComponent) editorComponent;
1450             return component.processKeyBinding(ks, e, WHEN_FOCUSED, pressed);
1451         }
1452         return false;
1453     }
1454 
1455     /**
1456      * Sets the object that translates a keyboard character into a list
1457      * selection. Typically, the first selection with a matching first
1458      * character becomes the selected item.
1459      *
1460      * @param aManager a key selection manager
1461      * @beaninfo
1462      *       expert: true
1463      *  description: The objects that changes the selection when a key is pressed.
1464      */


1465     public void setKeySelectionManager(KeySelectionManager aManager) {
1466         keySelectionManager = aManager;
1467     }
1468 
1469     /**
1470      * Returns the list's key-selection manager.
1471      *
1472      * @return the <code>KeySelectionManager</code> currently in use
1473      */
1474     public KeySelectionManager getKeySelectionManager() {
1475         return keySelectionManager;
1476     }
1477 
1478     /* Accessing the model */
1479     /**
1480      * Returns the number of items in the list.
1481      *
1482      * @return an integer equal to the number of items in the list
1483      */

1484     public int getItemCount() {
1485         return dataModel.getSize();
1486     }
1487 
1488     /**
1489      * Returns the list item at the specified index.  If <code>index</code>
1490      * is out of range (less than zero or greater than or equal to size)
1491      * it will return <code>null</code>.
1492      *
1493      * @param index  an integer indicating the list position, where the first
1494      *               item starts at zero
1495      * @return the item at that list position; or
1496      *                  <code>null</code> if out of range
1497      */
1498     public E getItemAt(int index) {
1499         return dataModel.getElementAt(index);
1500     }
1501 
1502     /**
1503      * Returns an instance of the default key-selection manager.


1612         ",isEditable=" + isEditableString +
1613         ",lightWeightPopupEnabled=" + lightWeightPopupEnabledString +
1614         ",maximumRowCount=" + maximumRowCount +
1615         ",selectedItemReminder=" + selectedItemReminderString;
1616     }
1617 
1618 
1619 ///////////////////
1620 // Accessibility support
1621 ///////////////////
1622 
1623     /**
1624      * Gets the AccessibleContext associated with this JComboBox.
1625      * For combo boxes, the AccessibleContext takes the form of an
1626      * AccessibleJComboBox.
1627      * A new AccessibleJComboBox instance is created if necessary.
1628      *
1629      * @return an AccessibleJComboBox that serves as the
1630      *         AccessibleContext of this JComboBox
1631      */

1632     public AccessibleContext getAccessibleContext() {
1633         if ( accessibleContext == null ) {
1634             accessibleContext = new AccessibleJComboBox();
1635         }
1636         return accessibleContext;
1637     }
1638 
1639     /**
1640      * This class implements accessibility support for the
1641      * <code>JComboBox</code> class.  It provides an implementation of the
1642      * Java Accessibility API appropriate to Combo Box user-interface elements.
1643      * <p>
1644      * <strong>Warning:</strong>
1645      * Serialized objects of this class will not be compatible with
1646      * future Swing releases. The current serialization support is
1647      * appropriate for short term storage or RMI between applications running
1648      * the same version of Swing.  As of 1.4, support for long term storage
1649      * of all JavaBeans&trade;
1650      * has been added to the <code>java.beans</code> package.
1651      * Please see {@link java.beans.XMLEncoder}.


2114              * could be 'city.'
2115              *
2116              * @return the localized name of the object; null if this
2117              * object does not have a name
2118              *
2119              * @see #setAccessibleName
2120              */
2121             public String getAccessibleName() {
2122                 return ac.getAccessibleName();
2123             }
2124 
2125             /**
2126              * Sets the localized accessible name of this object.  Changing the
2127              * name will cause a PropertyChangeEvent to be fired for the
2128              * ACCESSIBLE_NAME_PROPERTY property.
2129              *
2130              * @param s the new localized name of the object.
2131              *
2132              * @see #getAccessibleName
2133              * @see #addPropertyChangeListener
2134              *
2135              * @beaninfo
2136              *    preferred:   true
2137              *    description: Sets the accessible name for the component.
2138              */


2139             public void setAccessibleName(String s) {
2140                 ac.setAccessibleName(s);
2141             }
2142 
2143             /**
2144              * Gets the accessibleDescription property of this object.  The
2145              * accessibleDescription property of this object is a short localized
2146              * phrase describing the purpose of the object.  For example, in the
2147              * case of a 'Cancel' button, the accessibleDescription could be
2148              * 'Ignore changes and close dialog box.'
2149              *
2150              * @return the localized description of the object; null if
2151              * this object does not have a description
2152              *
2153              * @see #setAccessibleDescription
2154              */
2155             public String getAccessibleDescription() {
2156                 return ac.getAccessibleDescription();
2157             }
2158 
2159             /**
2160              * Sets the accessible description of this object.  Changing the
2161              * name will cause a PropertyChangeEvent to be fired for the
2162              * ACCESSIBLE_DESCRIPTION_PROPERTY property.
2163              *
2164              * @param s the new localized description of the object
2165              *
2166              * @see #setAccessibleName
2167              * @see #addPropertyChangeListener
2168              *
2169              * @beaninfo
2170              *    preferred:   true
2171              *    description: Sets the accessible description for the component.
2172              */


2173             public void setAccessibleDescription(String s) {
2174                 ac.setAccessibleDescription(s);
2175             }
2176 
2177             /**
2178              * Gets the role of this object.  The role of the object is the generic
2179              * purpose or use of the class of this object.  For example, the role
2180              * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in
2181              * AccessibleRole are provided so component developers can pick from
2182              * a set of predefined roles.  This enables assistive technologies to
2183              * provide a consistent interface to various tweaked subclasses of
2184              * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
2185              * that act like a push button) as well as distinguish between subclasses
2186              * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
2187              * and AccessibleRole.RADIO_BUTTON for radio buttons).
2188              * <p>Note that the AccessibleRole class is also extensible, so
2189              * custom component developers can define their own AccessibleRole's
2190              * if the set of predefined roles is inadequate.
2191              *
2192              * @return an instance of AccessibleRole describing the role of the object


   1 /*
   2  * Copyright (c) 1997, 2015, 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.JavaBean;
  28 import java.beans.BeanProperty;
  29 import java.beans.PropertyChangeEvent;
  30 import java.beans.PropertyChangeListener;
  31 import java.beans.Transient;
  32 import java.util.*;
  33 
  34 import java.awt.*;
  35 import java.awt.event.*;
  36 
  37 import java.io.Serializable;
  38 import java.io.ObjectOutputStream;
  39 import java.io.IOException;
  40 
  41 import javax.swing.event.*;
  42 import javax.swing.plaf.*;
  43 
  44 import javax.accessibility.*;
  45 
  46 /**
  47  * A component that combines a button or editable field and a drop-down list.
  48  * The user can select a value from the drop-down list, which appears at the


  56  * <p>
  57  * <strong>Warning:</strong>
  58  * Serialized objects of this class will not be compatible with
  59  * future Swing releases. The current serialization support is
  60  * appropriate for short term storage or RMI between applications running
  61  * the same version of Swing.  As of 1.4, support for long term storage
  62  * of all JavaBeans&trade;
  63  * has been added to the <code>java.beans</code> package.
  64  * Please see {@link java.beans.XMLEncoder}.
  65  *
  66  * <p>
  67  * See <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html">How to Use Combo Boxes</a>
  68  * in <a href="http://docs.oracle.com/javase/tutorial/"><em>The Java Tutorial</em></a>
  69  * for further information.
  70  *
  71  * @see ComboBoxModel
  72  * @see DefaultComboBoxModel
  73  *
  74  * @param <E> the type of the elements of this combo box
  75  *




  76  * @author Arnaud Weber
  77  * @author Mark Davidson
  78  * @since 1.2
  79  */
  80 @JavaBean(defaultProperty = "UI", description = "A combination of a text field and a drop-down list.")
  81 @SwingContainer(false)
  82 @SuppressWarnings("serial") // Same-version serialization only
  83 public class JComboBox<E> extends JComponent
  84 implements ItemSelectable,ListDataListener,ActionListener, Accessible {
  85     /**
  86      * @see #getUIClassID
  87      * @see #readObject
  88      */
  89     private static final String uiClassID = "ComboBoxUI";
  90 
  91     /**
  92      * This protected field is implementation specific. Do not access directly
  93      * or override. Use the accessor methods instead.
  94      *
  95      * @see #getModel
  96      * @see #setModel
  97      */
  98     protected ComboBoxModel<E>    dataModel;
  99     /**
 100      * This protected field is implementation specific. Do not access directly
 101      * or override. Use the accessor methods instead.


 238      * {@code AncestorEvents} when it or any of its ancestors
 239      * move or are made visible or invisible.
 240      * Events are also sent when the component or its ancestors are added
 241      * or removed from the containment hierarchy.
 242      */
 243     protected void installAncestorListener() {
 244         addAncestorListener(new AncestorListener(){
 245                                 public void ancestorAdded(AncestorEvent event){ hidePopup();}
 246                                 public void ancestorRemoved(AncestorEvent event){ hidePopup();}
 247                                 public void ancestorMoved(AncestorEvent event){
 248                                     if (event.getSource() != JComboBox.this)
 249                                         hidePopup();
 250                                 }});
 251     }
 252 
 253     /**
 254      * Sets the L&amp;F object that renders this component.
 255      *
 256      * @param ui  the <code>ComboBoxUI</code> L&amp;F object
 257      * @see UIDefaults#getUI






 258      */
 259     @BeanProperty(hidden = true, visualUpdate = true, description
 260             = "The UI object that implements the Component's LookAndFeel.")
 261     public void setUI(ComboBoxUI ui) {
 262         super.setUI(ui);
 263     }
 264 
 265     /**
 266      * Resets the UI property to a value from the current look and feel.
 267      *
 268      * @see JComponent#updateUI
 269      */
 270     public void updateUI() {
 271         setUI((ComboBoxUI)UIManager.getUI(this));
 272 
 273         ListCellRenderer<? super E> renderer = getRenderer();
 274         if (renderer instanceof Component) {
 275             SwingUtilities.updateComponentTreeUI((Component)renderer);
 276         }
 277     }
 278 
 279 
 280     /**
 281      * Returns the name of the L&amp;F class that renders this component.
 282      *
 283      * @return the string "ComboBoxUI"
 284      * @see JComponent#getUIClassID
 285      * @see UIDefaults#getUI
 286      */
 287     @BeanProperty(bound = false)
 288     public String getUIClassID() {
 289         return uiClassID;
 290     }
 291 
 292 
 293     /**
 294      * Returns the L&amp;F object that renders this component.
 295      *
 296      * @return the ComboBoxUI object that renders this component
 297      */
 298     public ComboBoxUI getUI() {
 299         return(ComboBoxUI)ui;
 300     }
 301 
 302     /**
 303      * Sets the data model that the <code>JComboBox</code> uses to obtain
 304      * the list of items.
 305      *
 306      * @param aModel the <code>ComboBoxModel</code> that provides the
 307      *  displayed list of items




 308      */
 309     @BeanProperty(description
 310             = "Model that the combo box uses to get data to display.")
 311     public void setModel(ComboBoxModel<E> aModel) {
 312         ComboBoxModel<E> oldModel = dataModel;
 313         if (oldModel != null) {
 314             oldModel.removeListDataListener(this);
 315         }
 316         dataModel = aModel;
 317         dataModel.addListDataListener(this);
 318 
 319         // set the current selected item.
 320         selectedItemReminder = dataModel.getSelectedItem();
 321 
 322         firePropertyChange( "model", oldModel, dataModel);
 323     }
 324 
 325     /**
 326      * Returns the data model currently used by the <code>JComboBox</code>.
 327      *
 328      * @return the <code>ComboBoxModel</code> that provides the displayed
 329      *                  list of items
 330      */


 341      * provides a hint as to whether or not a lightweight
 342      * <code>Component</code> should be used to contain the
 343      * <code>JComboBox</code>, versus a heavyweight
 344      * <code>Component</code> such as a <code>Panel</code>
 345      * or a <code>Window</code>.  The decision of lightweight
 346      * versus heavyweight is ultimately up to the
 347      * <code>JComboBox</code>.  Lightweight windows are more
 348      * efficient than heavyweight windows, but lightweight
 349      * and heavyweight components do not mix well in a GUI.
 350      * If your application mixes lightweight and heavyweight
 351      * components, you should disable lightweight popups.
 352      * The default value for the <code>lightWeightPopupEnabled</code>
 353      * property is <code>true</code>, unless otherwise specified
 354      * by the look and feel.  Some look and feels always use
 355      * heavyweight popups, no matter what the value of this property.
 356      * <p>
 357      * See the article <a href="http://www.oracle.com/technetwork/articles/java/mixing-components-433992.html">Mixing Heavy and Light Components</a>
 358      * This method fires a property changed event.
 359      *
 360      * @param aFlag if <code>true</code>, lightweight popups are desired





 361      */
 362     @BeanProperty(expert = true, description
 363             = "Set to <code>false</code> to require heavyweight popups.")
 364     public void setLightWeightPopupEnabled(boolean aFlag) {
 365         boolean oldFlag = lightWeightPopupEnabled;
 366         lightWeightPopupEnabled = aFlag;
 367         firePropertyChange("lightWeightPopupEnabled", oldFlag, lightWeightPopupEnabled);
 368     }
 369 
 370     /**
 371      * Gets the value of the <code>lightWeightPopupEnabled</code>
 372      * property.
 373      *
 374      * @return the value of the <code>lightWeightPopupEnabled</code>
 375      *    property
 376      * @see #setLightWeightPopupEnabled
 377      */
 378     public boolean isLightWeightPopupEnabled() {
 379         return lightWeightPopupEnabled;
 380     }
 381 
 382     /**
 383      * Determines whether the <code>JComboBox</code> field is editable.
 384      * An editable <code>JComboBox</code> allows the user to type into the
 385      * field or selected an item from the list to initialize the field,
 386      * after which it can be edited. (The editing affects only the field,
 387      * the list item remains intact.) A non editable <code>JComboBox</code>
 388      * displays the selected item in the field,
 389      * but the selection cannot be modified.
 390      *
 391      * @param aFlag a boolean value, where true indicates that the
 392      *                  field is editable





 393      */
 394     @BeanProperty(preferred = true, description
 395             = "If true, the user can type a new value in the combo box.")
 396     public void setEditable(boolean aFlag) {
 397         boolean oldFlag = isEditable;
 398         isEditable = aFlag;
 399         firePropertyChange( "editable", oldFlag, isEditable );
 400     }
 401 
 402     /**
 403      * Returns true if the <code>JComboBox</code> is editable.
 404      * By default, a combo box is not editable.
 405      *
 406      * @return true if the <code>JComboBox</code> is editable, else false
 407      */
 408     public boolean isEditable() {
 409         return isEditable;
 410     }
 411 
 412     /**
 413      * Sets the maximum number of rows the <code>JComboBox</code> displays.
 414      * If the number of objects in the model is greater than count,
 415      * the combo box uses a scrollbar.
 416      *
 417      * @param count an integer specifying the maximum number of items to
 418      *              display in the list before using a scrollbar




 419      */
 420     @BeanProperty(preferred = true, description
 421             = "The maximum number of rows the popup should have")
 422     public void setMaximumRowCount(int count) {
 423         int oldCount = maximumRowCount;
 424         maximumRowCount = count;
 425         firePropertyChange( "maximumRowCount", oldCount, maximumRowCount );
 426     }
 427 
 428     /**
 429      * Returns the maximum number of items the combo box can display
 430      * without a scrollbar
 431      *
 432      * @return an integer specifying the maximum number of items that are
 433      *         displayed in the list before using a scrollbar
 434      */
 435     public int getMaximumRowCount() {
 436         return maximumRowCount;
 437     }
 438 
 439     /**
 440      * Sets the renderer that paints the list items and the item selected from the list in
 441      * the JComboBox field. The renderer is used if the JComboBox is not
 442      * editable. If it is editable, the editor is used to render and edit
 443      * the selected item.
 444      * <p>
 445      * The default renderer displays a string or an icon.
 446      * Other renderers can handle graphic images and composite items.
 447      * <p>
 448      * To display the selected item,
 449      * <code>aRenderer.getListCellRendererComponent</code>
 450      * is called, passing the list object and an index of -1.
 451      *
 452      * @param aRenderer  the <code>ListCellRenderer</code> that
 453      *                  displays the selected item
 454      * @see #setEditor




 455      */
 456     @BeanProperty(expert = true, description
 457             = "The renderer that paints the item selected in the list.")
 458     public void setRenderer(ListCellRenderer<? super E> aRenderer) {
 459         ListCellRenderer<? super E> oldRenderer = renderer;
 460         renderer = aRenderer;
 461         firePropertyChange( "renderer", oldRenderer, renderer );
 462         invalidate();
 463     }
 464 
 465     /**
 466      * Returns the renderer used to display the selected item in the
 467      * <code>JComboBox</code> field.
 468      *
 469      * @return  the <code>ListCellRenderer</code> that displays
 470      *                  the selected item.
 471      */
 472     public ListCellRenderer<? super E> getRenderer() {
 473         return renderer;
 474     }
 475 
 476     /**
 477      * Sets the editor used to paint and edit the selected item in the
 478      * <code>JComboBox</code> field.  The editor is used only if the
 479      * receiving <code>JComboBox</code> is editable. If not editable,
 480      * the combo box uses the renderer to paint the selected item.
 481      *
 482      * @param anEditor  the <code>ComboBoxEditor</code> that
 483      *                  displays the selected item
 484      * @see #setRenderer




 485      */
 486     @BeanProperty(expert = true, description
 487             = "The editor that combo box uses to edit the current value")
 488     public void setEditor(ComboBoxEditor anEditor) {
 489         ComboBoxEditor oldEditor = editor;
 490 
 491         if ( editor != null ) {
 492             editor.removeActionListener(this);
 493         }
 494         editor = anEditor;
 495         if ( editor != null ) {
 496             editor.addActionListener(this);
 497         }
 498         firePropertyChange( "editor", oldEditor, editor );
 499     }
 500 
 501     /**
 502      * Returns the editor used to paint and edit the selected item in the
 503      * <code>JComboBox</code> field.
 504      *
 505      * @return the <code>ComboBoxEditor</code> that displays the selected item
 506      */
 507     public ComboBoxEditor getEditor() {


 519      * <code>anObject</code> selected.
 520      * <p>
 521      * If <code>anObject</code> is <i>not</i> in the list and the combo box is
 522      * uneditable, it will not change the current selection. For editable
 523      * combo boxes, the selection will change to <code>anObject</code>.
 524      * <p>
 525      * If this constitutes a change in the selected item,
 526      * <code>ItemListener</code>s added to the combo box will be notified with
 527      * one or two <code>ItemEvent</code>s.
 528      * If there is a current selected item, an <code>ItemEvent</code> will be
 529      * fired and the state change will be <code>ItemEvent.DESELECTED</code>.
 530      * If <code>anObject</code> is in the list and is not currently selected
 531      * then an <code>ItemEvent</code> will be fired and the state change will
 532      * be <code>ItemEvent.SELECTED</code>.
 533      * <p>
 534      * <code>ActionListener</code>s added to the combo box will be notified
 535      * with an <code>ActionEvent</code> when this method is called.
 536      *
 537      * @param anObject  the list object to select; use <code>null</code> to
 538                         clear the selection



 539      */
 540     @BeanProperty(bound = false, preferred = true, description
 541             = "Sets the selected item in the JComboBox.")
 542     public void setSelectedItem(Object anObject) {
 543         Object oldSelection = selectedItemReminder;
 544         Object objectToSelect = anObject;
 545         if (oldSelection == null || !oldSelection.equals(anObject)) {
 546 
 547             if (anObject != null && !isEditable()) {
 548                 // For non editable combo boxes, an invalid selection
 549                 // will be rejected.
 550                 boolean found = false;
 551                 for (int i = 0; i < dataModel.getSize(); i++) {
 552                     E element = dataModel.getElementAt(i);
 553                     if (anObject.equals(element)) {
 554                         found = true;
 555                         objectToSelect = element;
 556                         break;
 557                     }
 558                 }
 559                 if (!found) {
 560                     return;
 561                 }


 583      * Returns the current selected item.
 584      * <p>
 585      * If the combo box is editable, then this value may not have been added
 586      * to the combo box with <code>addItem</code>, <code>insertItemAt</code>
 587      * or the data constructors.
 588      *
 589      * @return the current selected Object
 590      * @see #setSelectedItem
 591      */
 592     public Object getSelectedItem() {
 593         return dataModel.getSelectedItem();
 594     }
 595 
 596     /**
 597      * Selects the item at index <code>anIndex</code>.
 598      *
 599      * @param anIndex an integer specifying the list item to select,
 600      *                  where 0 specifies the first item in the list and -1 indicates no selection
 601      * @exception IllegalArgumentException if <code>anIndex</code> &lt; -1 or
 602      *                  <code>anIndex</code> is greater than or equal to size



 603      */
 604     @BeanProperty(bound = false, preferred = true, description
 605             = "The item at index is selected.")
 606     public void setSelectedIndex(int anIndex) {
 607         int size = dataModel.getSize();
 608 
 609         if ( anIndex == -1 ) {
 610             setSelectedItem( null );
 611         } else if ( anIndex < -1 || anIndex >= size ) {
 612             throw new IllegalArgumentException("setSelectedIndex: " + anIndex + " out of bounds");
 613         } else {
 614             setSelectedItem(dataModel.getElementAt(anIndex));
 615         }
 616     }
 617 
 618     /**
 619      * Returns the first item in the list that matches the given item.
 620      * The result is not always defined if the <code>JComboBox</code>
 621      * allows selected items that are not in the list.
 622      * Returns -1 if there is no selected item or if the user specified
 623      * an item which is not in the list.
 624 
 625      * @return an integer specifying the currently selected list item,


 653     public E getPrototypeDisplayValue() {
 654         return prototypeDisplayValue;
 655     }
 656 
 657     /**
 658      * Sets the prototype display value used to calculate the size of the display
 659      * for the UI portion.
 660      * <p>
 661      * If a prototype display value is specified, the preferred size of
 662      * the combo box is calculated by configuring the renderer with the
 663      * prototype display value and obtaining its preferred size. Specifying
 664      * the preferred display value is often useful when the combo box will be
 665      * displaying large amounts of data. If no prototype display value has
 666      * been specified, the renderer must be configured for each value from
 667      * the model and its preferred size obtained, which can be
 668      * relatively expensive.
 669      *
 670      * @param prototypeDisplayValue the prototype display value
 671      * @see #getPrototypeDisplayValue
 672      * @since 1.4




 673      */
 674     @BeanProperty(visualUpdate = true, description
 675             = "The display prototype value, used to compute display width and height.")
 676     public void setPrototypeDisplayValue(E prototypeDisplayValue) {
 677         Object oldValue = this.prototypeDisplayValue;
 678         this.prototypeDisplayValue = prototypeDisplayValue;
 679         firePropertyChange("prototypeDisplayValue", oldValue, prototypeDisplayValue);
 680     }
 681 
 682     /**
 683      * Adds an item to the item list.
 684      * This method works only if the <code>JComboBox</code> uses a
 685      * mutable data model.
 686      * <p>
 687      * <strong>Warning:</strong>
 688      * Focus and keyboard navigation problems may arise if you add duplicate
 689      * String objects. A workaround is to add new objects instead of String
 690      * objects and make sure that the toString() method is defined.
 691      * For example:
 692      * <pre>
 693      *   comboBox.addItem(makeObj("Item 1"));
 694      *   comboBox.addItem(makeObj("Item 1"));
 695      *   ...


 831     public void addItemListener(ItemListener aListener) {
 832         listenerList.add(ItemListener.class,aListener);
 833     }
 834 
 835     /** Removes an <code>ItemListener</code>.
 836      *
 837      * @param aListener  the <code>ItemListener</code> to remove
 838      */
 839     public void removeItemListener(ItemListener aListener) {
 840         listenerList.remove(ItemListener.class,aListener);
 841     }
 842 
 843     /**
 844      * Returns an array of all the <code>ItemListener</code>s added
 845      * to this JComboBox with addItemListener().
 846      *
 847      * @return all of the <code>ItemListener</code>s added or an empty
 848      *         array if no listeners have been added
 849      * @since 1.4
 850      */
 851     @BeanProperty(bound = false)
 852     public ItemListener[] getItemListeners() {
 853         return listenerList.getListeners(ItemListener.class);
 854     }
 855 
 856     /**
 857      * Adds an <code>ActionListener</code>.
 858      * <p>
 859      * The <code>ActionListener</code> will receive an <code>ActionEvent</code>
 860      * when a selection has been made. If the combo box is editable, then
 861      * an <code>ActionEvent</code> will be fired when editing has stopped.
 862      *
 863      * @param l  the <code>ActionListener</code> that is to be notified
 864      * @see #setSelectedItem
 865      */
 866     public void addActionListener(ActionListener l) {
 867         listenerList.add(ActionListener.class,l);
 868     }
 869 
 870     /** Removes an <code>ActionListener</code>.
 871      *
 872      * @param l  the <code>ActionListener</code> to remove
 873      */
 874     public void removeActionListener(ActionListener l) {
 875         if ((l != null) && (getAction() == l)) {
 876             setAction(null);
 877         } else {
 878             listenerList.remove(ActionListener.class, l);
 879         }
 880     }
 881 
 882     /**
 883      * Returns an array of all the <code>ActionListener</code>s added
 884      * to this JComboBox with addActionListener().
 885      *
 886      * @return all of the <code>ActionListener</code>s added or an empty
 887      *         array if no listeners have been added
 888      * @since 1.4
 889      */
 890     @BeanProperty(bound = false)
 891     public ActionListener[] getActionListeners() {
 892         return listenerList.getListeners(ActionListener.class);
 893     }
 894 
 895     /**
 896      * Adds a <code>PopupMenu</code> listener which will listen to notification
 897      * messages from the popup portion of the combo box.
 898      * <p>
 899      * For all standard look and feels shipped with Java, the popup list
 900      * portion of combo box is implemented as a <code>JPopupMenu</code>.
 901      * A custom look and feel may not implement it this way and will
 902      * therefore not receive the notification.
 903      *
 904      * @param l  the <code>PopupMenuListener</code> to add
 905      * @since 1.4
 906      */
 907     public void addPopupMenuListener(PopupMenuListener l) {
 908         listenerList.add(PopupMenuListener.class,l);
 909     }
 910 
 911     /**
 912      * Removes a <code>PopupMenuListener</code>.
 913      *
 914      * @param l  the <code>PopupMenuListener</code> to remove
 915      * @see #addPopupMenuListener
 916      * @since 1.4
 917      */
 918     public void removePopupMenuListener(PopupMenuListener l) {
 919         listenerList.remove(PopupMenuListener.class,l);
 920     }
 921 
 922     /**
 923      * Returns an array of all the <code>PopupMenuListener</code>s added
 924      * to this JComboBox with addPopupMenuListener().
 925      *
 926      * @return all of the <code>PopupMenuListener</code>s added or an empty
 927      *         array if no listeners have been added
 928      * @since 1.4
 929      */
 930     @BeanProperty(bound = false)
 931     public PopupMenuListener[] getPopupMenuListeners() {
 932         return listenerList.getListeners(PopupMenuListener.class);
 933     }
 934 
 935     /**
 936      * Notifies <code>PopupMenuListener</code>s that the popup portion of the
 937      * combo box will become visible.
 938      * <p>
 939      * This method is public but should not be called by anything other than
 940      * the UI delegate.
 941      * @see #addPopupMenuListener
 942      * @since 1.4
 943      */
 944     public void firePopupMenuWillBecomeVisible() {
 945         Object[] listeners = listenerList.getListenerList();
 946         PopupMenuEvent e=null;
 947         for (int i = listeners.length-2; i>=0; i-=2) {
 948             if (listeners[i]==PopupMenuListener.class) {
 949                 if (e == null)
 950                     e = new PopupMenuEvent(this);


1039      * <p>
1040      * This method uses three other methods to set
1041      * and help track the <code>Action</code>'s property values.
1042      * It uses the <code>configurePropertiesFromAction</code> method
1043      * to immediately change the combobox's properties.
1044      * To track changes in the <code>Action</code>'s property values,
1045      * this method registers the <code>PropertyChangeListener</code>
1046      * returned by <code>createActionPropertyChangeListener</code>. The
1047      * default {@code PropertyChangeListener} invokes the
1048      * {@code actionPropertyChanged} method when a property in the
1049      * {@code Action} changes.
1050      *
1051      * @param a the <code>Action</code> for the <code>JComboBox</code>,
1052      *                  or <code>null</code>.
1053      * @since 1.3
1054      * @see Action
1055      * @see #getAction
1056      * @see #configurePropertiesFromAction
1057      * @see #createActionPropertyChangeListener
1058      * @see #actionPropertyChanged




1059      */
1060     @BeanProperty(visualUpdate = true, description
1061             = "the Action instance connected with this ActionEvent source")
1062     public void setAction(Action a) {
1063         Action oldValue = getAction();
1064         if (action==null || !action.equals(a)) {
1065             action = a;
1066             if (oldValue!=null) {
1067                 removeActionListener(oldValue);
1068                 oldValue.removePropertyChangeListener(actionPropertyChangeListener);
1069                 actionPropertyChangeListener = null;
1070             }
1071             configurePropertiesFromAction(action);
1072             if (action!=null) {
1073                 // Don't add if it is already a listener
1074                 if (!isListener(ActionListener.class, action)) {
1075                     addActionListener(action);
1076                 }
1077                 // Reverse linkage:
1078                 actionPropertyChangeListener = createActionPropertyChangeListener(action);
1079                 action.addPropertyChangeListener(actionPropertyChangeListener);
1080             }
1081             firePropertyChange("action", oldValue, action);


1268         }
1269 
1270         // set the new selected item.
1271         selectedItemReminder = dataModel.getSelectedItem();
1272 
1273         if (selectedItemReminder != null ) {
1274             fireItemStateChanged(new ItemEvent(this,ItemEvent.ITEM_STATE_CHANGED,
1275                                                selectedItemReminder,
1276                                                ItemEvent.SELECTED));
1277         }
1278     }
1279 
1280     /**
1281      * Returns an array containing the selected item.
1282      * This method is implemented for compatibility with
1283      * <code>ItemSelectable</code>.
1284      *
1285      * @return an array of <code>Objects</code> containing one
1286      *          element -- the selected item
1287      */
1288     @BeanProperty(bound = false)
1289     public Object[] getSelectedObjects() {
1290         Object selectedObject = getSelectedItem();
1291         if ( selectedObject == null )
1292             return new Object[0];
1293         else {
1294             Object result[] = new Object[1];
1295             result[0] = selectedObject;
1296             return result;
1297         }
1298     }
1299 
1300     /**
1301      * This method is public as an implementation side effect.
1302      * do not call or override.
1303      */
1304     public void actionPerformed(ActionEvent e) {
1305         setPopupVisible(false);
1306         getModel().setSelectedItem(getEditor().getItem());
1307         String oldCommand = getActionCommand();
1308         setActionCommand("comboBoxEdited");


1358 
1359         if ( keySelectionManager == null )
1360             keySelectionManager = createDefaultKeySelectionManager();
1361 
1362         index = keySelectionManager.selectionForKey(keyChar,getModel());
1363         if ( index != -1 ) {
1364             setSelectedIndex(index);
1365             return true;
1366         }
1367         else
1368             return false;
1369     }
1370 
1371     /**
1372      * Enables the combo box so that items can be selected. When the
1373      * combo box is disabled, items cannot be selected and values
1374      * cannot be typed into its field (if it is editable).
1375      *
1376      * @param b a boolean value, where true enables the component and
1377      *          false disables it




1378      */
1379     @BeanProperty(preferred = true, description
1380             = "The enabled state of the component.")
1381     public void setEnabled(boolean b) {
1382         super.setEnabled(b);
1383         firePropertyChange( "enabled", !isEnabled(), isEnabled() );
1384     }
1385 
1386     /**
1387      * Initializes the editor with the specified item.
1388      *
1389      * @param anEditor the <code>ComboBoxEditor</code> that displays
1390      *                  the list item in the
1391      *                  combo box field and allows it to be edited
1392      * @param anItem   the object to display and edit in the field
1393      */
1394     public void configureEditor(ComboBoxEditor anEditor, Object anItem) {
1395         anEditor.setItem(anItem);
1396     }
1397 
1398     /**
1399      * Handles <code>KeyEvent</code>s, looking for the Tab key.
1400      * If the Tab key is found, the popup window is closed.


1420 
1421         if (!isEditable() || condition != WHEN_FOCUSED || getEditor() == null
1422                 || !Boolean.TRUE.equals(getClientProperty("JComboBox.isTableCellEditor"))) {
1423             return false;
1424         }
1425 
1426         Component editorComponent = getEditor().getEditorComponent();
1427         if (editorComponent instanceof JComponent) {
1428             JComponent component = (JComponent) editorComponent;
1429             return component.processKeyBinding(ks, e, WHEN_FOCUSED, pressed);
1430         }
1431         return false;
1432     }
1433 
1434     /**
1435      * Sets the object that translates a keyboard character into a list
1436      * selection. Typically, the first selection with a matching first
1437      * character becomes the selected item.
1438      *
1439      * @param aManager a key selection manager



1440      */
1441     @BeanProperty(bound = false, expert = true, description
1442             = "The objects that changes the selection when a key is pressed.")
1443     public void setKeySelectionManager(KeySelectionManager aManager) {
1444         keySelectionManager = aManager;
1445     }
1446 
1447     /**
1448      * Returns the list's key-selection manager.
1449      *
1450      * @return the <code>KeySelectionManager</code> currently in use
1451      */
1452     public KeySelectionManager getKeySelectionManager() {
1453         return keySelectionManager;
1454     }
1455 
1456     /* Accessing the model */
1457     /**
1458      * Returns the number of items in the list.
1459      *
1460      * @return an integer equal to the number of items in the list
1461      */
1462     @BeanProperty(bound = false)
1463     public int getItemCount() {
1464         return dataModel.getSize();
1465     }
1466 
1467     /**
1468      * Returns the list item at the specified index.  If <code>index</code>
1469      * is out of range (less than zero or greater than or equal to size)
1470      * it will return <code>null</code>.
1471      *
1472      * @param index  an integer indicating the list position, where the first
1473      *               item starts at zero
1474      * @return the item at that list position; or
1475      *                  <code>null</code> if out of range
1476      */
1477     public E getItemAt(int index) {
1478         return dataModel.getElementAt(index);
1479     }
1480 
1481     /**
1482      * Returns an instance of the default key-selection manager.


1591         ",isEditable=" + isEditableString +
1592         ",lightWeightPopupEnabled=" + lightWeightPopupEnabledString +
1593         ",maximumRowCount=" + maximumRowCount +
1594         ",selectedItemReminder=" + selectedItemReminderString;
1595     }
1596 
1597 
1598 ///////////////////
1599 // Accessibility support
1600 ///////////////////
1601 
1602     /**
1603      * Gets the AccessibleContext associated with this JComboBox.
1604      * For combo boxes, the AccessibleContext takes the form of an
1605      * AccessibleJComboBox.
1606      * A new AccessibleJComboBox instance is created if necessary.
1607      *
1608      * @return an AccessibleJComboBox that serves as the
1609      *         AccessibleContext of this JComboBox
1610      */
1611     @BeanProperty(bound = false)
1612     public AccessibleContext getAccessibleContext() {
1613         if ( accessibleContext == null ) {
1614             accessibleContext = new AccessibleJComboBox();
1615         }
1616         return accessibleContext;
1617     }
1618 
1619     /**
1620      * This class implements accessibility support for the
1621      * <code>JComboBox</code> class.  It provides an implementation of the
1622      * Java Accessibility API appropriate to Combo Box user-interface elements.
1623      * <p>
1624      * <strong>Warning:</strong>
1625      * Serialized objects of this class will not be compatible with
1626      * future Swing releases. The current serialization support is
1627      * appropriate for short term storage or RMI between applications running
1628      * the same version of Swing.  As of 1.4, support for long term storage
1629      * of all JavaBeans&trade;
1630      * has been added to the <code>java.beans</code> package.
1631      * Please see {@link java.beans.XMLEncoder}.


2094              * could be 'city.'
2095              *
2096              * @return the localized name of the object; null if this
2097              * object does not have a name
2098              *
2099              * @see #setAccessibleName
2100              */
2101             public String getAccessibleName() {
2102                 return ac.getAccessibleName();
2103             }
2104 
2105             /**
2106              * Sets the localized accessible name of this object.  Changing the
2107              * name will cause a PropertyChangeEvent to be fired for the
2108              * ACCESSIBLE_NAME_PROPERTY property.
2109              *
2110              * @param s the new localized name of the object.
2111              *
2112              * @see #getAccessibleName
2113              * @see #addPropertyChangeListener




2114              */
2115             @BeanProperty(preferred = true, description
2116                     = "Sets the accessible name for the component.")
2117             public void setAccessibleName(String s) {
2118                 ac.setAccessibleName(s);
2119             }
2120 
2121             /**
2122              * Gets the accessibleDescription property of this object.  The
2123              * accessibleDescription property of this object is a short localized
2124              * phrase describing the purpose of the object.  For example, in the
2125              * case of a 'Cancel' button, the accessibleDescription could be
2126              * 'Ignore changes and close dialog box.'
2127              *
2128              * @return the localized description of the object; null if
2129              * this object does not have a description
2130              *
2131              * @see #setAccessibleDescription
2132              */
2133             public String getAccessibleDescription() {
2134                 return ac.getAccessibleDescription();
2135             }
2136 
2137             /**
2138              * Sets the accessible description of this object.  Changing the
2139              * name will cause a PropertyChangeEvent to be fired for the
2140              * ACCESSIBLE_DESCRIPTION_PROPERTY property.
2141              *
2142              * @param s the new localized description of the object
2143              *
2144              * @see #setAccessibleName
2145              * @see #addPropertyChangeListener




2146              */
2147             @BeanProperty(preferred = true, description
2148                     = "Sets the accessible description for the component.")
2149             public void setAccessibleDescription(String s) {
2150                 ac.setAccessibleDescription(s);
2151             }
2152 
2153             /**
2154              * Gets the role of this object.  The role of the object is the generic
2155              * purpose or use of the class of this object.  For example, the role
2156              * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in
2157              * AccessibleRole are provided so component developers can pick from
2158              * a set of predefined roles.  This enables assistive technologies to
2159              * provide a consistent interface to various tweaked subclasses of
2160              * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
2161              * that act like a push button) as well as distinguish between subclasses
2162              * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
2163              * and AccessibleRole.RADIO_BUTTON for radio buttons).
2164              * <p>Note that the AccessibleRole class is also extensible, so
2165              * custom component developers can define their own AccessibleRole's
2166              * if the set of predefined roles is inadequate.
2167              *
2168              * @return an instance of AccessibleRole describing the role of the object