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