1 /*
   2  * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package java.awt;
  26 
  27 import java.util.*;
  28 import java.awt.peer.ChoicePeer;
  29 import java.awt.event.*;
  30 import java.util.EventListener;
  31 import java.io.ObjectOutputStream;
  32 import java.io.ObjectInputStream;
  33 import java.io.IOException;
  34 
  35 import javax.accessibility.*;
  36 
  37 
  38 /**
  39  * The <code>Choice</code> class presents a pop-up menu of choices.
  40  * The current choice is displayed as the title of the menu.
  41  * <p>
  42  * The following code example produces a pop-up menu:
  43  * <p>
  44  * <hr><blockquote><pre>
  45  * Choice ColorChooser = new Choice();
  46  * ColorChooser.add("Green");
  47  * ColorChooser.add("Red");
  48  * ColorChooser.add("Blue");
  49  * </pre></blockquote><hr>
  50  * <p>
  51  * After this choice menu has been added to a panel,
  52  * it appears as follows in its normal state:
  53  * <p>
  54  * <img src="doc-files/Choice-1.gif" alt="The following text describes the graphic"
  55  * ALIGN=center HSPACE=10 VSPACE=7>
  56  * <p>
  57  * In the picture, <code>"Green"</code> is the current choice.
  58  * Pushing the mouse button down on the object causes a menu to
  59  * appear with the current choice highlighted.
  60  * <p>
  61  * Some native platforms do not support arbitrary resizing of
  62  * <code>Choice</code> components and the behavior of
  63  * <code>setSize()/getSize()</code> is bound by
  64  * such limitations.
  65  * Native GUI <code>Choice</code> components' size are often bound by such
  66  * attributes as font size and length of items contained within
  67  * the <code>Choice</code>.
  68  * <p>
  69  * @author      Sami Shaio
  70  * @author      Arthur van Hoff
  71  * @since       JDK1.0
  72  */
  73 public class Choice extends Component implements ItemSelectable, Accessible {
  74     /**
  75      * The items for the <code>Choice</code>.
  76      * This can be a <code>null</code> value.
  77      * @serial
  78      * @see #add(String)
  79      * @see #addItem(String)
  80      * @see #getItem(int)
  81      * @see #getItemCount()
  82      * @see #insert(String, int)
  83      * @see #remove(String)
  84      */
  85     Vector<String> pItems;
  86 
  87     /**
  88      * The index of the current choice for this <code>Choice</code>
  89      * or -1 if nothing is selected.
  90      * @serial
  91      * @see #getSelectedItem()
  92      * @see #select(int)
  93      */
  94     int selectedIndex = -1;
  95 
  96     transient ItemListener itemListener;
  97 
  98     private static final String base = "choice";
  99     private static int nameCounter = 0;
 100 
 101     /*
 102      * JDK 1.1 serialVersionUID
 103      */
 104     private static final long serialVersionUID = -4075310674757313071L;
 105 
 106     static {
 107         /* ensure that the necessary native libraries are loaded */
 108         Toolkit.loadLibraries();
 109         /* initialize JNI field and method ids */
 110         if (!GraphicsEnvironment.isHeadless()) {
 111             initIDs();
 112         }
 113     }
 114 
 115     /**
 116      * Creates a new choice menu. The menu initially has no items in it.
 117      * <p>
 118      * By default, the first item added to the choice menu becomes the
 119      * selected item, until a different selection is made by the user
 120      * by calling one of the <code>select</code> methods.
 121      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
 122      * returns true
 123      * @see       java.awt.GraphicsEnvironment#isHeadless
 124      * @see       #select(int)
 125      * @see       #select(java.lang.String)
 126      */
 127     public Choice() throws HeadlessException {
 128         GraphicsEnvironment.checkHeadless();
 129         pItems = new Vector<>();
 130     }
 131 
 132     /**
 133      * Constructs a name for this component.  Called by
 134      * <code>getName</code> when the name is <code>null</code>.
 135      */
 136     String constructComponentName() {
 137         synchronized (Choice.class) {
 138             return base + nameCounter++;
 139         }
 140     }
 141 
 142     /**
 143      * Creates the <code>Choice</code>'s peer.  This peer allows us
 144      * to change the look
 145      * of the <code>Choice</code> without changing its functionality.
 146      * @see     java.awt.Toolkit#createChoice(java.awt.Choice)
 147      * @see     java.awt.Component#getToolkit()
 148      */
 149     public void addNotify() {
 150         synchronized (getTreeLock()) {
 151             if (peer == null)
 152                 peer = getToolkit().createChoice(this);
 153             super.addNotify();
 154         }
 155     }
 156 
 157     /**
 158      * Returns the number of items in this <code>Choice</code> menu.
 159      * @return the number of items in this <code>Choice</code> menu
 160      * @see     #getItem
 161      * @since   JDK1.1
 162      */
 163     public int getItemCount() {
 164         return countItems();
 165     }
 166 
 167     /**
 168      * @deprecated As of JDK version 1.1,
 169      * replaced by <code>getItemCount()</code>.
 170      */
 171     @Deprecated
 172     public int countItems() {
 173         return pItems.size();
 174     }
 175 
 176     /**
 177      * Gets the string at the specified index in this
 178      * <code>Choice</code> menu.
 179      * @param      index the index at which to begin
 180      * @see        #getItemCount
 181      */
 182     public String getItem(int index) {
 183         return getItemImpl(index);
 184     }
 185 
 186     /*
 187      * This is called by the native code, so client code can't
 188      * be called on the toolkit thread.
 189      */
 190     final String getItemImpl(int index) {
 191         return pItems.elementAt(index);
 192     }
 193 
 194     /**
 195      * Adds an item to this <code>Choice</code> menu.
 196      * @param      item    the item to be added
 197      * @exception  NullPointerException   if the item's value is
 198      *                  <code>null</code>
 199      * @since      JDK1.1
 200      */
 201     public void add(String item) {
 202         addItem(item);
 203     }
 204 
 205     /**
 206      * Obsolete as of Java 2 platform v1.1.  Please use the
 207      * <code>add</code> method instead.
 208      * <p>
 209      * Adds an item to this <code>Choice</code> menu.
 210      * @param item the item to be added
 211      * @exception NullPointerException if the item's value is equal to
 212      *          <code>null</code>
 213      */
 214     public void addItem(String item) {
 215         synchronized (this) {
 216             insertNoInvalidate(item, pItems.size());
 217         }
 218 
 219         // This could change the preferred size of the Component.
 220         invalidateIfValid();
 221     }
 222 
 223     /**
 224      * Inserts an item to this <code>Choice</code>,
 225      * but does not invalidate the <code>Choice</code>.
 226      * Client methods must provide their own synchronization before
 227      * invoking this method.
 228      * @param item the item to be added
 229      * @param index the new item position
 230      * @exception NullPointerException if the item's value is equal to
 231      *          <code>null</code>
 232      */
 233     private void insertNoInvalidate(String item, int index) {
 234         if (item == null) {
 235             throw new
 236                 NullPointerException("cannot add null item to Choice");
 237         }
 238         pItems.insertElementAt(item, index);
 239         ChoicePeer peer = (ChoicePeer)this.peer;
 240         if (peer != null) {
 241             peer.add(item, index);
 242         }
 243         // no selection or selection shifted up
 244         if (selectedIndex < 0 || selectedIndex >= index) {
 245             select(0);
 246         }
 247     }
 248 
 249 
 250     /**
 251      * Inserts the item into this choice at the specified position.
 252      * Existing items at an index greater than or equal to
 253      * <code>index</code> are shifted up by one to accommodate
 254      * the new item.  If <code>index</code> is greater than or
 255      * equal to the number of items in this choice,
 256      * <code>item</code> is added to the end of this choice.
 257      * <p>
 258      * If the item is the first one being added to the choice,
 259      * then the item becomes selected.  Otherwise, if the
 260      * selected item was one of the items shifted, the first
 261      * item in the choice becomes the selected item.  If the
 262      * selected item was no among those shifted, it remains
 263      * the selected item.
 264      * @param item the non-<code>null</code> item to be inserted
 265      * @param index the position at which the item should be inserted
 266      * @exception IllegalArgumentException if index is less than 0
 267      */
 268     public void insert(String item, int index) {
 269         synchronized (this) {
 270             if (index < 0) {
 271                 throw new IllegalArgumentException("index less than zero.");
 272             }
 273             /* if the index greater than item count, add item to the end */
 274             index = Math.min(index, pItems.size());
 275 
 276             insertNoInvalidate(item, index);
 277         }
 278 
 279         // This could change the preferred size of the Component.
 280         invalidateIfValid();
 281     }
 282 
 283     /**
 284      * Removes the first occurrence of <code>item</code>
 285      * from the <code>Choice</code> menu.  If the item
 286      * being removed is the currently selected item,
 287      * then the first item in the choice becomes the
 288      * selected item.  Otherwise, the currently selected
 289      * item remains selected (and the selected index is
 290      * updated accordingly).
 291      * @param      item  the item to remove from this <code>Choice</code> menu
 292      * @exception  IllegalArgumentException  if the item doesn't
 293      *                     exist in the choice menu
 294      * @since      JDK1.1
 295      */
 296     public void remove(String item) {
 297         synchronized (this) {
 298             int index = pItems.indexOf(item);
 299             if (index < 0) {
 300                 throw new IllegalArgumentException("item " + item +
 301                                                    " not found in choice");
 302             } else {
 303                 removeNoInvalidate(index);
 304             }
 305         }
 306 
 307         // This could change the preferred size of the Component.
 308         invalidateIfValid();
 309     }
 310 
 311     /**
 312      * Removes an item from the choice menu
 313      * at the specified position.  If the item
 314      * being removed is the currently selected item,
 315      * then the first item in the choice becomes the
 316      * selected item.  Otherwise, the currently selected
 317      * item remains selected (and the selected index is
 318      * updated accordingly).
 319      * @param      position the position of the item
 320      * @throws IndexOutOfBoundsException if the specified
 321      *          position is out of bounds
 322      * @since      JDK1.1
 323      */
 324     public void remove(int position) {
 325         synchronized (this) {
 326             removeNoInvalidate(position);
 327         }
 328 
 329         // This could change the preferred size of the Component.
 330         invalidateIfValid();
 331     }
 332 
 333     /**
 334      * Removes an item from the <code>Choice</code> at the
 335      * specified position, but does not invalidate the <code>Choice</code>.
 336      * Client methods must provide their
 337      * own synchronization before invoking this method.
 338      * @param      position   the position of the item
 339      */
 340     private void removeNoInvalidate(int position) {
 341         pItems.removeElementAt(position);
 342         ChoicePeer peer = (ChoicePeer)this.peer;
 343         if (peer != null) {
 344             peer.remove(position);
 345         }
 346         /* Adjust selectedIndex if selected item was removed. */
 347         if (pItems.size() == 0) {
 348             selectedIndex = -1;
 349         } else if (selectedIndex == position) {
 350             select(0);
 351         } else if (selectedIndex > position) {
 352             select(selectedIndex-1);
 353         }
 354     }
 355 
 356 
 357     /**
 358      * Removes all items from the choice menu.
 359      * @see       #remove
 360      * @since     JDK1.1
 361      */
 362     public void removeAll() {
 363         synchronized (this) {
 364             if (peer != null) {
 365                 ((ChoicePeer)peer).removeAll();
 366             }
 367             pItems.removeAllElements();
 368             selectedIndex = -1;
 369         }
 370 
 371         // This could change the preferred size of the Component.
 372         invalidateIfValid();
 373     }
 374 
 375     /**
 376      * Gets a representation of the current choice as a string.
 377      * @return    a string representation of the currently
 378      *                     selected item in this choice menu
 379      * @see       #getSelectedIndex
 380      */
 381     public synchronized String getSelectedItem() {
 382         return (selectedIndex >= 0) ? getItem(selectedIndex) : null;
 383     }
 384 
 385     /**
 386      * Returns an array (length 1) containing the currently selected
 387      * item.  If this choice has no items, returns <code>null</code>.
 388      * @see ItemSelectable
 389      */
 390     public synchronized Object[] getSelectedObjects() {
 391         if (selectedIndex >= 0) {
 392             Object[] items = new Object[1];
 393             items[0] = getItem(selectedIndex);
 394             return items;
 395         }
 396         return null;
 397     }
 398 
 399     /**
 400      * Returns the index of the currently selected item.
 401      * If nothing is selected, returns -1.
 402      *
 403      * @return the index of the currently selected item, or -1 if nothing
 404      *  is currently selected
 405      * @see #getSelectedItem
 406      */
 407     public int getSelectedIndex() {
 408         return selectedIndex;
 409     }
 410 
 411     /**
 412      * Sets the selected item in this <code>Choice</code> menu to be the
 413      * item at the specified position.
 414      *
 415      * <p>Note that this method should be primarily used to
 416      * initially select an item in this component.
 417      * Programmatically calling this method will <i>not</i> trigger
 418      * an <code>ItemEvent</code>.  The only way to trigger an
 419      * <code>ItemEvent</code> is by user interaction.
 420      *
 421      * @param      pos      the positon of the selected item
 422      * @exception  IllegalArgumentException if the specified
 423      *                            position is greater than the
 424      *                            number of items or less than zero
 425      * @see        #getSelectedItem
 426      * @see        #getSelectedIndex
 427      */
 428     public synchronized void select(int pos) {
 429         if ((pos >= pItems.size()) || (pos < 0)) {
 430             throw new IllegalArgumentException("illegal Choice item position: " + pos);
 431         }
 432         if (pItems.size() > 0) {
 433             selectedIndex = pos;
 434             ChoicePeer peer = (ChoicePeer)this.peer;
 435             if (peer != null) {
 436                 peer.select(pos);
 437             }
 438         }
 439     }
 440 
 441     /**
 442      * Sets the selected item in this <code>Choice</code> menu
 443      * to be the item whose name is equal to the specified string.
 444      * If more than one item matches (is equal to) the specified string,
 445      * the one with the smallest index is selected.
 446      *
 447      * <p>Note that this method should be primarily used to
 448      * initially select an item in this component.
 449      * Programmatically calling this method will <i>not</i> trigger
 450      * an <code>ItemEvent</code>.  The only way to trigger an
 451      * <code>ItemEvent</code> is by user interaction.
 452      *
 453      * @param       str     the specified string
 454      * @see         #getSelectedItem
 455      * @see         #getSelectedIndex
 456      */
 457     public synchronized void select(String str) {
 458         int index = pItems.indexOf(str);
 459         if (index >= 0) {
 460             select(index);
 461         }
 462     }
 463 
 464     /**
 465      * Adds the specified item listener to receive item events from
 466      * this <code>Choice</code> menu.  Item events are sent in response
 467      * to user input, but not in response to calls to <code>select</code>.
 468      * If l is <code>null</code>, no exception is thrown and no action
 469      * is performed.
 470      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
 471      * >AWT Threading Issues</a> for details on AWT's threading model.
 472      * @param         l    the item listener
 473      * @see           #removeItemListener
 474      * @see           #getItemListeners
 475      * @see           #select
 476      * @see           java.awt.event.ItemEvent
 477      * @see           java.awt.event.ItemListener
 478      * @since         JDK1.1
 479      */
 480     public synchronized void addItemListener(ItemListener l) {
 481         if (l == null) {
 482            return;
 483         }
 484         itemListener = AWTEventMulticaster.add(itemListener, l);
 485         newEventsOnly = true;
 486     }
 487 
 488     /**
 489      * Removes the specified item listener so that it no longer receives
 490      * item events from this <code>Choice</code> menu.
 491      * If l is <code>null</code>, no exception is thrown and no
 492      * action is performed.
 493      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
 494      * >AWT Threading Issues</a> for details on AWT's threading model.
 495      * @param         l    the item listener
 496      * @see           #addItemListener
 497      * @see           #getItemListeners
 498      * @see           java.awt.event.ItemEvent
 499      * @see           java.awt.event.ItemListener
 500      * @since         JDK1.1
 501      */
 502     public synchronized void removeItemListener(ItemListener l) {
 503         if (l == null) {
 504             return;
 505         }
 506         itemListener = AWTEventMulticaster.remove(itemListener, l);
 507     }
 508 
 509     /**
 510      * Returns an array of all the item listeners
 511      * registered on this choice.
 512      *
 513      * @return all of this choice's <code>ItemListener</code>s
 514      *         or an empty array if no item
 515      *         listeners are currently registered
 516      *
 517      * @see           #addItemListener
 518      * @see           #removeItemListener
 519      * @see           java.awt.event.ItemEvent
 520      * @see           java.awt.event.ItemListener
 521      * @since 1.4
 522      */
 523     public synchronized ItemListener[] getItemListeners() {
 524         return getListeners(ItemListener.class);
 525     }
 526 
 527     /**
 528      * Returns an array of all the objects currently registered
 529      * as <code><em>Foo</em>Listener</code>s
 530      * upon this <code>Choice</code>.
 531      * <code><em>Foo</em>Listener</code>s are registered using the
 532      * <code>add<em>Foo</em>Listener</code> method.
 533      *
 534      * <p>
 535      * You can specify the <code>listenerType</code> argument
 536      * with a class literal, such as
 537      * <code><em>Foo</em>Listener.class</code>.
 538      * For example, you can query a
 539      * <code>Choice</code> <code>c</code>
 540      * for its item listeners with the following code:
 541      *
 542      * <pre>ItemListener[] ils = (ItemListener[])(c.getListeners(ItemListener.class));</pre>
 543      *
 544      * If no such listeners exist, this method returns an empty array.
 545      *
 546      * @param listenerType the type of listeners requested; this parameter
 547      *          should specify an interface that descends from
 548      *          <code>java.util.EventListener</code>
 549      * @return an array of all objects registered as
 550      *          <code><em>Foo</em>Listener</code>s on this choice,
 551      *          or an empty array if no such
 552      *          listeners have been added
 553      * @exception ClassCastException if <code>listenerType</code>
 554      *          doesn't specify a class or interface that implements
 555      *          <code>java.util.EventListener</code>
 556      *
 557      * @see #getItemListeners
 558      * @since 1.3
 559      */
 560     public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
 561         EventListener l = null;
 562         if  (listenerType == ItemListener.class) {
 563             l = itemListener;
 564         } else {
 565             return super.getListeners(listenerType);
 566         }
 567         return AWTEventMulticaster.getListeners(l, listenerType);
 568     }
 569 
 570     // REMIND: remove when filtering is done at lower level
 571     boolean eventEnabled(AWTEvent e) {
 572         if (e.id == ItemEvent.ITEM_STATE_CHANGED) {
 573             if ((eventMask & AWTEvent.ITEM_EVENT_MASK) != 0 ||
 574                 itemListener != null) {
 575                 return true;
 576             }
 577             return false;
 578         }
 579         return super.eventEnabled(e);
 580     }
 581 
 582     /**
 583      * Processes events on this choice. If the event is an
 584      * instance of <code>ItemEvent</code>, it invokes the
 585      * <code>processItemEvent</code> method. Otherwise, it calls its
 586      * superclass's <code>processEvent</code> method.
 587      * <p>Note that if the event parameter is <code>null</code>
 588      * the behavior is unspecified and may result in an
 589      * exception.
 590      *
 591      * @param      e the event
 592      * @see        java.awt.event.ItemEvent
 593      * @see        #processItemEvent
 594      * @since      JDK1.1
 595      */
 596     protected void processEvent(AWTEvent e) {
 597         if (e instanceof ItemEvent) {
 598             processItemEvent((ItemEvent)e);
 599             return;
 600         }
 601         super.processEvent(e);
 602     }
 603 
 604     /**
 605      * Processes item events occurring on this <code>Choice</code>
 606      * menu by dispatching them to any registered
 607      * <code>ItemListener</code> objects.
 608      * <p>
 609      * This method is not called unless item events are
 610      * enabled for this component. Item events are enabled
 611      * when one of the following occurs:
 612      * <p><ul>
 613      * <li>An <code>ItemListener</code> object is registered
 614      * via <code>addItemListener</code>.
 615      * <li>Item events are enabled via <code>enableEvents</code>.
 616      * </ul>
 617      * <p>Note that if the event parameter is <code>null</code>
 618      * the behavior is unspecified and may result in an
 619      * exception.
 620      *
 621      * @param       e the item event
 622      * @see         java.awt.event.ItemEvent
 623      * @see         java.awt.event.ItemListener
 624      * @see         #addItemListener(ItemListener)
 625      * @see         java.awt.Component#enableEvents
 626      * @since       JDK1.1
 627      */
 628     protected void processItemEvent(ItemEvent e) {
 629         ItemListener listener = itemListener;
 630         if (listener != null) {
 631             listener.itemStateChanged(e);
 632         }
 633     }
 634 
 635     /**
 636      * Returns a string representing the state of this <code>Choice</code>
 637      * menu. This method is intended to be used only for debugging purposes,
 638      * and the content and format of the returned string may vary between
 639      * implementations. The returned string may be empty but may not be
 640      * <code>null</code>.
 641      *
 642      * @return    the parameter string of this <code>Choice</code> menu
 643      */
 644     protected String paramString() {
 645         return super.paramString() + ",current=" + getSelectedItem();
 646     }
 647 
 648 
 649     /* Serialization support.
 650      */
 651 
 652     /*
 653      * Choice Serial Data Version.
 654      * @serial
 655      */
 656     private int choiceSerializedDataVersion = 1;
 657 
 658     /**
 659      * Writes default serializable fields to stream.  Writes
 660      * a list of serializable <code>ItemListeners</code>
 661      * as optional data. The non-serializable
 662      * <code>ItemListeners</code> are detected and
 663      * no attempt is made to serialize them.
 664      *
 665      * @param s the <code>ObjectOutputStream</code> to write
 666      * @serialData <code>null</code> terminated sequence of 0
 667      *   or more pairs; the pair consists of a <code>String</code>
 668      *   and an <code>Object</code>; the <code>String</code> indicates
 669      *   the type of object and is one of the following:
 670      *   <code>itemListenerK</code> indicating an
 671      *     <code>ItemListener</code> object
 672      *
 673      * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
 674      * @see java.awt.Component#itemListenerK
 675      * @see #readObject(ObjectInputStream)
 676      */
 677     private void writeObject(ObjectOutputStream s)
 678       throws java.io.IOException
 679     {
 680       s.defaultWriteObject();
 681 
 682       AWTEventMulticaster.save(s, itemListenerK, itemListener);
 683       s.writeObject(null);
 684     }
 685 
 686     /**
 687      * Reads the <code>ObjectInputStream</code> and if it
 688      * isn't <code>null</code> adds a listener to receive
 689      * item events fired by the <code>Choice</code> item.
 690      * Unrecognized keys or values will be ignored.
 691      *
 692      * @param s the <code>ObjectInputStream</code> to read
 693      * @exception HeadlessException if
 694      *   <code>GraphicsEnvironment.isHeadless</code> returns
 695      *   <code>true</code>
 696      * @serial
 697      * @see #removeItemListener(ItemListener)
 698      * @see #addItemListener(ItemListener)
 699      * @see java.awt.GraphicsEnvironment#isHeadless
 700      * @see #writeObject(ObjectOutputStream)
 701      */
 702     private void readObject(ObjectInputStream s)
 703       throws ClassNotFoundException, IOException, HeadlessException
 704     {
 705       GraphicsEnvironment.checkHeadless();
 706       s.defaultReadObject();
 707 
 708       Object keyOrNull;
 709       while(null != (keyOrNull = s.readObject())) {
 710         String key = ((String)keyOrNull).intern();
 711 
 712         if (itemListenerK == key)
 713           addItemListener((ItemListener)(s.readObject()));
 714 
 715         else // skip value for unrecognized key
 716           s.readObject();
 717       }
 718     }
 719 
 720     /**
 721      * Initialize JNI field and method IDs
 722      */
 723     private static native void initIDs();
 724 
 725 /////////////////
 726 // Accessibility support
 727 ////////////////
 728 
 729 
 730     /**
 731      * Gets the <code>AccessibleContext</code> associated with this
 732      * <code>Choice</code>. For <code>Choice</code> components,
 733      * the <code>AccessibleContext</code> takes the form of an
 734      * <code>AccessibleAWTChoice</code>. A new <code>AccessibleAWTChoice</code>
 735      * instance is created if necessary.
 736      *
 737      * @return an <code>AccessibleAWTChoice</code> that serves as the
 738      *         <code>AccessibleContext</code> of this <code>Choice</code>
 739      * @since 1.3
 740      */
 741     public AccessibleContext getAccessibleContext() {
 742         if (accessibleContext == null) {
 743             accessibleContext = new AccessibleAWTChoice();
 744         }
 745         return accessibleContext;
 746     }
 747 
 748     /**
 749      * This class implements accessibility support for the
 750      * <code>Choice</code> class.  It provides an implementation of the
 751      * Java Accessibility API appropriate to choice user-interface elements.
 752      * @since 1.3
 753      */
 754     protected class AccessibleAWTChoice extends AccessibleAWTComponent
 755         implements AccessibleAction
 756     {
 757         /*
 758          * JDK 1.3 serialVersionUID
 759          */
 760         private static final long serialVersionUID = 7175603582428509322L;
 761 
 762         public AccessibleAWTChoice() {
 763             super();
 764         }
 765 
 766         /**
 767          * Get the AccessibleAction associated with this object.  In the
 768          * implementation of the Java Accessibility API for this class,
 769          * return this object, which is responsible for implementing the
 770          * AccessibleAction interface on behalf of itself.
 771          *
 772          * @return this object
 773          * @see AccessibleAction
 774          */
 775         public AccessibleAction getAccessibleAction() {
 776             return this;
 777         }
 778 
 779         /**
 780          * Get the role of this object.
 781          *
 782          * @return an instance of AccessibleRole describing the role of the
 783          * object
 784          * @see AccessibleRole
 785          */
 786         public AccessibleRole getAccessibleRole() {
 787             return AccessibleRole.COMBO_BOX;
 788         }
 789 
 790         /**
 791          * Returns the number of accessible actions available in this object
 792          * If there are more than one, the first one is considered the "default"
 793          * action of the object.
 794          *
 795          * @return the zero-based number of Actions in this object
 796          */
 797         public int getAccessibleActionCount() {
 798             return 0;  //  To be fully implemented in a future release
 799         }
 800 
 801         /**
 802          * Returns a description of the specified action of the object.
 803          *
 804          * @param i zero-based index of the actions
 805          * @return a String description of the action
 806          * @see #getAccessibleActionCount
 807          */
 808         public String getAccessibleActionDescription(int i) {
 809             return null;  //  To be fully implemented in a future release
 810         }
 811 
 812         /**
 813          * Perform the specified Action on the object
 814          *
 815          * @param i zero-based index of actions
 816          * @return true if the action was performed; otherwise false.
 817          * @see #getAccessibleActionCount
 818          */
 819         public boolean doAccessibleAction(int i) {
 820             return false;  //  To be fully implemented in a future release
 821         }
 822 
 823     } // inner class AccessibleAWTChoice
 824 
 825 }