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 
 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:    */
 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:     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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 473:   protected void processEvent(AWTEvent event)
 474:   {
 475:     if (event instanceof ItemEvent)
 476:       processItemEvent((ItemEvent)event);
 477:     else
 478:       super.processEvent(event);
 479:   }
 480: 
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 560:   String generateName()
 561:   {
 562:     return "choice" + getUniqueLong();
 563:   }
 564: 
 565:   private static synchronized long getUniqueLong()
 566:   {
 567:     return next_choice_number++;
 568:   }
 569: } // class Choice