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