Source for javax.swing.JComboBox

   1: /* JComboBox.java --
   2:    Copyright (C) 2002, 2004, 2005, 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 javax.swing;
  40: 
  41: import java.awt.ItemSelectable;
  42: import java.awt.event.ActionEvent;
  43: import java.awt.event.ActionListener;
  44: import java.awt.event.ItemEvent;
  45: import java.awt.event.ItemListener;
  46: import java.awt.event.KeyEvent;
  47: import java.beans.PropertyChangeEvent;
  48: import java.beans.PropertyChangeListener;
  49: import java.util.Vector;
  50: 
  51: import javax.accessibility.Accessible;
  52: import javax.accessibility.AccessibleAction;
  53: import javax.accessibility.AccessibleContext;
  54: import javax.accessibility.AccessibleRole;
  55: import javax.accessibility.AccessibleSelection;
  56: import javax.swing.event.ListDataEvent;
  57: import javax.swing.event.ListDataListener;
  58: import javax.swing.event.PopupMenuEvent;
  59: import javax.swing.event.PopupMenuListener;
  60: import javax.swing.plaf.ComboBoxUI;
  61: import javax.swing.plaf.ComponentUI;
  62: import javax.swing.plaf.basic.ComboPopup;
  63: 
  64: /**
  65:  * A component that allows a user to select any item in its list and
  66:  * displays the selected item to the user. JComboBox also can show/hide a
  67:  * popup menu containing its list of item whenever the mouse is pressed
  68:  * over it.
  69:  *
  70:  * @author Andrew Selkirk
  71:  * @author Olga Rodimina
  72:  * @author Robert Schuster
  73:  */
  74: public class JComboBox extends JComponent implements ItemSelectable,
  75:                                                      ListDataListener,
  76:                                                      ActionListener,
  77:                                                      Accessible
  78: {
  79: 
  80:   private static final long serialVersionUID = 5654585963292734470L;
  81: 
  82:   /**
  83:    * Classes implementing this interface are
  84:    * responsible for matching key characters typed by the user with combo
  85:    * box's items.
  86:    */
  87:   public static interface KeySelectionManager
  88:   {
  89:     int selectionForKey(char aKey, ComboBoxModel aModel);
  90:   }
  91: 
  92:   /**
  93:    * Maximum number of rows that should be visible by default  in the
  94:    * JComboBox's popup
  95:    */
  96:   private static final int DEFAULT_MAXIMUM_ROW_COUNT = 8;
  97: 
  98:   /**
  99:    * Data model used by JComboBox to keep track of its list data and currently
 100:    * selected element in the list.
 101:    */
 102:   protected ComboBoxModel dataModel;
 103: 
 104:   /**
 105:    * Renderer renders(paints) every object in the combo box list in its
 106:    * associated list cell. This ListCellRenderer is used only when  this
 107:    * JComboBox is uneditable.
 108:    */
 109:   protected ListCellRenderer renderer;
 110: 
 111:   /**
 112:    * Editor that is responsible for editing an object in a combo box list.
 113:    */
 114:   protected ComboBoxEditor editor;
 115: 
 116:   /**
 117:    * Number of rows that will be visible in the JComboBox's popup.
 118:    */
 119:   protected int maximumRowCount;
 120: 
 121:   /**
 122:    * This field indicates if textfield of this JComboBox is editable or not.
 123:    */
 124:   protected boolean isEditable;
 125: 
 126:   /**
 127:    * This field is reference to the current selection of the combo box.
 128:    */
 129:   protected Object selectedItemReminder;
 130: 
 131:   /**
 132:    * keySelectionManager
 133:    */
 134:   protected KeySelectionManager keySelectionManager;
 135: 
 136:   /**
 137:    * This actionCommand is used in ActionEvent that is fired to JComboBox's
 138:    * ActionListeneres.
 139:    */
 140:   protected String actionCommand;
 141: 
 142:   /**
 143:    * This property indicates if heavyweight popup or lightweight popup will be
 144:    * used to diplay JComboBox's elements.
 145:    */
 146:   protected boolean lightWeightPopupEnabled;
 147: 
 148:   /**
 149:    * The action taken when new item is selected in the JComboBox
 150:    */
 151:   private Action action;
 152: 
 153:   /**
 154:    * since 1.4  If this field is set then comboBox's display area for the
 155:    * selected item  will be set by default to this value.
 156:    */
 157:   private Object prototypeDisplayValue;
 158: 
 159:   /**
 160:    * Constructs JComboBox object with specified data model for it.
 161:    * <p>Note that the JComboBox will not change the value that
 162:    * is preselected by your ComboBoxModel implementation.</p>
 163:    *
 164:    * @param model Data model that will be used by this JComboBox to keep track
 165:    *        of its list of items.
 166:    */
 167:   public JComboBox(ComboBoxModel model)
 168:   {
 169:     setEditable(false);
 170:     setEnabled(true);
 171:     setMaximumRowCount(DEFAULT_MAXIMUM_ROW_COUNT);
 172:     setModel(model);
 173:     setActionCommand("comboBoxChanged");
 174: 
 175:     lightWeightPopupEnabled = true;
 176:     isEditable = false;
 177: 
 178:     updateUI();
 179:   }
 180: 
 181:   /**
 182:    * Constructs JComboBox with specified list of items.
 183:    *
 184:    * @param itemArray array containing list of items for this JComboBox
 185:    */
 186:   public JComboBox(Object[] itemArray)
 187:   {
 188:     this(new DefaultComboBoxModel(itemArray));
 189:     
 190:     if (itemArray.length > 0) 
 191:       setSelectedIndex(0);
 192:   }
 193: 
 194:   /**
 195:    * Constructs JComboBox object with specified list of items.
 196:    *
 197:    * @param itemVector vector containing list of items for this JComboBox.
 198:    */
 199:   public JComboBox(Vector<?> itemVector)
 200:   {
 201:     this(new DefaultComboBoxModel(itemVector));
 202: 
 203:     if (itemVector.size() > 0)
 204:       setSelectedIndex(0);
 205:   }
 206: 
 207:   /**
 208:    * Constructor. Creates new empty JComboBox. ComboBox's data model is set to
 209:    * DefaultComboBoxModel.
 210:    */
 211:   public JComboBox()
 212:   {
 213:     this(new DefaultComboBoxModel());
 214:   }
 215: 
 216:   /**
 217:    * This method returns true JComboBox is editable and false otherwise
 218:    *
 219:    * @return boolean true if JComboBox is editable and false otherwise
 220:    */
 221:   public boolean isEditable()
 222:   {
 223:     return isEditable;
 224:   }
 225: 
 226:   /*
 227:    * This method adds ancestor listener to this JComboBox.
 228:    */
 229:   protected void installAncestorListener()
 230:   {
 231:     /* FIXME: Need to implement.
 232:      *
 233:      * Need to add ancestor listener to this JComboBox. This listener
 234:      * should close combo box's popup list of items whenever it
 235:      * receives an AncestorEvent.
 236:      */
 237:   }
 238: 
 239:   /**
 240:    * Set the "UI" property of the combo box, which is a look and feel class
 241:    * responsible for handling comboBox's input events and painting it.
 242:    *
 243:    * @param ui The new "UI" property
 244:    */
 245:   public void setUI(ComboBoxUI ui)
 246:   {
 247:     super.setUI(ui);
 248:   }
 249: 
 250:   /**
 251:    * This method sets this comboBox's UI to the UIManager's default for the
 252:    * current look and feel.
 253:    */
 254:   public void updateUI()
 255:   {
 256:     setUI((ComboBoxUI) UIManager.getUI(this));
 257:   }
 258: 
 259:   /**
 260:    * This method returns the String identifier for the UI class to the used
 261:    * with the JComboBox.
 262:    *
 263:    * @return The String identifier for the UI class.
 264:    */
 265:   public String getUIClassID()
 266:   {
 267:     return "ComboBoxUI";
 268:   }
 269: 
 270:   /**
 271:    * This method returns the UI used to display the JComboBox.
 272:    *
 273:    * @return The UI used to display the JComboBox.
 274:    */
 275:   public ComboBoxUI getUI()
 276:   {
 277:     return (ComboBoxUI) ui;
 278:   }
 279: 
 280:   /**
 281:    * Set the data model for this JComboBox. This un-registers all  listeners
 282:    * associated with the current model, and re-registers them with the new
 283:    * model.
 284:    *
 285:    * @param newDataModel The new data model for this JComboBox
 286:    */
 287:   public void setModel(ComboBoxModel newDataModel)
 288:   {
 289:     // dataModel is null if it this method is called from inside the constructors.
 290:     if (dataModel != null)
 291:       {
 292:         // Prevents unneccessary updates.
 293:         if (dataModel == newDataModel)
 294:           return;
 295: 
 296:         // Removes itself (as DataListener) from the to-be-replaced model.
 297:         dataModel.removeListDataListener(this);
 298:       }
 299:     
 300:     /* Adds itself as a DataListener to the new model.
 301:      * It is intentioned that this operation will fail with a NullPointerException if the
 302:      * caller delivered a null argument.
 303:      */
 304:     newDataModel.addListDataListener(this);
 305: 
 306:     // Stores old data model for event notification.
 307:     ComboBoxModel oldDataModel = dataModel;
 308:     dataModel = newDataModel;
 309:     selectedItemReminder = newDataModel.getSelectedItem();
 310:     
 311:     // Notifies the listeners of the model change.
 312:     firePropertyChange("model", oldDataModel, dataModel);
 313:   }
 314: 
 315:   /**
 316:    * This method returns data model for this comboBox.
 317:    *
 318:    * @return ComboBoxModel containing items for this combo box.
 319:    */
 320:   public ComboBoxModel getModel()
 321:   {
 322:     return dataModel;
 323:   }
 324: 
 325:   /**
 326:    * This method sets JComboBox's popup to be either lightweight or
 327:    * heavyweight. If 'enabled' is true then lightweight popup is used and
 328:    * heavyweight otherwise. By default lightweight popup is used to display
 329:    * this JComboBox's elements.
 330:    *
 331:    * @param enabled indicates if lightweight popup or heavyweight popup should
 332:    *        be used to display JComboBox's elements.
 333:    */
 334:   public void setLightWeightPopupEnabled(boolean enabled)
 335:   {
 336:     lightWeightPopupEnabled = enabled;
 337:   }
 338: 
 339:   /**
 340:    * This method returns whether popup menu that is used to display list of
 341:    * combo box's item is lightWeight or not.
 342:    *
 343:    * @return boolean true if popup menu is lightweight and false otherwise.
 344:    */
 345:   public boolean isLightWeightPopupEnabled()
 346:   {
 347:     return lightWeightPopupEnabled;
 348:   }
 349: 
 350:   /**
 351:    * This method sets editability of the combo box. If combo box  is editable
 352:    * the user can choose component from the combo box list by typing
 353:    * component's name in the editor(JTextfield by default).  Otherwise if not
 354:    * editable, the user should use the list to choose   the component. This
 355:    * method fires PropertyChangeEvents to JComboBox's registered
 356:    * PropertyChangeListeners to indicate that 'editable' property of the
 357:    * JComboBox has changed.
 358:    *
 359:    * @param editable indicates if the JComboBox's textfield should be editable
 360:    *        or not.
 361:    */
 362:   public void setEditable(boolean editable)
 363:   {
 364:     if (isEditable != editable)
 365:       {
 366:         isEditable = editable;
 367:         firePropertyChange("editable", !isEditable, isEditable);
 368:       }
 369:   }
 370: 
 371:   /**
 372:    * Sets number of rows that should be visible in this JComboBox's popup. If
 373:    * this JComboBox's popup has more elements that maximum number or rows
 374:    * then popup will have a scroll pane to allow users to view other
 375:    * elements.
 376:    *
 377:    * @param rowCount number of rows that will be visible in JComboBox's popup.
 378:    */
 379:   public void setMaximumRowCount(int rowCount)
 380:   {
 381:     if (maximumRowCount != rowCount)
 382:       {
 383:         int oldMaximumRowCount = maximumRowCount;
 384:         maximumRowCount = rowCount;
 385:         firePropertyChange("maximumRowCount", oldMaximumRowCount,
 386:                            maximumRowCount);
 387:       }
 388:   }
 389: 
 390:   /**
 391:    * This method returns number of rows visible in the JComboBox's list of
 392:    * items.
 393:    *
 394:    * @return int maximun number of visible rows in the JComboBox's list.
 395:    */
 396:   public int getMaximumRowCount()
 397:   {
 398:     return maximumRowCount;
 399:   }
 400: 
 401:   /**
 402:    * This method sets cell renderer for this JComboBox that will be used to
 403:    * paint combo box's items. The Renderer should only be used only when
 404:    * JComboBox is not editable.  In the case when JComboBox is editable  the
 405:    * editor must be used.  This method also fires PropertyChangeEvent when
 406:    * cellRendered for this JComboBox has changed.
 407:    *
 408:    * @param aRenderer cell renderer that will be used by this JComboBox to
 409:    *        paint its elements.
 410:    */
 411:   public void setRenderer(ListCellRenderer aRenderer)
 412:   {
 413:     if (renderer != aRenderer)
 414:       {
 415:         ListCellRenderer oldRenderer = renderer;
 416:         renderer = aRenderer;
 417:         firePropertyChange("renderer", oldRenderer, renderer);
 418:       }
 419:   }
 420: 
 421:   /**
 422:    * This method returns renderer responsible for rendering selected item in
 423:    * the combo box
 424:    *
 425:    * @return ListCellRenderer
 426:    */
 427:   public ListCellRenderer getRenderer()
 428:   {
 429:     return renderer;
 430:   }
 431: 
 432:   /**
 433:    * Sets editor for this JComboBox
 434:    *
 435:    * @param newEditor ComboBoxEditor for this JComboBox. This method fires
 436:    *        PropertyChangeEvent when 'editor' property is changed.
 437:    */
 438:   public void setEditor(ComboBoxEditor newEditor)
 439:   {
 440:     if (editor == newEditor)
 441:       return;
 442: 
 443:     if (editor != null)
 444:       editor.removeActionListener(this);
 445: 
 446:     ComboBoxEditor oldEditor = editor;
 447:     editor = newEditor;
 448: 
 449:     if (editor != null)
 450:       editor.addActionListener(this);
 451: 
 452:     firePropertyChange("editor", oldEditor, editor);
 453:   }
 454: 
 455:   /**
 456:    * Returns editor component that is responsible for displaying/editing
 457:    * selected item in the combo box.
 458:    *
 459:    * @return ComboBoxEditor
 460:    */
 461:   public ComboBoxEditor getEditor()
 462:   {
 463:     return editor;
 464:   }
 465: 
 466:   /**
 467:    * Forces combo box to select given item
 468:    *
 469:    * @param item element in the combo box to select.
 470:    */
 471:   public void setSelectedItem(Object item)
 472:   {
 473:     dataModel.setSelectedItem(item);
 474:     fireActionEvent();
 475:   }
 476: 
 477:   /**
 478:    * Returns currently selected item in the combo box.
 479:    * The result may be <code>null</code> to indicate that nothing is
 480:    * currently selected.
 481:    *
 482:    * @return element that is currently selected in this combo box.
 483:    */
 484:   public Object getSelectedItem()
 485:   {
 486:     return dataModel.getSelectedItem();
 487:   }
 488: 
 489:   /**
 490:    * Forces JComboBox to select component located in the given index in the
 491:    * combo box.
 492:    * <p>If the index is below -1 or exceeds the upper bound an
 493:    * <code>IllegalArgumentException</code> is thrown.<p/>
 494:    * <p>If the index is -1 then no item gets selected.</p>
 495:    *
 496:    * @param index index specifying location of the component that  should be
 497:    *        selected.
 498:    */
 499:   public void setSelectedIndex(int index)
 500:   {
 501:       if (index < -1 || index >= dataModel.getSize())
 502:       // Fails because index is out of bounds.
 503:       throw new IllegalArgumentException("illegal index: " + index);
 504:     else
 505:        // Selects the item at the given index or clears the selection if the
 506:        // index value is -1.
 507:       setSelectedItem((index == -1) ? null : dataModel.getElementAt(index));
 508:   }
 509: 
 510:   /**
 511:    * Returns index of the item that is currently selected in the combo box. If
 512:    * no item is currently selected, then -1 is returned.
 513:    * <p>
 514:    * Note: For performance reasons you should minimize invocation of this
 515:    * method. If the data model is not an instance of
 516:    * <code>DefaultComboBoxModel</code> the complexity is O(n) where n is the
 517:    * number of elements in the combo box.
 518:    * </p>
 519:    * 
 520:    * @return int Index specifying location of the currently selected item in the
 521:    *         combo box or -1 if nothing is selected in the combo box.
 522:    */
 523:   public int getSelectedIndex()
 524:   {
 525:     Object selectedItem = getSelectedItem();
 526: 
 527:     if (selectedItem != null)
 528:       {
 529:         if (dataModel instanceof DefaultComboBoxModel)
 530:           // Uses special method of DefaultComboBoxModel to retrieve the index.
 531:           return ((DefaultComboBoxModel) dataModel).getIndexOf(selectedItem);
 532:         else
 533:           {
 534:             // Iterates over all items to retrieve the index.
 535:             int size = dataModel.getSize();
 536: 
 537:             for (int i = 0; i < size; i++)
 538:               {
 539:                 Object o = dataModel.getElementAt(i);
 540: 
 541:                 // XXX: Is special handling of ComparableS neccessary?
 542:                 if ((selectedItem != null) ? selectedItem.equals(o) : o == null)
 543:                   return i;
 544:               }
 545:           }
 546:       }
 547: 
 548:     // returns that no item is currently selected
 549:     return -1;
 550:   }
 551: 
 552:   /**
 553:    * Returns an object that is used as the display value when calculating the 
 554:    * preferred size for the combo box.  This value is, of course, never 
 555:    * displayed anywhere.
 556:    * 
 557:    * @return The prototype display value (possibly <code>null</code>).
 558:    * 
 559:    * @since 1.4
 560:    * @see #setPrototypeDisplayValue(Object)
 561:    */
 562:   public Object getPrototypeDisplayValue()
 563:   {
 564:     return prototypeDisplayValue;
 565:   }
 566: 
 567:   /**
 568:    * Sets the object that is assumed to be the displayed item when calculating
 569:    * the preferred size for the combo box.  A {@link PropertyChangeEvent} (with
 570:    * the name <code>prototypeDisplayValue</code>) is sent to all registered 
 571:    * listeners. 
 572:    * 
 573:    * @param value  the new value (<code>null</code> permitted).
 574:    * 
 575:    * @since 1.4
 576:    * @see #getPrototypeDisplayValue()
 577:    */
 578:   public void setPrototypeDisplayValue(Object value)
 579:   {
 580:     Object oldValue = prototypeDisplayValue;
 581:     prototypeDisplayValue = value;
 582:     firePropertyChange("prototypeDisplayValue", oldValue, value);
 583:   }
 584: 
 585:   /**
 586:    * This method adds given element to this JComboBox.
 587:    * <p>A <code>RuntimeException</code> is thrown if the data model is not
 588:    * an instance of {@link MutableComboBoxModel}.</p>
 589:    *
 590:    * @param element element to add
 591:    */
 592:   public void addItem(Object element)
 593:   {
 594:       if (dataModel instanceof MutableComboBoxModel)
 595:       ((MutableComboBoxModel) dataModel).addElement(element);
 596:     else
 597:       throw new RuntimeException("Unable to add the item because the data "
 598:                                  + "model it is not an instance of "
 599:                                  + "MutableComboBoxModel.");
 600:   }
 601: 
 602:   /**
 603:    * Inserts given element at the specified index to this JComboBox.
 604:    * <p>A <code>RuntimeException</code> is thrown if the data model is not
 605:    * an instance of {@link MutableComboBoxModel}.</p>
 606:    *
 607:    * @param element element to insert
 608:    * @param index position where to insert the element
 609:    */
 610:   public void insertItemAt(Object element, int index)
 611:   {
 612:     if (dataModel instanceof MutableComboBoxModel)
 613:       ((MutableComboBoxModel) dataModel).insertElementAt(element, index);
 614:     else
 615:       throw new RuntimeException("Unable to insert the item because the data "
 616:                                  + "model it is not an instance of "
 617:                                  + "MutableComboBoxModel.");
 618:   }
 619: 
 620:   /**
 621:    * This method removes given element from this JComboBox.
 622:    * <p>A <code>RuntimeException</code> is thrown if the data model is not
 623:    * an instance of {@link MutableComboBoxModel}.</p>
 624:    *
 625:    * @param element element to remove
 626:    */
 627:   public void removeItem(Object element)
 628:   {
 629:     if (dataModel instanceof MutableComboBoxModel)
 630:       ((MutableComboBoxModel) dataModel).removeElement(element);
 631:     else
 632:       throw new RuntimeException("Unable to remove the item because the data "
 633:                                  + "model it is not an instance of "
 634:                                  + "MutableComboBoxModel.");
 635:   }
 636: 
 637:   /**
 638:    * This method remove element location in the specified index in the
 639:    * JComboBox.
 640:    * <p>A <code>RuntimeException</code> is thrown if the data model is not
 641:    * an instance of {@link MutableComboBoxModel}.</p>
 642:    *
 643:    * @param index index specifying position of the element to remove
 644:    */
 645:   public void removeItemAt(int index)
 646:   {
 647:     if (dataModel instanceof MutableComboBoxModel)
 648:       ((MutableComboBoxModel) dataModel).removeElementAt(index);
 649:     else
 650:       throw new RuntimeException("Unable to remove the item because the data "
 651:                                  + "model it is not an instance of "
 652:                                  + "MutableComboBoxModel.");
 653:   }
 654: 
 655:   /**
 656:    * This method removes all elements from this JComboBox.
 657:    * <p>
 658:    * A <code>RuntimeException</code> is thrown if the data model is not an
 659:    * instance of {@link MutableComboBoxModel}.
 660:    * </p>
 661:    */
 662:   public void removeAllItems()
 663:   {
 664:     if (dataModel instanceof DefaultComboBoxModel)
 665:       // Uses special method if we have a DefaultComboBoxModel.
 666:       ((DefaultComboBoxModel) dataModel).removeAllElements();
 667:     else if (dataModel instanceof MutableComboBoxModel)
 668:       {
 669:         // Iterates over all items and removes each.
 670:         MutableComboBoxModel mcbm = (MutableComboBoxModel) dataModel;
 671: 
 672:          // We intentionally remove the items backwards to support models which
 673:          // shift their content to the beginning (e.g. linked lists)
 674:         for (int i = mcbm.getSize() - 1; i >= 0; i--)
 675:           mcbm.removeElementAt(i);
 676:       }
 677:     else
 678:       throw new RuntimeException("Unable to remove the items because the data "
 679:                                  + "model it is not an instance of "
 680:                                  + "MutableComboBoxModel.");
 681:   }
 682: 
 683:   /**
 684:    * This method displays popup with list of combo box's items on the screen
 685:    */
 686:   public void showPopup()
 687:   {
 688:     setPopupVisible(true);
 689:   }
 690: 
 691:   /**
 692:    * This method hides popup containing list of combo box's items
 693:    */
 694:   public void hidePopup()
 695:   {
 696:     setPopupVisible(false);
 697:   }
 698: 
 699:   /**
 700:    * This method either displayes or hides the popup containing  list of combo
 701:    * box's items.
 702:    *
 703:    * @param visible show popup if 'visible' is true and hide it otherwise
 704:    */
 705:   public void setPopupVisible(boolean visible)
 706:   {
 707:     getUI().setPopupVisible(this, visible);
 708:   }
 709: 
 710:   /**
 711:    * Checks if popup is currently visible on the screen.
 712:    *
 713:    * @return boolean true if popup is visible and false otherwise
 714:    */
 715:   public boolean isPopupVisible()
 716:   {
 717:     return getUI().isPopupVisible(this);
 718:   }
 719: 
 720:   /**
 721:    * This method sets actionCommand to the specified string. ActionEvent fired
 722:    * to this JComboBox  registered ActionListeners will contain this
 723:    * actionCommand.
 724:    *
 725:    * @param aCommand new action command for the JComboBox's ActionEvent
 726:    */
 727:   public void setActionCommand(String aCommand)
 728:   {
 729:     actionCommand = aCommand;
 730:   }
 731: 
 732:   /**
 733:    * Returns actionCommand associated with the ActionEvent fired by the
 734:    * JComboBox to its registered ActionListeners.
 735:    *
 736:    * @return String actionCommand for the ActionEvent
 737:    */
 738:   public String getActionCommand()
 739:   {
 740:     return actionCommand;
 741:   }
 742: 
 743:   /**
 744:    * setAction
 745:    *
 746:    * @param a action to set
 747:    */
 748:   public void setAction(Action a)
 749:   {
 750:     Action old = action;
 751:     action = a;
 752:     configurePropertiesFromAction(action);
 753:     if (action != null)
 754:       // FIXME: remove from old action and add to new action 
 755:       // PropertyChangeListener to listen to changes in the action
 756:       addActionListener(action);
 757:   }
 758: 
 759:   /**
 760:    * This method returns Action that is invoked when selected item is changed
 761:    * in the JComboBox.
 762:    *
 763:    * @return Action
 764:    */
 765:   public Action getAction()
 766:   {
 767:     return action;
 768:   }
 769: 
 770:   /**
 771:    * Configure properties of the JComboBox by reading properties of specified
 772:    * action. This method always sets the comboBox's "enabled" property to the
 773:    * value of the Action's "enabled" property.
 774:    *
 775:    * @param a An Action to configure the combo box from
 776:    */
 777:   protected void configurePropertiesFromAction(Action a)
 778:   {
 779:     if (a == null)
 780:       {
 781:         setEnabled(true);
 782:         setToolTipText(null);
 783:       }
 784:     else
 785:       {
 786:         setEnabled(a.isEnabled());
 787:         setToolTipText((String) (a.getValue(Action.SHORT_DESCRIPTION)));
 788:       }
 789:   }
 790: 
 791:   /**
 792:    * Creates PropertyChangeListener to listen for the changes in comboBox's
 793:    * action properties.
 794:    *
 795:    * @param action action to listen to for property changes
 796:    *
 797:    * @return a PropertyChangeListener that listens to changes in
 798:    *         action properties.
 799:    */
 800:   protected PropertyChangeListener createActionPropertyChangeListener(Action action)
 801:   {
 802:     return new PropertyChangeListener()
 803:       {
 804:         public void propertyChange(PropertyChangeEvent e)
 805:         {
 806:           Action act = (Action) (e.getSource());
 807:           configurePropertiesFromAction(act);
 808:         }
 809:       };
 810:   }
 811: 
 812:   /**
 813:    * This method fires ItemEvent to this JComboBox's registered ItemListeners.
 814:    * This method is invoked when currently selected item in this combo box
 815:    * has changed.
 816:    *
 817:    * @param e the ItemEvent describing the change in the combo box's
 818:    *        selection.
 819:    */
 820:   protected void fireItemStateChanged(ItemEvent e)
 821:   {
 822:     ItemListener[] ll = getItemListeners();
 823: 
 824:     for (int i = 0; i < ll.length; i++)
 825:       ll[i].itemStateChanged(e);
 826:   }
 827: 
 828:   /**
 829:    * This method fires ActionEvent to this JComboBox's registered
 830:    * ActionListeners. This method is invoked when user explicitly changes
 831:    * currently selected item.
 832:    */
 833:   protected void fireActionEvent()
 834:   {
 835:     ActionListener[] ll = getActionListeners();
 836: 
 837:     for (int i = 0; i < ll.length; i++)
 838:       ll[i].actionPerformed(new ActionEvent(this,
 839:                                             ActionEvent.ACTION_PERFORMED,
 840:                                             actionCommand));
 841:   }
 842: 
 843:   /**
 844:    * Fires a popupMenuCanceled() event to all <code>PopupMenuListeners</code>.
 845:    *
 846:    * Note: This method is intended for use by plaf classes only.
 847:    */
 848:   public void firePopupMenuCanceled()
 849:   {
 850:     PopupMenuListener[] listeners = getPopupMenuListeners();
 851:     PopupMenuEvent e = new PopupMenuEvent(this);
 852:     for (int i = 0; i < listeners.length; i++)
 853:       listeners[i].popupMenuCanceled(e);
 854:   }
 855: 
 856:   /**
 857:    * Fires a popupMenuWillBecomeInvisible() event to all 
 858:    * <code>PopupMenuListeners</code>.
 859:    *
 860:    * Note: This method is intended for use by plaf classes only.
 861:    */
 862:   public void firePopupMenuWillBecomeInvisible()
 863:   {
 864:     PopupMenuListener[] listeners = getPopupMenuListeners();
 865:     PopupMenuEvent e = new PopupMenuEvent(this);
 866:     for (int i = 0; i < listeners.length; i++)
 867:       listeners[i].popupMenuWillBecomeInvisible(e);
 868:   }
 869: 
 870:   /**
 871:    * Fires a popupMenuWillBecomeVisible() event to all 
 872:    * <code>PopupMenuListeners</code>.
 873:    *
 874:    * Note: This method is intended for use by plaf classes only.
 875:    */
 876:   public void firePopupMenuWillBecomeVisible()
 877:   {
 878:     PopupMenuListener[] listeners = getPopupMenuListeners();
 879:     PopupMenuEvent e = new PopupMenuEvent(this);
 880:     for (int i = 0; i < listeners.length; i++)
 881:       listeners[i].popupMenuWillBecomeVisible(e);
 882:   }
 883: 
 884:   /**
 885:    * This method is invoked whenever selected item changes in the combo box's
 886:    * data model. It fires ItemEvent and ActionEvent to all registered
 887:    * ComboBox's ItemListeners and ActionListeners respectively, indicating
 888:    * the change.
 889:    */
 890:   protected void selectedItemChanged()
 891:   {
 892:     // Fire ItemEvent to indicated that previously selected item is now
 893:     // deselected        
 894:     if (selectedItemReminder != null)
 895:       fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED,
 896:                                          selectedItemReminder,
 897:                                          ItemEvent.DESELECTED));
 898: 
 899:     // Fire ItemEvent to indicate that new item is selected    
 900:     Object newSelection = getSelectedItem();
 901:     if (newSelection != null)
 902:       fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED,
 903:                                          newSelection, ItemEvent.SELECTED));
 904: 
 905:     // Fire Action Event to JComboBox's registered listeners                                      
 906:     fireActionEvent();
 907: 
 908:     selectedItemReminder = newSelection;
 909:   }
 910: 
 911:   /**
 912:    * Returns Object array of size 1 containing currently selected element in
 913:    * the JComboBox.
 914:    *
 915:    * @return Object[] Object array of size 1 containing currently selected
 916:    *         element in the JComboBox.
 917:    */
 918:   public Object[] getSelectedObjects()
 919:   {
 920:     return new Object[] { getSelectedItem() };
 921:   }
 922: 
 923:   /**
 924:    * This method handles actionEvents fired by the ComboBoxEditor. It changes
 925:    * this JComboBox's selection to the new value currently in the editor and
 926:    * hides list of combo box items.
 927:    *
 928:    * @param e the ActionEvent
 929:    */
 930:   public void actionPerformed(ActionEvent e)
 931:   {
 932:     setSelectedItem(getEditor().getItem());
 933:     setPopupVisible(false);
 934:   }
 935: 
 936:   /**
 937:    * This method selects item in this combo box that matches specified
 938:    * specified keyChar and returns true if such item is found. Otherwise
 939:    * false is returned.
 940:    *
 941:    * @param keyChar character indicating which item in the combo box should be
 942:    *        selected.
 943:    *
 944:    * @return boolean true if item corresponding to the specified keyChar
 945:    *         exists in the combo box. Otherwise false is returned.
 946:    */
 947:   public boolean selectWithKeyChar(char keyChar)
 948:   {
 949:     if (keySelectionManager == null)
 950:       {
 951:         keySelectionManager = createDefaultKeySelectionManager();
 952:       }
 953: 
 954:     int index = keySelectionManager.selectionForKey(keyChar, getModel());
 955:     boolean retVal = false;
 956:     if (index >= 0)
 957:       {
 958:         setSelectedIndex(index);
 959:         retVal = true;
 960:       }
 961:     return retVal;
 962:   }
 963: 
 964:   /**
 965:    * The part of implementation of ListDataListener interface. This method is
 966:    * invoked when some items where added to the JComboBox's data model.
 967:    *
 968:    * @param event ListDataEvent describing the change
 969:    */
 970:   public void intervalAdded(ListDataEvent event)
 971:   {
 972:     // FIXME: Need to implement
 973:     repaint();
 974:   }
 975: 
 976:   /**
 977:    * The part of implementation of ListDataListener interface. This method is
 978:    * invoked when some items where removed from the JComboBox's data model.
 979:    *
 980:    * @param event ListDataEvent describing the change.
 981:    */
 982:   public void intervalRemoved(ListDataEvent event)
 983:   {
 984:     // FIXME: Need to implement
 985:     repaint();
 986:   }
 987: 
 988:   /**
 989:    * The part of implementation of ListDataListener interface. This method is
 990:    * invoked when contents of the JComboBox's  data model changed.
 991:    *
 992:    * @param event ListDataEvent describing the change
 993:    */
 994:   public void contentsChanged(ListDataEvent event)
 995:   {
 996:     // if first and last index of the given ListDataEvent are both -1,
 997:     // then it indicates that selected item in the combo box data model
 998:     // have changed. 
 999:     if (event.getIndex0() == -1 && event.getIndex1() == -1)
1000:       selectedItemChanged();
1001:   }
1002: 
1003:   /**
1004:    * This method disables or enables JComboBox. If the JComboBox is enabled,
1005:    * then user is able to make item choice, otherwise if JComboBox is
1006:    * disabled then user is not able to make a selection.
1007:    *
1008:    * @param enabled if 'enabled' is true then enable JComboBox and disable it
1009:    */
1010:   public void setEnabled(boolean enabled)
1011:   {
1012:     boolean oldEnabled = super.isEnabled();
1013:     if (enabled != oldEnabled)
1014:       {
1015:         super.setEnabled(enabled);
1016:         firePropertyChange("enabled", oldEnabled, enabled);
1017:       }
1018:   }
1019: 
1020:   /**
1021:    * This method initializes specified ComboBoxEditor to display given item.
1022:    *
1023:    * @param anEditor ComboBoxEditor to initialize
1024:    * @param anItem Item that should displayed in the specified editor
1025:    */
1026:   public void configureEditor(ComboBoxEditor anEditor, Object anItem)
1027:   {
1028:     anEditor.setItem(anItem);
1029:   }
1030: 
1031:   /**
1032:    * This method is fired whenever a key is pressed with the combo box
1033:    * in focus
1034:    *
1035:    * @param e The KeyEvent indicating which key was pressed.
1036:    */
1037:   public void processKeyEvent(KeyEvent e)
1038:   {
1039:     if (e.getKeyCode() == KeyEvent.VK_TAB)
1040:       setPopupVisible(false);
1041:     else
1042:       super.processKeyEvent(e);
1043:   }
1044: 
1045:   /**
1046:    * setKeySelectionManager
1047:    *
1048:    * @param aManager
1049:    */
1050:   public void setKeySelectionManager(KeySelectionManager aManager)
1051:   {
1052:     keySelectionManager = aManager;
1053:   }
1054: 
1055:   /**
1056:    * getKeySelectionManager
1057:    *
1058:    * @return JComboBox.KeySelectionManager
1059:    */
1060:   public KeySelectionManager getKeySelectionManager()
1061:   {
1062:     return keySelectionManager;
1063:   }
1064: 
1065:   /**
1066:    * This method returns number of elements in this JComboBox
1067:    *
1068:    * @return int number of elements in this JComboBox
1069:    */
1070:   public int getItemCount()
1071:   {
1072:     return dataModel.getSize();
1073:   }
1074: 
1075:   /**
1076:    * Returns elements located in the combo box at the given index.
1077:    *
1078:    * @param index index specifying location of the component to  return.
1079:    *
1080:    * @return component in the combo box that is located in  the given index.
1081:    */
1082:   public Object getItemAt(int index)
1083:   {
1084:     return dataModel.getElementAt(index);
1085:   }
1086: 
1087:   /**
1088:    * createDefaultKeySelectionManager
1089:    *
1090:    * @return KeySelectionManager
1091:    */
1092:   protected KeySelectionManager createDefaultKeySelectionManager()
1093:   {
1094:     return new DefaultKeySelectionManager();
1095:   }
1096: 
1097:   /**
1098:    * Returns an implementation-dependent string describing the attributes of
1099:    * this <code>JComboBox</code>.
1100:    *
1101:    * @return A string describing the attributes of this <code>JComboBox</code>
1102:    *         (never <code>null</code>).
1103:    */
1104:   protected String paramString()
1105:   {
1106:     String superParamStr = super.paramString();
1107:     StringBuffer sb = new StringBuffer();
1108:     sb.append(",isEditable=").append(isEditable());
1109:     sb.append(",lightWeightPopupEnabled=").append(isLightWeightPopupEnabled());
1110:     sb.append(",maximumRowCount=").append(getMaximumRowCount());
1111:     
1112:     sb.append(",selectedItemReminder=");
1113:     if (selectedItemReminder != null)
1114:       sb.append(selectedItemReminder);
1115:     return superParamStr + sb.toString();
1116:   }
1117: 
1118:   /**
1119:    * Returns the object that provides accessibility features for this
1120:    * <code>JComboBox</code> component.
1121:    *
1122:    * @return The accessible context (an instance of 
1123:    *         {@link AccessibleJComboBox}).
1124:    */
1125:   public AccessibleContext getAccessibleContext()
1126:   {
1127:     if (accessibleContext == null)
1128:       accessibleContext = new AccessibleJComboBox();
1129: 
1130:     return accessibleContext;
1131:   }
1132: 
1133:   /**
1134:    * This methods adds specified ActionListener to this JComboBox.
1135:    *
1136:    * @param listener to add
1137:    */
1138:   public void addActionListener(ActionListener listener)
1139:   {
1140:     listenerList.add(ActionListener.class, listener);
1141:   }
1142: 
1143:   /**
1144:    * This method removes specified ActionListener from this JComboBox.
1145:    *
1146:    * @param listener ActionListener
1147:    */
1148:   public void removeActionListener(ActionListener listener)
1149:   {
1150:     listenerList.remove(ActionListener.class, listener);
1151:   }
1152: 
1153:   /**
1154:    * This method returns array of ActionListeners that are registered with
1155:    * this JComboBox.
1156:    *
1157:    * @since 1.4
1158:    */
1159:   public ActionListener[] getActionListeners()
1160:   {
1161:     return (ActionListener[]) getListeners(ActionListener.class);
1162:   }
1163: 
1164:   /**
1165:    * This method registers given ItemListener with this JComboBox
1166:    *
1167:    * @param listener to remove
1168:    */
1169:   public void addItemListener(ItemListener listener)
1170:   {
1171:     listenerList.add(ItemListener.class, listener);
1172:   }
1173: 
1174:   /**
1175:    * This method unregisters given ItemListener from this JComboBox
1176:    *
1177:    * @param listener to remove
1178:    */
1179:   public void removeItemListener(ItemListener listener)
1180:   {
1181:     listenerList.remove(ItemListener.class, listener);
1182:   }
1183: 
1184:   /**
1185:    * This method returns array of ItemListeners that are registered with this
1186:    * JComboBox.
1187:    *
1188:    * @since 1.4
1189:    */
1190:   public ItemListener[] getItemListeners()
1191:   {
1192:     return (ItemListener[]) getListeners(ItemListener.class);
1193:   }
1194: 
1195:   /**
1196:    * Adds PopupMenuListener to combo box to listen to the events fired by the
1197:    * combo box's popup menu containing its list of items
1198:    *
1199:    * @param listener to add
1200:    */
1201:   public void addPopupMenuListener(PopupMenuListener listener)
1202:   {
1203:     listenerList.add(PopupMenuListener.class, listener);
1204:   }
1205: 
1206:   /**
1207:    * Removes PopupMenuListener to combo box to listen to the events fired by
1208:    * the combo box's popup menu containing its list of items
1209:    *
1210:    * @param listener to add
1211:    */
1212:   public void removePopupMenuListener(PopupMenuListener listener)
1213:   {
1214:     listenerList.remove(PopupMenuListener.class, listener);
1215:   }
1216: 
1217:   /**
1218:    * Returns array of PopupMenuListeners that are registered with  combo box.
1219:    */
1220:   public PopupMenuListener[] getPopupMenuListeners()
1221:   {
1222:     return (PopupMenuListener[]) getListeners(PopupMenuListener.class);
1223:   }
1224: 
1225:   /**
1226:    * Accessibility support for <code>JComboBox</code>.
1227:    */
1228:   protected class AccessibleJComboBox extends AccessibleJComponent
1229:     implements AccessibleAction, AccessibleSelection
1230:   {
1231:     private static final long serialVersionUID = 8217828307256675666L;
1232: 
1233:     /**
1234:      * @specnote This constructor was protected in 1.4, but made public
1235:      * in 1.5.
1236:      */
1237:     public AccessibleJComboBox()
1238:     {
1239:       // Nothing to do here.
1240:     }
1241: 
1242:     /**
1243:      * Returns the number of accessible children of this object. The
1244:      * implementation of AccessibleJComboBox delegates this call to the UI
1245:      * of the associated JComboBox.
1246:      *
1247:      * @return the number of accessible children of this object
1248:      *
1249:      * @see ComponentUI#getAccessibleChildrenCount(JComponent)
1250:      */
1251:     public int getAccessibleChildrenCount()
1252:     {
1253:       ComponentUI ui = getUI();
1254:       int count;
1255:       if (ui != null)
1256:         count = ui.getAccessibleChildrenCount(JComboBox.this);
1257:       else
1258:         count = super.getAccessibleChildrenCount();
1259:       return count;
1260:     }
1261: 
1262:     /**
1263:      * Returns the number of accessible children of this object. The
1264:      * implementation of AccessibleJComboBox delegates this call to the UI
1265:      * of the associated JComboBox.
1266:      *
1267:      * @param index the index of the accessible child to fetch
1268:      *
1269:      * @return the number of accessible children of this object
1270:      *
1271:      * @see ComponentUI#getAccessibleChild(JComponent, int)
1272:      */
1273:     public Accessible getAccessibleChild(int index)
1274:     {
1275:       ComponentUI ui = getUI();
1276:       Accessible child = null;
1277:       if (ui != null)
1278:         child = ui.getAccessibleChild(JComboBox.this, index);
1279:       else
1280:         child = super.getAccessibleChild(index);
1281:       return child;
1282:     }
1283: 
1284:     /**
1285:      * Returns the AccessibleSelection object associated with this object.
1286:      * AccessibleJComboBoxes handle their selection themselves, so this
1287:      * always returns <code>this</code>.
1288:      *
1289:      * @return the AccessibleSelection object associated with this object
1290:      */
1291:     public AccessibleSelection getAccessibleSelection()
1292:     {
1293:       return this;
1294:     }
1295: 
1296:     /**
1297:      * Returns the accessible selection from this AccssibleJComboBox.
1298:      *
1299:      * @param index the index of the selected child to fetch
1300:      *
1301:      * @return the accessible selection from this AccssibleJComboBox
1302:      */
1303:     public Accessible getAccessibleSelection(int index)
1304:     {
1305:       // Get hold of the actual popup.
1306:       Accessible popup = getUI().getAccessibleChild(JComboBox.this, 0);
1307:       Accessible selected = null;
1308:       if (popup != null && popup instanceof ComboPopup)
1309:         {
1310:           ComboPopup cPopup = (ComboPopup) popup;
1311:           // Query the list for the currently selected child.
1312:           JList l = cPopup.getList();
1313:           AccessibleContext listCtx = l.getAccessibleContext();
1314:           if (listCtx != null)
1315:             {
1316:               AccessibleSelection s = listCtx.getAccessibleSelection();
1317:               if (s != null)
1318:                 {
1319:                   selected = s.getAccessibleSelection(index);
1320:                 }
1321:             }
1322:         }
1323:       return selected;
1324:     }
1325: 
1326:     /**
1327:      * Returns <code>true</code> if the accessible child with the specified
1328:      * <code>index</code> is selected, <code>false</code> otherwise.
1329:      *
1330:      * @param index the index of the accessible child
1331:      *
1332:      * @return <code>true</code> if the accessible child with the specified
1333:      *         <code>index</code> is selected, <code>false</code> otherwise
1334:      */
1335:     public boolean isAccessibleChildSelected(int index)
1336:     {
1337:       return getSelectedIndex() == index;
1338:     }
1339: 
1340:     /**
1341:      * Returns the accessible role for the <code>JComboBox</code> component.
1342:      *
1343:      * @return {@link AccessibleRole#COMBO_BOX}.
1344:      */
1345:     public AccessibleRole getAccessibleRole()
1346:     {
1347:       return AccessibleRole.COMBO_BOX;
1348:     }
1349: 
1350:     /**
1351:      * Returns the accessible action associated to this accessible object.
1352:      * AccessibleJComboBox implements its own AccessibleAction, so this
1353:      * method returns <code>this</code>.
1354:      *
1355:      * @return the accessible action associated to this accessible object
1356:      */
1357:     public AccessibleAction getAccessibleAction()
1358:     {
1359:       return this;
1360:     }
1361: 
1362:     /**
1363:      * Returns the description of the specified action. AccessibleJComboBox
1364:      * implements 1 action (toggle the popup menu) and thus returns
1365:      * <code>UIManager.getString("ComboBox.togglePopupText")</code>
1366:      *
1367:      * @param actionIndex the index of the action for which to return the
1368:      *        description
1369:      *
1370:      * @return the description of the specified action
1371:      */
1372:     public String getAccessibleActionDescription(int actionIndex)
1373:     {
1374:       return UIManager.getString("ComboBox.togglePopupText");
1375:     }
1376: 
1377:     /**
1378:      * Returns the number of accessible actions that can be performed by
1379:      * this object. AccessibleJComboBox implement s one accessible action
1380:      * (toggle the popup menu), so this method always returns <code>1</code>.
1381:      *
1382:      * @return the number of accessible actions that can be performed by
1383:      *         this object
1384:      */
1385:     public int getAccessibleActionCount()
1386:     {
1387:       return 1;
1388:     }
1389: 
1390:     /**
1391:      * Performs the accessible action with the specified index.
1392:      * AccessibleJComboBox has 1 accessible action
1393:      * (<code>actionIndex == 0</code>), which is to toggle the
1394:      * popup menu. All other action indices have no effect and return
1395:      * <code<>false</code>.
1396:      *
1397:      * @param actionIndex the index of the action to perform
1398:      *
1399:      * @return <code>true</code> if the action has been performed,
1400:      *         <code>false</code> otherwise
1401:      */
1402:     public boolean doAccessibleAction(int actionIndex)
1403:     {
1404:       boolean actionPerformed = false;
1405:       if (actionIndex == 0)
1406:         {
1407:           setPopupVisible(! isPopupVisible());
1408:           actionPerformed = true;
1409:         }
1410:       return actionPerformed;
1411:     }
1412: 
1413:     /**
1414:      * Returns the number of selected accessible children of this object. This
1415:      * returns <code>1</code> if the combobox has a selected entry,
1416:      * <code>0</code> otherwise.
1417:      *
1418:      * @return the number of selected accessible children of this object
1419:      */
1420:     public int getAccessibleSelectionCount()
1421:     {
1422:       Object sel = getSelectedItem();
1423:       int count = 0;
1424:       if (sel != null)
1425:         count = 1;
1426:       return count;
1427:     }
1428: 
1429:     /**
1430:      * Sets the current selection to the specified <code>index</code>.
1431:      *
1432:      * @param index the index to set as selection
1433:      */
1434:     public void addAccessibleSelection(int index)
1435:     {
1436:       setSelectedIndex(index);
1437:     }
1438: 
1439:     /**
1440:      * Removes the specified index from the current selection.
1441:      *
1442:      * @param index the index to remove from the selection
1443:      */
1444:     public void removeAccessibleSelection(int index)
1445:     {
1446:       if (getSelectedIndex() == index)
1447:         clearAccessibleSelection();
1448:     }
1449: 
1450:     /**
1451:      * Clears the current selection.
1452:      */
1453:     public void clearAccessibleSelection()
1454:     {
1455:       setSelectedIndex(-1);
1456:     }
1457: 
1458:     /**
1459:      * Multiple selection is not supported by AccessibleJComboBox, so this
1460:      * does nothing.
1461:      */
1462:     public void selectAllAccessibleSelection()
1463:     {
1464:       // Nothing to do here.
1465:     }
1466:   }
1467:   
1468:   private class DefaultKeySelectionManager
1469:       implements KeySelectionManager
1470:   {
1471: 
1472:     public int selectionForKey(char aKey, ComboBoxModel aModel)
1473:     {
1474:       int selectedIndex = getSelectedIndex();
1475: 
1476:       // Start at currently selected item and iterate to end of list
1477:       for (int i = selectedIndex + 1; i < aModel.getSize(); i++)
1478:         {
1479:           String nextItem = aModel.getElementAt(i).toString();
1480: 
1481:           if (nextItem.charAt(0) == aKey)
1482:             return i;
1483:         }
1484: 
1485:       // Wrap to start of list if no match yet
1486:       for (int i = 0; i <= selectedIndex; i++)
1487:         {
1488:           String nextItem = aModel.getElementAt(i).toString();
1489: 
1490:           if (nextItem.charAt(0) == aKey)
1491:             return i;
1492:         }
1493: 
1494:       return - 1;
1495:     }
1496:   }
1497: }