Source for java.awt.Choice

   1: /* Choice.java -- Java choice button widget.
   2:    Copyright (C) 1999, 2000, 2001, 2002, 2004 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: /*
  63:  * Static Variables
  64:  */
  65: 
  66: /**
  67:  * The number used to generate the name returned by getName.
  68:  */
  69: private static transient long next_choice_number;
  70: 
  71: // Serialization constant
  72: private static final long serialVersionUID = -4075310674757313071L;
  73: 
  74: /*************************************************************************/
  75: 
  76: /*
  77:  * Instance Variables
  78:  */
  79: 
  80: /**
  81:   * @serial A list of items for the choice box, which can be <code>null</code>.
  82:   * This is package-private to avoid an accessor method.
  83:   */
  84: Vector pItems = new Vector();
  85: 
  86: /**
  87:   * @serial The index of the selected item in the choice box.
  88:   */
  89: private int selectedIndex = -1;
  90: 
  91: // Listener chain
  92: private ItemListener item_listeners;
  93: 
  94: /**
  95:  * This class provides accessibility support for the
  96:  * combo box.
  97:  *
  98:  * @author Jerry Quinn  (jlquinn@optonline.net)
  99:  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 100:  */
 101:   protected class AccessibleAWTChoice
 102:   extends AccessibleAWTComponent
 103:   implements AccessibleAction
 104:   {
 105: 
 106:     /**
 107:      * Serialization constant to match JDK 1.5
 108:      */
 109:     private static final long serialVersionUID = 7175603582428509322L;
 110: 
 111:     /**
 112:      * Default constructor which simply calls the
 113:      * super class for generic component accessibility
 114:      * handling.
 115:      */
 116:     public AccessibleAWTChoice()
 117:     {
 118:       super();
 119:     }
 120: 
 121:     /**
 122:      * Returns an implementation of the <code>AccessibleAction</code>
 123:      * interface for this accessible object.  In this case, the
 124:      * current instance is simply returned (with a more appropriate
 125:      * type), as it also implements the accessible action as well as
 126:      * the context.
 127:      *
 128:      * @return the accessible action associated with this context.
 129:      * @see javax.accessibility.AccessibleAction
 130:      */
 131:     public AccessibleAction getAccessibleAction()
 132:     {
 133:       return this;
 134:     }
 135: 
 136:     /**
 137:      * Returns the role of this accessible object.
 138:      *
 139:      * @return the instance of <code>AccessibleRole</code>,
 140:      *         which describes this object.
 141:      * @see javax.accessibility.AccessibleRole
 142:      */
 143:     public AccessibleRole getAccessibleRole()
 144:     {
 145:       return AccessibleRole.COMBO_BOX;
 146:     }
 147:       
 148:     /**
 149:      * Returns the number of actions associated with this accessible
 150:      * object.  In this case, it is the number of choices available.
 151:      *
 152:      * @return the number of choices available.
 153:      * @see javax.accessibility.AccessibleAction#getAccessibleActionCount()
 154:      */
 155:     public int getAccessibleActionCount()
 156:     {
 157:       return pItems.size();
 158:     }
 159: 
 160:     /**
 161:      * Returns a description of the action with the supplied id.
 162:      * In this case, it is the text used in displaying the particular
 163:      * choice on-screen.
 164:      *
 165:      * @param i the id of the choice whose description should be
 166:      *          retrieved.
 167:      * @return the <code>String</code> used to describe the choice.
 168:      * @see javax.accessibility.AccessibleAction#getAccessibleActionDescription(int)
 169:      */
 170:     public String getAccessibleActionDescription(int i)
 171:     {
 172:       return (String) pItems.get(i);
 173:     }
 174:       
 175:     /**
 176:      * Executes the action with the specified id.  In this case,
 177:      * calling this method provides the same behaviour as would
 178:      * choosing a choice from the list in a visual manner.
 179:      *
 180:      * @param i the id of the choice to select.
 181:      * @return true if a valid choice was specified.
 182:      * @see javax.accessibility.AccessibleAction#doAccessibleAction(int)
 183:      */
 184:     public boolean doAccessibleAction(int i)
 185:     {
 186:       if (i < 0 || i >= pItems.size())
 187:     return false;
 188:         
 189:       Choice.this.processItemEvent(new ItemEvent(Choice.this,
 190:                          ItemEvent.ITEM_STATE_CHANGED,
 191:                          this, ItemEvent.SELECTED));
 192:       return true;
 193:     }
 194:   }
 195: 
 196: /*************************************************************************/
 197: 
 198: /*
 199:  * Constructors
 200:  */
 201: 
 202:   /**
 203:    * Initializes a new instance of <code>Choice</code>.
 204:    *
 205:    * @exception HeadlessException If GraphicsEnvironment.isHeadless()
 206:    * returns true
 207:    */
 208:   public Choice()
 209:   {
 210:     if (GraphicsEnvironment.isHeadless())
 211:       throw new HeadlessException ();
 212:   }
 213: 
 214: /*************************************************************************/
 215: 
 216: /*
 217:  * Instance Methods
 218:  */
 219: 
 220: /**
 221:   * Returns the number of items in the list.
 222:   *
 223:   * @return The number of items in the list.
 224:   */
 225: public int
 226: getItemCount()
 227: {
 228:   return countItems ();
 229: }
 230: 
 231: /*************************************************************************/
 232: 
 233: /**
 234:   * Returns the number of items in the list.
 235:   *
 236:   * @return The number of items in the list.
 237:   *
 238:   * @deprecated This method is deprecated in favor of <code>getItemCount</code>.
 239:   */
 240: public int
 241: countItems()
 242: {
 243:   return(pItems.size());
 244: }
 245: 
 246: /*************************************************************************/
 247: 
 248: /**
 249:   * Returns the item at the specified index in the list.
 250:   *
 251:   * @param index The index into the list to return the item from.
 252:   *
 253:   * @exception ArrayIndexOutOfBoundsException If the index is invalid.
 254:   */
 255: public String
 256: getItem(int index)
 257: {
 258:   return((String)pItems.elementAt(index));
 259: }
 260: 
 261: /*************************************************************************/
 262: 
 263: /**
 264:   * Adds the specified item to this choice box.
 265:   *
 266:   * @param item The item to add.
 267:   *
 268:   * @exception NullPointerException If the item's value is null
 269:   *
 270:   * @since 1.1
 271:   */
 272: public synchronized void
 273: add(String item)
 274: {
 275:   if (item == null)
 276:     throw new NullPointerException ("item must be non-null");
 277: 
 278:   pItems.addElement(item);
 279: 
 280:   int i = pItems.size () - 1;
 281:   if (peer != null)
 282:     {
 283:       ChoicePeer cp = (ChoicePeer) peer;
 284:       cp.add (item, i);
 285:     }
 286:   else if (selectedIndex == -1) 
 287:     select(0);
 288: }
 289: 
 290: /*************************************************************************/
 291: 
 292: /**
 293:   * Adds the specified item to this choice box.
 294:   *
 295:   * This method is oboslete since Java 2 platform 1.1. Please use @see add
 296:   * instead.
 297:   *
 298:   * @param item The item to add.
 299:   *
 300:   * @exception NullPointerException If the item's value is equal to null
 301:   */
 302: public synchronized void
 303: addItem(String item)
 304: {
 305:   add(item);
 306: }
 307: 
 308: /*************************************************************************/
 309: 
 310: /** Inserts an item into this Choice.  Existing items are shifted
 311:  * upwards.  If the new item is the only item, then it is selected.
 312:  * If the currently selected item is shifted, then the first item is
 313:  * selected.  If the currently selected item is not shifted, then it
 314:  * remains selected.
 315:  *
 316:  * @param item The item to add.
 317:  * @param index The index at which the item should be inserted.
 318:  *
 319:  * @exception IllegalArgumentException If index is less than 0
 320:  */
 321: public synchronized void
 322: insert(String item, int index)
 323: {
 324:   if (index < 0)
 325:     throw new IllegalArgumentException ("index may not be less then 0");
 326: 
 327:   if (index > getItemCount ())
 328:     index = getItemCount ();
 329: 
 330:   pItems.insertElementAt(item, index);
 331: 
 332:   if (peer != null)
 333:     {
 334:       ChoicePeer cp = (ChoicePeer) peer;
 335:       cp.add (item, index);
 336:     }
 337:   else if (selectedIndex == -1 || selectedIndex >= index)
 338:     select(0);
 339: }
 340: 
 341: /*************************************************************************/
 342: 
 343: /**
 344:   * Removes the specified item from the choice box.
 345:   *
 346:   * @param item The item to remove.
 347:   *
 348:   * @exception IllegalArgumentException If the specified item doesn't exist.
 349:   */
 350: public synchronized void
 351: remove(String item)
 352: {
 353:   int index = pItems.indexOf(item);
 354:   if (index == -1)
 355:     throw new IllegalArgumentException ("item \""
 356:                     + item + "\" not found in Choice");
 357:   remove(index);
 358: }
 359: 
 360: /*************************************************************************/
 361: 
 362: /**
 363:   * Removes the item at the specified index from the choice box.
 364:   *
 365:   * @param index The index of the item to remove.
 366:   *
 367:   * @exception IndexOutOfBoundsException If the index is not valid.
 368:   */
 369: public synchronized void
 370: remove(int index)
 371: {
 372:   if ((index < 0) || (index > getItemCount()))
 373:     throw new IllegalArgumentException("Bad index: " + index);
 374: 
 375:   pItems.removeElementAt(index);
 376: 
 377:   if (peer != null)
 378:     {
 379:       ChoicePeer cp = (ChoicePeer) peer;
 380:       cp.remove (index);
 381:     }
 382:   else
 383:     {
 384:       if (getItemCount() == 0)
 385:     selectedIndex = -1;
 386:       else if (index == selectedIndex)
 387:     select(0);
 388:     }
 389: 
 390:   if (selectedIndex > index)
 391:     --selectedIndex;
 392: }
 393: 
 394: /*************************************************************************/
 395: 
 396: /**
 397:   * Removes all of the objects from this choice box.
 398:   */
 399: public synchronized void
 400: removeAll()
 401: {
 402:   if (getItemCount() <= 0)
 403:     return;
 404:   
 405:   pItems.removeAllElements ();
 406: 
 407:   if (peer != null)
 408:     {
 409:       ChoicePeer cp = (ChoicePeer) peer;
 410:       cp.removeAll ();
 411:     }
 412: 
 413:   selectedIndex = -1;
 414: }
 415: 
 416: /*************************************************************************/
 417: 
 418: /**
 419:   * Returns the currently selected item, or null if no item is
 420:   * selected.
 421:   *
 422:   * @return The currently selected item.
 423:   */
 424: public synchronized String
 425: getSelectedItem()
 426: {
 427:   return (selectedIndex == -1
 428:       ? null
 429:       : ((String)pItems.elementAt(selectedIndex)));
 430: }
 431: 
 432: /*************************************************************************/
 433: 
 434: /**
 435:   * Returns an array with one row containing the selected item.
 436:   *
 437:   * @return An array containing the selected item.
 438:   */
 439: public synchronized Object[]
 440: getSelectedObjects()
 441: {
 442:   if (selectedIndex == -1)
 443:     return null;
 444: 
 445:   Object[] objs = new Object[1];
 446:   objs[0] = pItems.elementAt(selectedIndex);
 447: 
 448:   return(objs);
 449: }
 450: 
 451: /*************************************************************************/
 452: 
 453: /**
 454:   * Returns the index of the selected item.
 455:   *
 456:   * @return The index of the selected item.
 457:   */
 458: public int
 459: getSelectedIndex()
 460: {
 461:   return(selectedIndex);
 462: }
 463: 
 464: /*************************************************************************/
 465: 
 466: /**
 467:   * Forces the item at the specified index to be selected.
 468:   *
 469:   * @param index The index of the row to make selected.
 470:   *
 471:   * @exception IllegalArgumentException If the specified index is invalid.
 472:   */
 473: public synchronized void
 474: select(int index)
 475: {
 476:   if ((index < 0) || (index >= getItemCount()))
 477:     throw new IllegalArgumentException("Bad index: " + index);
 478: 
 479:   if (pItems.size() > 0) {
 480:       selectedIndex = index;
 481:       ChoicePeer cp = (ChoicePeer) peer;
 482:       if (cp != null) {
 483:           cp.select(index);
 484:       }
 485:   }
 486: }
 487: 
 488: /*************************************************************************/
 489: 
 490: /**
 491:   * Forces the named item to be selected.
 492:   *
 493:   * @param item The item to be selected.
 494:   *
 495:   * @exception IllegalArgumentException If the specified item does not exist.
 496:   */
 497: public synchronized void
 498: select(String item)
 499: {
 500:   int index = pItems.indexOf(item);
 501:   if (index >= 0)
 502:     select(index);
 503: }
 504: 
 505: /*************************************************************************/
 506: 
 507: /**
 508:   * Creates the native peer for this object.
 509:   */
 510: public void
 511: addNotify()
 512: {
 513:   if (peer == null)
 514:     peer = getToolkit ().createChoice (this);
 515:   super.addNotify ();
 516: }
 517: 
 518: /*************************************************************************/
 519: 
 520: /**
 521:   * Adds the specified listener to the list of registered listeners for
 522:   * this object.
 523:   *
 524:   * @param listener The listener to add.
 525:   */
 526: public synchronized void
 527: addItemListener(ItemListener listener)
 528: {
 529:   item_listeners = AWTEventMulticaster.add(item_listeners, listener);
 530: }
 531: 
 532: /*************************************************************************/
 533: 
 534: /**
 535:   * Removes the specified listener from the list of registered listeners for
 536:   * this object.
 537:   *
 538:   * @param listener The listener to remove.
 539:   */
 540: public synchronized void
 541: removeItemListener(ItemListener listener)
 542: {
 543:   item_listeners = AWTEventMulticaster.remove(item_listeners, listener);
 544: }
 545: 
 546: /*************************************************************************/
 547: 
 548: /**
 549:   * Processes this event by invoking <code>processItemEvent()</code> if the
 550:   * event is an instance of <code>ItemEvent</code>, otherwise the event
 551:   * is passed to the superclass.
 552:   *
 553:   * @param event The event to process.
 554:   */
 555: protected void
 556: processEvent(AWTEvent event)
 557: {
 558:   if (event instanceof ItemEvent)
 559:     processItemEvent((ItemEvent)event);
 560:   else
 561:     super.processEvent(event);
 562: }
 563: 
 564: void 
 565: dispatchEventImpl(AWTEvent e)
 566: {
 567:   if (e.id <= ItemEvent.ITEM_LAST
 568:       && e.id >= ItemEvent.ITEM_FIRST
 569:       && (item_listeners != null || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0))
 570:     processEvent(e);
 571:   else
 572:     super.dispatchEventImpl(e);
 573: }
 574: 
 575: /*************************************************************************/
 576: 
 577: /**
 578:   * Processes item event by dispatching to any registered listeners.
 579:   *
 580:   * @param event The event to process.
 581:   */
 582: protected void
 583: processItemEvent(ItemEvent event)
 584: {
 585:   int index = pItems.indexOf((String) event.getItem());
 586:   // Don't call back into the peers when selecting index here
 587:   if (event.getStateChange() == ItemEvent.SELECTED)
 588:     this.selectedIndex = index;
 589:   if (item_listeners != null)
 590:     item_listeners.itemStateChanged(event);
 591: }
 592: 
 593: /*************************************************************************/
 594: 
 595: /**
 596:   * Returns a debugging string for this object.
 597:   *
 598:   * @return A debugging string for this object.
 599:   */
 600: protected String
 601: paramString()
 602: {
 603:   return ("selectedIndex=" + selectedIndex + "," + super.paramString());
 604: }
 605: 
 606:   /**
 607:    * Returns an array of all the objects currently registered as FooListeners
 608:    * upon this Choice. FooListeners are registered using the addFooListener
 609:    * method.
 610:    *
 611:    * @exception ClassCastException If listenerType doesn't specify a class or
 612:    * interface that implements java.util.EventListener.
 613:    *
 614:    * @since 1.3
 615:    */
 616:   public EventListener[] getListeners (Class listenerType)
 617:   {
 618:     if (listenerType == ItemListener.class)
 619:       return AWTEventMulticaster.getListeners (item_listeners, listenerType);
 620:     
 621:     return super.getListeners (listenerType);
 622:   }
 623: 
 624:   /**
 625:    * Returns all registered item listeners.
 626:    *
 627:    * @since 1.4
 628:    */
 629:   public ItemListener[] getItemListeners ()
 630:   {
 631:     return (ItemListener[]) getListeners (ItemListener.class);
 632:   }
 633: 
 634:   /**
 635:    * Gets the AccessibleContext associated with this <code>Choice</code>.
 636:    * The context is created, if necessary.
 637:    *
 638:    * @return the associated context
 639:    */
 640:   public AccessibleContext getAccessibleContext()
 641:   {
 642:     /* Create the context if this is the first request */
 643:     if (accessibleContext == null)
 644:       accessibleContext = new AccessibleAWTChoice();
 645:     return accessibleContext;
 646:   }
 647:   
 648:   /**
 649:    * Generate a unique name for this <code>Choice</code>.
 650:    *
 651:    * @return A unique name for this <code>Choice</code>.
 652:    */
 653:   String generateName()
 654:   {
 655:     return "choice" + getUniqueLong();
 656:   }
 657: 
 658:   private static synchronized long getUniqueLong()
 659:   {
 660:     return next_choice_number++;
 661:   }
 662: } // class Choice