1 /* Choice.java -- Java choice button widget.
2    Copyright (C) 1999, 2000, 2001, 2002, 2004, 2006 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package java.awt;
40 
41 import java.awt.event.ItemEvent;
42 import java.awt.event.ItemListener;
43 import java.awt.peer.ChoicePeer;
44 import java.io.Serializable;
45 import java.util.EventListener;
46 import java.util.Vector;
47 
48 import javax.accessibility.Accessible;
49 import javax.accessibility.AccessibleAction;
50 import javax.accessibility.AccessibleContext;
51 import javax.accessibility.AccessibleRole;
52 
53 /**
54  * This class implements a drop down choice list.
55  *
56  * @author Aaron M. Renn (arenn@urbanophile.com)
57  */
58 public class Choice extends Component
59   implements ItemSelectable, Serializable, Accessible
60 {
61   /**
62    * The number used to generate the name returned by getName.
63    */
64   private static transient long next_choice_number;
65 
66   // Serialization constant
67   private static final long serialVersionUID = -4075310674757313071L;
68 
69   /**
70    * @serial A list of items for the choice box, which can be <code>null</code>.
71    * This is package-private to avoid an accessor method.
72    */
73   Vector pItems = new Vector();
74 
75   /**
76    * @serial The index of the selected item in the choice box.
77    */
78   private int selectedIndex = -1;
79 
80   /**
81    * ItemListener chain
82    */
83   private ItemListener item_listeners;
84 
85   /**
86    * This class provides accessibility support for the
87    * combo box.
88    *
89    * @author Jerry Quinn  (jlquinn@optonline.net)
90    * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
91    */
92   protected class AccessibleAWTChoice
93     extends AccessibleAWTComponent
94     implements AccessibleAction
95   {
96 
97     /**
98      * Serialization constant to match JDK 1.5
99      */
100     private static final long serialVersionUID = 7175603582428509322L;
101 
102     /**
103      * Default constructor which simply calls the
104      * super class for generic component accessibility
105      * handling.
106      */
AccessibleAWTChoice()107     public AccessibleAWTChoice()
108     {
109       super();
110     }
111 
112     /**
113      * Returns an implementation of the <code>AccessibleAction</code>
114      * interface for this accessible object.  In this case, the
115      * current instance is simply returned (with a more appropriate
116      * type), as it also implements the accessible action as well as
117      * the context.
118      *
119      * @return the accessible action associated with this context.
120      * @see javax.accessibility.AccessibleAction
121      */
getAccessibleAction()122     public AccessibleAction getAccessibleAction()
123     {
124       return this;
125     }
126 
127     /**
128      * Returns the role of this accessible object.
129      *
130      * @return the instance of <code>AccessibleRole</code>,
131      *         which describes this object.
132      * @see javax.accessibility.AccessibleRole
133      */
getAccessibleRole()134     public AccessibleRole getAccessibleRole()
135     {
136       return AccessibleRole.COMBO_BOX;
137     }
138 
139     /**
140      * Returns the number of actions associated with this accessible
141      * object.  In this case, it is the number of choices available.
142      *
143      * @return the number of choices available.
144      * @see javax.accessibility.AccessibleAction#getAccessibleActionCount()
145      */
getAccessibleActionCount()146     public int getAccessibleActionCount()
147     {
148       return pItems.size();
149     }
150 
151     /**
152      * Returns a description of the action with the supplied id.
153      * In this case, it is the text used in displaying the particular
154      * choice on-screen.
155      *
156      * @param i the id of the choice whose description should be
157      *          retrieved.
158      * @return the <code>String</code> used to describe the choice.
159      * @see javax.accessibility.AccessibleAction#getAccessibleActionDescription(int)
160      */
getAccessibleActionDescription(int i)161     public String getAccessibleActionDescription(int i)
162     {
163       return (String) pItems.get(i);
164     }
165 
166     /**
167      * Executes the action with the specified id.  In this case,
168      * calling this method provides the same behaviour as would
169      * choosing a choice from the list in a visual manner.
170      *
171      * @param i the id of the choice to select.
172      * @return true if a valid choice was specified.
173      * @see javax.accessibility.AccessibleAction#doAccessibleAction(int)
174      */
doAccessibleAction(int i)175     public boolean doAccessibleAction(int i)
176     {
177       if (i < 0 || i >= pItems.size())
178         return false;
179 
180       Choice.this.select( i );
181 
182       return true;
183     }
184   }
185 
186   /**
187    * Initializes a new instance of <code>Choice</code>.
188    *
189    * @exception HeadlessException If GraphicsEnvironment.isHeadless()
190    * returns true
191    */
Choice()192   public Choice()
193   {
194     if (GraphicsEnvironment.isHeadless())
195       throw new HeadlessException ();
196   }
197 
198   /**
199    * Returns the number of items in the list.
200    *
201    * @return The number of items in the list.
202    */
getItemCount()203   public int getItemCount()
204   {
205     return countItems ();
206   }
207 
208   /**
209    * Returns the number of items in the list.
210    *
211    * @return The number of items in the list.
212    *
213    * @deprecated This method is deprecated in favor of <code>getItemCount</code>.
214    */
countItems()215   public int countItems()
216   {
217     return pItems.size();
218   }
219 
220   /**
221    * Returns the item at the specified index in the list.
222    *
223    * @param index The index into the list to return the item from.
224    *
225    * @exception ArrayIndexOutOfBoundsException If the index is invalid.
226    */
getItem(int index)227   public String getItem(int index)
228   {
229     return (String)pItems.elementAt(index);
230   }
231 
232   /**
233    * Adds the specified item to this choice box.
234    *
235    * @param item The item to add.
236    *
237    * @exception NullPointerException If the item's value is null
238    *
239    * @since 1.1
240    */
add(String item)241   public synchronized void add(String item)
242   {
243     if (item == null)
244       throw new NullPointerException ("item must be non-null");
245 
246     pItems.addElement(item);
247 
248     if (peer != null)
249       ((ChoicePeer) peer).add(item, getItemCount() - 1);
250 
251     if (selectedIndex == -1)
252       select( 0 );
253   }
254 
255   /**
256    * Adds the specified item to this choice box.
257    *
258    * This method is oboslete since Java 2 platform 1.1. Please use
259    * {@link #add(String)} instead.
260    *
261    * @param item The item to add.
262    *
263    * @exception NullPointerException If the item's value is equal to null
264    */
addItem(String item)265   public synchronized void addItem(String item)
266   {
267     add(item);
268   }
269 
270   /** Inserts an item into this Choice.  Existing items are shifted
271    * upwards.  If the new item is the only item, then it is selected.
272    * If the currently selected item is shifted, then the first item is
273    * selected.  If the currently selected item is not shifted, then it
274    * remains selected.
275    *
276    * @param item The item to add.
277    * @param index The index at which the item should be inserted.
278    *
279    * @exception IllegalArgumentException If index is less than 0
280    */
insert(String item, int index)281   public synchronized void insert(String item, int index)
282   {
283     if (index < 0)
284       throw new IllegalArgumentException ("index may not be less then 0");
285 
286     if (index > getItemCount ())
287       index = getItemCount ();
288 
289     pItems.insertElementAt(item, index);
290 
291     if (peer != null)
292       ((ChoicePeer) peer).add (item, index);
293 
294     if (selectedIndex == -1 || selectedIndex >= index)
295       select(0);
296   }
297 
298   /**
299    * Removes the specified item from the choice box.
300    *
301    * @param item The item to remove.
302    *
303    * @exception IllegalArgumentException If the specified item doesn't exist.
304    */
remove(String item)305   public synchronized void remove(String item)
306   {
307     int index = pItems.indexOf(item);
308     if (index == -1)
309       throw new IllegalArgumentException ("item \""
310                                           + item + "\" not found in Choice");
311     remove(index);
312   }
313 
314   /**
315    * Removes the item at the specified index from the choice box.
316    *
317    * @param index The index of the item to remove.
318    *
319    * @exception IndexOutOfBoundsException If the index is not valid.
320    */
remove(int index)321   public synchronized void remove(int index)
322   {
323     pItems.removeElementAt(index);
324 
325     if (peer != null)
326       ((ChoicePeer) peer).remove( index );
327 
328     if( getItemCount() == 0 )
329       selectedIndex = -1;
330     else
331       {
332         if( selectedIndex > index )
333           selectedIndex--;
334         else if( selectedIndex == index )
335           selectedIndex = 0;
336 
337         if( peer != null )
338           ((ChoicePeer)peer).select( selectedIndex );
339       }
340   }
341 
342   /**
343    * Removes all of the objects from this choice box.
344    */
removeAll()345   public synchronized void removeAll()
346   {
347     if (getItemCount() <= 0)
348       return;
349 
350     pItems.removeAllElements ();
351 
352     if (peer != null)
353       {
354         ChoicePeer cp = (ChoicePeer) peer;
355         cp.removeAll ();
356       }
357 
358     selectedIndex = -1;
359   }
360 
361   /**
362    * Returns the currently selected item, or null if no item is
363    * selected.
364    *
365    * @return The currently selected item.
366    */
getSelectedItem()367   public synchronized String getSelectedItem()
368   {
369     return (selectedIndex == -1
370             ? null
371             : ((String)pItems.elementAt(selectedIndex)));
372   }
373 
374   /**
375    * Returns an array with one row containing the selected item.
376    *
377    * @return An array containing the selected item.
378    */
getSelectedObjects()379   public synchronized Object[] getSelectedObjects()
380   {
381     if (selectedIndex == -1)
382       return null;
383 
384     Object[] objs = new Object[1];
385     objs[0] = pItems.elementAt(selectedIndex);
386 
387     return objs;
388   }
389 
390   /**
391    * Returns the index of the selected item.
392    *
393    * @return The index of the selected item.
394    */
getSelectedIndex()395   public int getSelectedIndex()
396   {
397     return selectedIndex;
398   }
399 
400   /**
401    * Forces the item at the specified index to be selected.
402    *
403    * @param index The index of the row to make selected.
404    *
405    * @exception IllegalArgumentException If the specified index is invalid.
406    */
select(int index)407   public synchronized void select(int index)
408   {
409     if ((index < 0) || (index >= getItemCount()))
410       throw new IllegalArgumentException("Bad index: " + index);
411 
412     if( selectedIndex == index )
413       return;
414 
415     selectedIndex = index;
416     if( peer != null )
417       ((ChoicePeer)peer).select( index );
418   }
419 
420   /**
421    * Forces the named item to be selected.
422    *
423    * @param item The item to be selected.
424    *
425    * @exception IllegalArgumentException If the specified item does not exist.
426    */
select(String item)427   public synchronized void select(String item)
428   {
429     int index = pItems.indexOf(item);
430     if( index >= 0 )
431       select( index );
432   }
433 
434   /**
435    * Creates the native peer for this object.
436    */
addNotify()437   public void addNotify()
438   {
439     if (peer == null)
440       peer = getToolkit ().createChoice (this);
441     super.addNotify ();
442   }
443 
444   /**
445    * Adds the specified listener to the list of registered listeners for
446    * this object.
447    *
448    * @param listener The listener to add.
449    */
addItemListener(ItemListener listener)450   public synchronized void addItemListener(ItemListener listener)
451   {
452     item_listeners = AWTEventMulticaster.add(item_listeners, listener);
453   }
454 
455   /**
456    * Removes the specified listener from the list of registered listeners for
457    * this object.
458    *
459    * @param listener The listener to remove.
460    */
removeItemListener(ItemListener listener)461   public synchronized void removeItemListener(ItemListener listener)
462   {
463     item_listeners = AWTEventMulticaster.remove(item_listeners, listener);
464   }
465 
466   /**
467    * Processes this event by invoking <code>processItemEvent()</code> if the
468    * event is an instance of <code>ItemEvent</code>, otherwise the event
469    * is passed to the superclass.
470    *
471    * @param event The event to process.
472    */
processEvent(AWTEvent event)473   protected void processEvent(AWTEvent event)
474   {
475     if (event instanceof ItemEvent)
476       processItemEvent((ItemEvent)event);
477     else
478       super.processEvent(event);
479   }
480 
dispatchEventImpl(AWTEvent e)481   void dispatchEventImpl(AWTEvent e)
482   {
483     super.dispatchEventImpl(e);
484 
485     if( e.id <= ItemEvent.ITEM_LAST && e.id >= ItemEvent.ITEM_FIRST &&
486         ( item_listeners != null ||
487           ( eventMask & AWTEvent.ITEM_EVENT_MASK ) != 0 ) )
488       processEvent(e);
489   }
490 
491   /**
492    * Processes item event by dispatching to any registered listeners.
493    *
494    * @param event The event to process.
495    */
processItemEvent(ItemEvent event)496   protected void processItemEvent(ItemEvent event)
497   {
498     int index = pItems.indexOf((String) event.getItem());
499     if (item_listeners != null)
500       item_listeners.itemStateChanged(event);
501   }
502 
503   /**
504    * Returns a debugging string for this object.
505    *
506    * @return A debugging string for this object.
507    */
paramString()508   protected String paramString()
509   {
510     return "selectedIndex=" + selectedIndex + "," + super.paramString();
511   }
512 
513   /**
514    * Returns an array of all the objects currently registered as FooListeners
515    * upon this Choice. FooListeners are registered using the addFooListener
516    * method.
517    *
518    * @exception ClassCastException If listenerType doesn't specify a class or
519    * interface that implements java.util.EventListener.
520    *
521    * @since 1.3
522    */
getListeners(Class<T> listenerType)523   public <T extends EventListener> T[] getListeners (Class<T> listenerType)
524   {
525     if (listenerType == ItemListener.class)
526       return AWTEventMulticaster.getListeners (item_listeners, listenerType);
527 
528     return super.getListeners (listenerType);
529   }
530 
531   /**
532    * Returns all registered item listeners.
533    *
534    * @since 1.4
535    */
getItemListeners()536   public ItemListener[] getItemListeners ()
537   {
538     return (ItemListener[]) getListeners (ItemListener.class);
539   }
540 
541   /**
542    * Gets the AccessibleContext associated with this <code>Choice</code>.
543    * The context is created, if necessary.
544    *
545    * @return the associated context
546    */
getAccessibleContext()547   public AccessibleContext getAccessibleContext()
548   {
549     /* Create the context if this is the first request */
550     if (accessibleContext == null)
551       accessibleContext = new AccessibleAWTChoice();
552     return accessibleContext;
553   }
554 
555   /**
556    * Generate a unique name for this <code>Choice</code>.
557    *
558    * @return A unique name for this <code>Choice</code>.
559    */
generateName()560   String generateName()
561   {
562     return "choice" + getUniqueLong();
563   }
564 
getUniqueLong()565   private static synchronized long getUniqueLong()
566   {
567     return next_choice_number++;
568   }
569 } // class Choice
570