Source for java.awt.Choice

   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:      */
 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:      */
 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:      */
 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:      */
 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:      */
 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:      */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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 @see add
 259:    * instead.
 260:    *
 261:    * @param item The item to add.
 262:    *
 263:    * @exception NullPointerException If the item's value is equal to null
 264:    */
 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:    */
 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:    */
 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:    */
 321:   public synchronized void remove(int index)
 322:   {
 323:     if ((index < 0) || (index > getItemCount()))
 324:       throw new IllegalArgumentException("Bad index: " + index);
 325: 
 326:     pItems.removeElementAt(index);
 327: 
 328:     if (peer != null)
 329:       ((ChoicePeer) peer).remove( index );
 330: 
 331:     if( getItemCount() == 0 )
 332:       selectedIndex = -1;
 333:     else 
 334:       {
 335:        if( selectedIndex > index )
 336:          selectedIndex--;
 337:        else if( selectedIndex == index )
 338:          selectedIndex = 0;
 339: 
 340:        if( peer != null )
 341:          ((ChoicePeer)peer).select( selectedIndex );
 342:        }
 343:   }
 344: 
 345:   /**
 346:    * Removes all of the objects from this choice box.
 347:    */
 348:   public synchronized void removeAll()
 349:   {
 350:     if (getItemCount() <= 0)
 351:       return;
 352:   
 353:     pItems.removeAllElements ();
 354: 
 355:     if (peer != null)
 356:       {
 357:     ChoicePeer cp = (ChoicePeer) peer;
 358:     cp.removeAll ();
 359:       }
 360: 
 361:     selectedIndex = -1;
 362:   }
 363: 
 364:   /**
 365:    * Returns the currently selected item, or null if no item is
 366:    * selected.
 367:    *
 368:    * @return The currently selected item.
 369:    */
 370:   public synchronized String getSelectedItem()
 371:   {
 372:     return (selectedIndex == -1
 373:         ? null
 374:         : ((String)pItems.elementAt(selectedIndex)));
 375:   }
 376: 
 377:   /**
 378:    * Returns an array with one row containing the selected item.
 379:    *
 380:    * @return An array containing the selected item.
 381:    */
 382:   public synchronized Object[] getSelectedObjects()
 383:   {
 384:     if (selectedIndex == -1)
 385:       return null;
 386: 
 387:     Object[] objs = new Object[1];
 388:     objs[0] = pItems.elementAt(selectedIndex);
 389: 
 390:     return objs;
 391:   }
 392: 
 393:   /**
 394:    * Returns the index of the selected item.
 395:    *
 396:    * @return The index of the selected item.
 397:    */
 398:   public int getSelectedIndex()
 399:   {
 400:     return selectedIndex;
 401:   }
 402: 
 403:   /**
 404:    * Forces the item at the specified index to be selected.
 405:    *
 406:    * @param index The index of the row to make selected.
 407:    *
 408:    * @exception IllegalArgumentException If the specified index is invalid.
 409:    */
 410:   public synchronized void select(int index)
 411:   {
 412:     if ((index < 0) || (index >= getItemCount()))
 413:       throw new IllegalArgumentException("Bad index: " + index);
 414: 
 415:     if( selectedIndex == index ) 
 416:       return;
 417: 
 418:     selectedIndex = index;
 419:     if( peer != null ) 
 420:       ((ChoicePeer)peer).select( index );
 421:   }
 422: 
 423:   /**
 424:    * Forces the named item to be selected.
 425:    *
 426:    * @param item The item to be selected.
 427:    *
 428:    * @exception IllegalArgumentException If the specified item does not exist.
 429:    */
 430:   public synchronized void select(String item)
 431:   {
 432:     int index = pItems.indexOf(item);
 433:     if( index >= 0 )
 434:       select( index );
 435:   }
 436: 
 437:   /**
 438:    * Creates the native peer for this object.
 439:    */
 440:   public void addNotify()
 441:   {
 442:     if (peer == null)
 443:       peer = getToolkit ().createChoice (this);
 444:     super.addNotify ();
 445:   }
 446: 
 447:   /**
 448:    * Adds the specified listener to the list of registered listeners for
 449:    * this object.
 450:    *
 451:    * @param listener The listener to add.
 452:    */
 453:   public synchronized void addItemListener(ItemListener listener)
 454:   {
 455:     item_listeners = AWTEventMulticaster.add(item_listeners, listener);
 456:   }
 457: 
 458:   /**
 459:    * Removes the specified listener from the list of registered listeners for
 460:    * this object.
 461:    *
 462:    * @param listener The listener to remove.
 463:    */
 464:   public synchronized void removeItemListener(ItemListener listener)
 465:   {
 466:     item_listeners = AWTEventMulticaster.remove(item_listeners, listener);
 467:   }
 468: 
 469:   /**
 470:    * Processes this event by invoking <code>processItemEvent()</code> if the
 471:    * event is an instance of <code>ItemEvent</code>, otherwise the event
 472:    * is passed to the superclass.
 473:    *
 474:    * @param event The event to process.
 475:    */
 476:   protected void processEvent(AWTEvent event)
 477:   {
 478:     if (event instanceof ItemEvent)
 479:       processItemEvent((ItemEvent)event);
 480:     else
 481:       super.processEvent(event);
 482:   }
 483: 
 484:   void dispatchEventImpl(AWTEvent e)
 485:   {
 486:     super.dispatchEventImpl(e);
 487: 
 488:     if( e.id <= ItemEvent.ITEM_LAST && e.id >= ItemEvent.ITEM_FIRST && 
 489:     ( item_listeners != null || 
 490:       ( eventMask & AWTEvent.ITEM_EVENT_MASK ) != 0 ) )
 491:       processEvent(e);
 492:   }
 493: 
 494:   /**
 495:    * Processes item event by dispatching to any registered listeners.
 496:    *
 497:    * @param event The event to process.
 498:    */
 499:   protected void processItemEvent(ItemEvent event)
 500:   {
 501:     int index = pItems.indexOf((String) event.getItem());
 502:     if (item_listeners != null)
 503:       item_listeners.itemStateChanged(event);
 504:   }
 505: 
 506:   /**
 507:    * Returns a debugging string for this object.
 508:    *
 509:    * @return A debugging string for this object.
 510:    */
 511:   protected String paramString()
 512:   {
 513:     return "selectedIndex=" + selectedIndex + "," + super.paramString();
 514:   }
 515: 
 516:   /**
 517:    * Returns an array of all the objects currently registered as FooListeners
 518:    * upon this Choice. FooListeners are registered using the addFooListener
 519:    * method.
 520:    *
 521:    * @exception ClassCastException If listenerType doesn't specify a class or
 522:    * interface that implements java.util.EventListener.
 523:    *
 524:    * @since 1.3
 525:    */
 526:   public EventListener[] getListeners (Class listenerType)
 527:   {
 528:     if (listenerType == ItemListener.class)
 529:       return AWTEventMulticaster.getListeners (item_listeners, listenerType);
 530:     
 531:     return super.getListeners (listenerType);
 532:   }
 533: 
 534:   /**
 535:    * Returns all registered item listeners.
 536:    *
 537:    * @since 1.4
 538:    */
 539:   public ItemListener[] getItemListeners ()
 540:   {
 541:     return (ItemListener[]) getListeners (ItemListener.class);
 542:   }
 543: 
 544:   /**
 545:    * Gets the AccessibleContext associated with this <code>Choice</code>.
 546:    * The context is created, if necessary.
 547:    *
 548:    * @return the associated context
 549:    */
 550:   public AccessibleContext getAccessibleContext()
 551:   {
 552:     /* Create the context if this is the first request */
 553:     if (accessibleContext == null)
 554:       accessibleContext = new AccessibleAWTChoice();
 555:     return accessibleContext;
 556:   }
 557:   
 558:   /**
 559:    * Generate a unique name for this <code>Choice</code>.
 560:    *
 561:    * @return A unique name for this <code>Choice</code>.
 562:    */
 563:   String generateName()
 564:   {
 565:     return "choice" + getUniqueLong();
 566:   }
 567: 
 568:   private static synchronized long getUniqueLong()
 569:   {
 570:     return next_choice_number++;
 571:   }
 572: } // class Choice