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