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