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 */
25package java.awt;
26
27import java.util.*;
28import java.awt.peer.ChoicePeer;
29import java.awt.event.*;
30import java.util.EventListener;
31import java.io.ObjectOutputStream;
32import java.io.ObjectInputStream;
33import java.io.IOException;
34
35import 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 */
73public 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}
834