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 { selectionForKey(char aKey, ComboBoxModel aModel)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 */ JComboBox(ComboBoxModel model)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 */ JComboBox(Object[] itemArray)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 */ JComboBox(Vector itemVector)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 */ JComboBox()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 */ isEditable()219 public boolean isEditable() 220 { 221 return isEditable; 222 } 223 224 /* 225 * This method adds ancestor listener to this JComboBox. 226 */ installAncestorListener()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 */ setUI(ComboBoxUI ui)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 */ updateUI()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 */ getUIClassID()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 */ getUI()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 */ setModel(ComboBoxModel newDataModel)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 */ getModel()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 */ setLightWeightPopupEnabled(boolean enabled)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 */ isLightWeightPopupEnabled()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 */ setEditable(boolean editable)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 */ setMaximumRowCount(int rowCount)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 */ getMaximumRowCount()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 */ setRenderer(ListCellRenderer aRenderer)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 */ getRenderer()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 */ setEditor(ComboBoxEditor newEditor)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 */ getEditor()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 */ setSelectedItem(Object item)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 */ getSelectedItem()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 */ setSelectedIndex(int index)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 */ getSelectedIndex()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 */ getPrototypeDisplayValue()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 */ setPrototypeDisplayValue(Object value)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 */ addItem(Object element)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 */ insertItemAt(Object element, int index)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 */ removeItem(Object element)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 */ removeItemAt(int index)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 */ removeAllItems()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 */ showPopup()684 public void showPopup() 685 { 686 setPopupVisible(true); 687 } 688 689 /** 690 * This method hides popup containing list of combo box's items 691 */ hidePopup()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 */ setPopupVisible(boolean visible)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 */ isPopupVisible()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 */ setActionCommand(String aCommand)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 */ getActionCommand()736 public String getActionCommand() 737 { 738 return actionCommand; 739 } 740 741 /** 742 * setAction 743 * 744 * @param a action to set 745 */ setAction(Action a)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 */ getAction()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 */ configurePropertiesFromAction(Action a)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 */ createActionPropertyChangeListener(Action action)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 } 1291