Home » openjdk-7 » javax » swing » [javadoc | source]

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

Home » openjdk-7 » javax » swing » [javadoc | source]