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