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