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