Source for javax.swing.JComboBox

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