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