1 /* 2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javax.swing; 26 27 import java.beans.PropertyChangeEvent; 28 import java.beans.PropertyChangeListener; 29 import java.beans.Transient; 30 import java.util.*; 31 32 import java.awt.*; 33 import java.awt.event.*; 34 35 import java.io.Serializable; 36 import java.io.ObjectOutputStream; 37 import java.io.IOException; 38 39 import javax.swing.event.*; 40 import javax.swing.plaf.*; 41 42 import javax.accessibility.*; 43 44 /** 45 * A component that combines a button or editable field and a drop-down list. 46 * The user can select a value from the drop-down list, which appears at the 47 * user's request. If you make the combo box editable, then the combo box 48 * includes an editable field into which the user can type a value. 49 * <p> 50 * <strong>Warning:</strong> Swing is not thread safe. For more 51 * information see <a 52 * href="package-summary.html#threading">Swing's Threading 53 * Policy</a>. 54 * <p> 55 * <strong>Warning:</strong> 56 * Serialized objects of this class will not be compatible with 57 * future Swing releases. The current serialization support is 58 * appropriate for short term storage or RMI between applications running 59 * the same version of Swing. As of 1.4, support for long term storage 60 * of all JavaBeans™ 61 * has been added to the <code>java.beans</code> package. 62 * Please see {@link java.beans.XMLEncoder}. 63 * 64 * <p> 65 * See <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html">How to Use Combo Boxes</a> 66 * in <a href="http://docs.oracle.com/javase/tutorial/"><em>The Java Tutorial</em></a> 67 * for further information. 68 * 69 * @see ComboBoxModel 70 * @see DefaultComboBoxModel 71 * 72 * @param <E> the type of the elements of this combo box 73 * 74 * @beaninfo 75 * attribute: isContainer false 76 * description: A combination of a text field and a drop-down list. 77 * 78 * @author Arnaud Weber 79 * @author Mark Davidson 80 * @since 1.2 81 */ 82 @SuppressWarnings("serial") // Same-version serialization only 83 public class JComboBox<E> extends JComponent 84 implements ItemSelectable,ListDataListener,ActionListener, Accessible { 85 /** 86 * @see #getUIClassID 87 * @see #readObject 88 */ 89 private static final String uiClassID = "ComboBoxUI"; 90 91 /** 92 * This protected field is implementation specific. Do not access directly 93 * or override. Use the accessor methods instead. 94 * 95 * @see #getModel 96 * @see #setModel 97 */ 98 protected ComboBoxModel<E> dataModel; 99 /** 100 * This protected field is implementation specific. Do not access directly 101 * or override. Use the accessor methods instead. 102 * 103 * @see #getRenderer 104 * @see #setRenderer 105 */ 106 protected ListCellRenderer<? super E> renderer; 107 /** 108 * This protected field is implementation specific. Do not access directly 109 * or override. Use the accessor methods instead. 110 * 111 * @see #getEditor 112 * @see #setEditor 113 */ 114 protected ComboBoxEditor editor; 115 /** 116 * This protected field is implementation specific. Do not access directly 117 * or override. Use the accessor methods instead. 118 * 119 * @see #getMaximumRowCount 120 * @see #setMaximumRowCount 121 */ 122 protected int maximumRowCount = 8; 123 124 /** 125 * This protected field is implementation specific. Do not access directly 126 * or override. Use the accessor methods instead. 127 * 128 * @see #isEditable 129 * @see #setEditable 130 */ 131 protected boolean isEditable = false; 132 /** 133 * This protected field is implementation specific. Do not access directly 134 * or override. Use the accessor methods instead. 135 * 136 * @see #setKeySelectionManager 137 * @see #getKeySelectionManager 138 */ 139 protected KeySelectionManager keySelectionManager = null; 140 /** 141 * This protected field is implementation specific. Do not access directly 142 * or override. Use the accessor methods instead. 143 * 144 * @see #setActionCommand 145 * @see #getActionCommand 146 */ 147 protected String actionCommand = "comboBoxChanged"; 148 /** 149 * This protected field is implementation specific. Do not access directly 150 * or override. Use the accessor methods instead. 151 * 152 * @see #setLightWeightPopupEnabled 153 * @see #isLightWeightPopupEnabled 154 */ 155 protected boolean lightWeightPopupEnabled = JPopupMenu.getDefaultLightWeightPopupEnabled(); 156 157 /** 158 * This protected field is implementation specific. Do not access directly 159 * or override. 160 */ 161 protected Object selectedItemReminder = null; 162 163 private E prototypeDisplayValue; 164 165 // Flag to ensure that infinite loops do not occur with ActionEvents. 166 private boolean firingActionEvent = false; 167 168 // Flag to ensure the we don't get multiple ActionEvents on item selection. 169 private boolean selectingItem = false; 170 171 /** 172 * Creates a <code>JComboBox</code> that takes its items from an 173 * existing <code>ComboBoxModel</code>. Since the 174 * <code>ComboBoxModel</code> is provided, a combo box created using 175 * this constructor does not create a default combo box model and 176 * may impact how the insert, remove and add methods behave. 177 * 178 * @param aModel the <code>ComboBoxModel</code> that provides the 179 * displayed list of items 180 * @see DefaultComboBoxModel 181 */ 182 public JComboBox(ComboBoxModel<E> aModel) { 183 super(); 184 setModel(aModel); 185 init(); 186 } 187 188 /** 189 * Creates a <code>JComboBox</code> that contains the elements 190 * in the specified array. By default the first item in the array 191 * (and therefore the data model) becomes selected. 192 * 193 * @param items an array of objects to insert into the combo box 194 * @see DefaultComboBoxModel 195 */ 196 public JComboBox(E[] items) { 197 super(); 198 setModel(new DefaultComboBoxModel<E>(items)); 199 init(); 200 } 201 202 /** 203 * Creates a <code>JComboBox</code> that contains the elements 204 * in the specified Vector. By default the first item in the vector 205 * (and therefore the data model) becomes selected. 206 * 207 * @param items an array of vectors to insert into the combo box 208 * @see DefaultComboBoxModel 209 */ 210 public JComboBox(Vector<E> items) { 211 super(); 212 setModel(new DefaultComboBoxModel<E>(items)); 213 init(); 214 } 215 216 /** 217 * Creates a <code>JComboBox</code> with a default data model. 218 * The default data model is an empty list of objects. 219 * Use <code>addItem</code> to add items. By default the first item 220 * in the data model becomes selected. 221 * 222 * @see DefaultComboBoxModel 223 */ 224 public JComboBox() { 225 super(); 226 setModel(new DefaultComboBoxModel<E>()); 227 init(); 228 } 229 230 private void init() { 231 installAncestorListener(); 232 setUIProperty("opaque",true); 233 updateUI(); 234 } 235 236 /** 237 * Registers ancestor listener so that it will receive 238 * {@code AncestorEvents} when it or any of its ancestors 239 * move or are made visible or invisible. 240 * Events are also sent when the component or its ancestors are added 241 * or removed from the containment hierarchy. 242 */ 243 protected void installAncestorListener() { 244 addAncestorListener(new AncestorListener(){ 245 public void ancestorAdded(AncestorEvent event){ hidePopup();} 246 public void ancestorRemoved(AncestorEvent event){ hidePopup();} 247 public void ancestorMoved(AncestorEvent event){ 248 if (event.getSource() != JComboBox.this) 249 hidePopup(); 250 }}); 251 } 252 253 /** 254 * Sets the L&F object that renders this component. 255 * 256 * @param ui the <code>ComboBoxUI</code> L&F object 257 * @see UIDefaults#getUI 258 * 259 * @beaninfo 260 * bound: true 261 * hidden: true 262 * attribute: visualUpdate true 263 * description: The UI object that implements the Component's LookAndFeel. 264 */ 265 public void setUI(ComboBoxUI ui) { 266 super.setUI(ui); 267 } 268 269 /** 270 * Resets the UI property to a value from the current look and feel. 271 * 272 * @see JComponent#updateUI 273 */ 274 public void updateUI() { 275 setUI((ComboBoxUI)UIManager.getUI(this)); 276 277 ListCellRenderer<? super E> renderer = getRenderer(); 278 if (renderer instanceof Component) { 279 SwingUtilities.updateComponentTreeUI((Component)renderer); 280 } 281 } 282 283 284 /** 285 * Returns the name of the L&F class that renders this component. 286 * 287 * @return the string "ComboBoxUI" 288 * @see JComponent#getUIClassID 289 * @see UIDefaults#getUI 290 */ 291 public String getUIClassID() { 292 return uiClassID; 293 } 294 295 296 /** 297 * Returns the L&F object that renders this component. 298 * 299 * @return the ComboBoxUI object that renders this component 300 */ 301 public ComboBoxUI getUI() { 302 return(ComboBoxUI)ui; 303 } 304 305 /** 306 * Sets the data model that the <code>JComboBox</code> uses to obtain 307 * the list of items. 308 * 309 * @param aModel the <code>ComboBoxModel</code> that provides the 310 * displayed list of items 311 * 312 * @beaninfo 313 * bound: true 314 * description: Model that the combo box uses to get data to display. 315 */ 316 public void setModel(ComboBoxModel<E> aModel) { 317 ComboBoxModel<E> oldModel = dataModel; 318 if (oldModel != null) { 319 oldModel.removeListDataListener(this); 320 } 321 dataModel = aModel; 322 dataModel.addListDataListener(this); 323 324 // set the current selected item. 325 selectedItemReminder = dataModel.getSelectedItem(); 326 327 firePropertyChange( "model", oldModel, dataModel); 328 } 329 330 /** 331 * Returns the data model currently used by the <code>JComboBox</code>. 332 * 333 * @return the <code>ComboBoxModel</code> that provides the displayed 334 * list of items 335 */ 336 public ComboBoxModel<E> getModel() { 337 return dataModel; 338 } 339 340 /* 341 * Properties 342 */ 343 344 /** 345 * Sets the <code>lightWeightPopupEnabled</code> property, which 346 * provides a hint as to whether or not a lightweight 347 * <code>Component</code> should be used to contain the 348 * <code>JComboBox</code>, versus a heavyweight 349 * <code>Component</code> such as a <code>Panel</code> 350 * or a <code>Window</code>. The decision of lightweight 351 * versus heavyweight is ultimately up to the 352 * <code>JComboBox</code>. Lightweight windows are more 353 * efficient than heavyweight windows, but lightweight 354 * and heavyweight components do not mix well in a GUI. 355 * If your application mixes lightweight and heavyweight 356 * components, you should disable lightweight popups. 357 * The default value for the <code>lightWeightPopupEnabled</code> 358 * property is <code>true</code>, unless otherwise specified 359 * by the look and feel. Some look and feels always use 360 * heavyweight popups, no matter what the value of this property. 361 * <p> 362 * See the article <a href="http://www.oracle.com/technetwork/articles/java/mixing-components-433992.html">Mixing Heavy and Light Components</a> 363 * This method fires a property changed event. 364 * 365 * @param aFlag if <code>true</code>, lightweight popups are desired 366 * 367 * @beaninfo 368 * bound: true 369 * expert: true 370 * description: Set to <code>false</code> to require heavyweight popups. 371 */ 372 public void setLightWeightPopupEnabled(boolean aFlag) { 373 boolean oldFlag = lightWeightPopupEnabled; 374 lightWeightPopupEnabled = aFlag; 375 firePropertyChange("lightWeightPopupEnabled", oldFlag, lightWeightPopupEnabled); 376 } 377 378 /** 379 * Gets the value of the <code>lightWeightPopupEnabled</code> 380 * property. 381 * 382 * @return the value of the <code>lightWeightPopupEnabled</code> 383 * property 384 * @see #setLightWeightPopupEnabled 385 */ 386 public boolean isLightWeightPopupEnabled() { 387 return lightWeightPopupEnabled; 388 } 389 390 /** 391 * Determines whether the <code>JComboBox</code> field is editable. 392 * An editable <code>JComboBox</code> allows the user to type into the 393 * field or selected an item from the list to initialize the field, 394 * after which it can be edited. (The editing affects only the field, 395 * the list item remains intact.) A non editable <code>JComboBox</code> 396 * displays the selected item in the field, 397 * but the selection cannot be modified. 398 * 399 * @param aFlag a boolean value, where true indicates that the 400 * field is editable 401 * 402 * @beaninfo 403 * bound: true 404 * preferred: true 405 * description: If true, the user can type a new value in the combo box. 406 */ 407 public void setEditable(boolean aFlag) { 408 boolean oldFlag = isEditable; 409 isEditable = aFlag; 410 firePropertyChange( "editable", oldFlag, isEditable ); 411 } 412 413 /** 414 * Returns true if the <code>JComboBox</code> is editable. 415 * By default, a combo box is not editable. 416 * 417 * @return true if the <code>JComboBox</code> is editable, else false 418 */ 419 public boolean isEditable() { 420 return isEditable; 421 } 422 423 /** 424 * Sets the maximum number of rows the <code>JComboBox</code> displays. 425 * If the number of objects in the model is greater than count, 426 * the combo box uses a scrollbar. 427 * 428 * @param count an integer specifying the maximum number of items to 429 * display in the list before using a scrollbar 430 * @beaninfo 431 * bound: true 432 * preferred: true 433 * description: The maximum number of rows the popup should have 434 */ 435 public void setMaximumRowCount(int count) { 436 int oldCount = maximumRowCount; 437 maximumRowCount = count; 438 firePropertyChange( "maximumRowCount", oldCount, maximumRowCount ); 439 } 440 441 /** 442 * Returns the maximum number of items the combo box can display 443 * without a scrollbar 444 * 445 * @return an integer specifying the maximum number of items that are 446 * displayed in the list before using a scrollbar 447 */ 448 public int getMaximumRowCount() { 449 return maximumRowCount; 450 } 451 452 /** 453 * Sets the renderer that paints the list items and the item selected from the list in 454 * the JComboBox field. The renderer is used if the JComboBox is not 455 * editable. If it is editable, the editor is used to render and edit 456 * the selected item. 457 * <p> 458 * The default renderer displays a string or an icon. 459 * Other renderers can handle graphic images and composite items. 460 * <p> 461 * To display the selected item, 462 * <code>aRenderer.getListCellRendererComponent</code> 463 * is called, passing the list object and an index of -1. 464 * 465 * @param aRenderer the <code>ListCellRenderer</code> that 466 * displays the selected item 467 * @see #setEditor 468 * @beaninfo 469 * bound: true 470 * expert: true 471 * description: The renderer that paints the item selected in the list. 472 */ 473 public void setRenderer(ListCellRenderer<? super E> aRenderer) { 474 ListCellRenderer<? super E> oldRenderer = renderer; 475 renderer = aRenderer; 476 firePropertyChange( "renderer", oldRenderer, renderer ); 477 invalidate(); 478 } 479 480 /** 481 * Returns the renderer used to display the selected item in the 482 * <code>JComboBox</code> field. 483 * 484 * @return the <code>ListCellRenderer</code> that displays 485 * the selected item. 486 */ 487 public ListCellRenderer<? super E> getRenderer() { 488 return renderer; 489 } 490 491 /** 492 * Sets the editor used to paint and edit the selected item in the 493 * <code>JComboBox</code> field. The editor is used only if the 494 * receiving <code>JComboBox</code> is editable. If not editable, 495 * the combo box uses the renderer to paint the selected item. 496 * 497 * @param anEditor the <code>ComboBoxEditor</code> that 498 * displays the selected item 499 * @see #setRenderer 500 * @beaninfo 501 * bound: true 502 * expert: true 503 * description: The editor that combo box uses to edit the current value 504 */ 505 public void setEditor(ComboBoxEditor anEditor) { 506 ComboBoxEditor oldEditor = editor; 507 508 if ( editor != null ) { 509 editor.removeActionListener(this); 510 } 511 editor = anEditor; 512 if ( editor != null ) { 513 editor.addActionListener(this); 514 } 515 firePropertyChange( "editor", oldEditor, editor ); 516 } 517 518 /** 519 * Returns the editor used to paint and edit the selected item in the 520 * <code>JComboBox</code> field. 521 * 522 * @return the <code>ComboBoxEditor</code> that displays the selected item 523 */ 524 public ComboBoxEditor getEditor() { 525 return editor; 526 } 527 528 // 529 // Selection 530 // 531 532 /** 533 * Sets the selected item in the combo box display area to the object in 534 * the argument. 535 * If <code>anObject</code> is in the list, the display area shows 536 * <code>anObject</code> selected. 537 * <p> 538 * If <code>anObject</code> is <i>not</i> in the list and the combo box is 539 * uneditable, it will not change the current selection. For editable 540 * combo boxes, the selection will change to <code>anObject</code>. 541 * <p> 542 * If this constitutes a change in the selected item, 543 * <code>ItemListener</code>s added to the combo box will be notified with 544 * one or two <code>ItemEvent</code>s. 545 * If there is a current selected item, an <code>ItemEvent</code> will be 546 * fired and the state change will be <code>ItemEvent.DESELECTED</code>. 547 * If <code>anObject</code> is in the list and is not currently selected 548 * then an <code>ItemEvent</code> will be fired and the state change will 549 * be <code>ItemEvent.SELECTED</code>. 550 * <p> 551 * <code>ActionListener</code>s added to the combo box will be notified 552 * with an <code>ActionEvent</code> when this method is called. 553 * 554 * @param anObject the list object to select; use <code>null</code> to 555 clear the selection 556 * @beaninfo 557 * preferred: true 558 * description: Sets the selected item in the JComboBox. 559 */ 560 public void setSelectedItem(Object anObject) { 561 Object oldSelection = selectedItemReminder; 562 Object objectToSelect = anObject; 563 if (oldSelection == null || !oldSelection.equals(anObject)) { 564 565 if (anObject != null && !isEditable()) { 566 // For non editable combo boxes, an invalid selection 567 // will be rejected. 568 boolean found = false; 569 for (int i = 0; i < dataModel.getSize(); i++) { 570 E element = dataModel.getElementAt(i); 571 if (anObject.equals(element)) { 572 found = true; 573 objectToSelect = element; 574 break; 575 } 576 } 577 if (!found) { 578 return; 579 } 580 581 getEditor().setItem(anObject); 582 } 583 584 // Must toggle the state of this flag since this method 585 // call may result in ListDataEvents being fired. 586 selectingItem = true; 587 dataModel.setSelectedItem(objectToSelect); 588 selectingItem = false; 589 590 if (selectedItemReminder != dataModel.getSelectedItem()) { 591 // in case a users implementation of ComboBoxModel 592 // doesn't fire a ListDataEvent when the selection 593 // changes. 594 selectedItemChanged(); 595 } 596 } 597 fireActionEvent(); 598 } 599 600 /** 601 * Returns the current selected item. 602 * <p> 603 * If the combo box is editable, then this value may not have been added 604 * to the combo box with <code>addItem</code>, <code>insertItemAt</code> 605 * or the data constructors. 606 * 607 * @return the current selected Object 608 * @see #setSelectedItem 609 */ 610 public Object getSelectedItem() { 611 return dataModel.getSelectedItem(); 612 } 613 614 /** 615 * Selects the item at index <code>anIndex</code>. 616 * 617 * @param anIndex an integer specifying the list item to select, 618 * where 0 specifies the first item in the list and -1 indicates no selection 619 * @exception IllegalArgumentException if <code>anIndex</code> < -1 or 620 * <code>anIndex</code> is greater than or equal to size 621 * @beaninfo 622 * preferred: true 623 * description: The item at index is selected. 624 */ 625 public void setSelectedIndex(int anIndex) { 626 int size = dataModel.getSize(); 627 628 if ( anIndex == -1 ) { 629 setSelectedItem( null ); 630 } else if ( anIndex < -1 || anIndex >= size ) { 631 throw new IllegalArgumentException("setSelectedIndex: " + anIndex + " out of bounds"); 632 } else { 633 setSelectedItem(dataModel.getElementAt(anIndex)); 634 } 635 } 636 637 /** 638 * Returns the first item in the list that matches the given item. 639 * The result is not always defined if the <code>JComboBox</code> 640 * allows selected items that are not in the list. 641 * Returns -1 if there is no selected item or if the user specified 642 * an item which is not in the list. 643 644 * @return an integer specifying the currently selected list item, 645 * where 0 specifies 646 * the first item in the list; 647 * or -1 if no item is selected or if 648 * the currently selected item is not in the list 649 */ 650 @Transient 651 public int getSelectedIndex() { 652 Object sObject = dataModel.getSelectedItem(); 653 int i,c; 654 E obj; 655 656 for ( i=0,c=dataModel.getSize();i<c;i++ ) { 657 obj = dataModel.getElementAt(i); 658 if ( obj != null && obj.equals(sObject) ) 659 return i; 660 } 661 return -1; 662 } 663 664 /** 665 * Returns the "prototypical display" value - an Object used 666 * for the calculation of the display height and width. 667 * 668 * @return the value of the <code>prototypeDisplayValue</code> property 669 * @see #setPrototypeDisplayValue 670 * @since 1.4 671 */ 672 public E getPrototypeDisplayValue() { 673 return prototypeDisplayValue; 674 } 675 676 /** 677 * Sets the prototype display value used to calculate the size of the display 678 * for the UI portion. 679 * <p> 680 * If a prototype display value is specified, the preferred size of 681 * the combo box is calculated by configuring the renderer with the 682 * prototype display value and obtaining its preferred size. Specifying 683 * the preferred display value is often useful when the combo box will be 684 * displaying large amounts of data. If no prototype display value has 685 * been specified, the renderer must be configured for each value from 686 * the model and its preferred size obtained, which can be 687 * relatively expensive. 688 * 689 * @param prototypeDisplayValue the prototype display value 690 * @see #getPrototypeDisplayValue 691 * @since 1.4 692 * @beaninfo 693 * bound: true 694 * attribute: visualUpdate true 695 * description: The display prototype value, used to compute display width and height. 696 */ 697 public void setPrototypeDisplayValue(E prototypeDisplayValue) { 698 Object oldValue = this.prototypeDisplayValue; 699 this.prototypeDisplayValue = prototypeDisplayValue; 700 firePropertyChange("prototypeDisplayValue", oldValue, prototypeDisplayValue); 701 } 702 703 /** 704 * Adds an item to the item list. 705 * This method works only if the <code>JComboBox</code> uses a 706 * mutable data model. 707 * <p> 708 * <strong>Warning:</strong> 709 * Focus and keyboard navigation problems may arise if you add duplicate 710 * String objects. A workaround is to add new objects instead of String 711 * objects and make sure that the toString() method is defined. 712 * For example: 713 * <pre> 714 * comboBox.addItem(makeObj("Item 1")); 715 * comboBox.addItem(makeObj("Item 1")); 716 * ... 717 * private Object makeObj(final String item) { 718 * return new Object() { public String toString() { return item; } }; 719 * } 720 * </pre> 721 * 722 * @param item the item to add to the list 723 * @see MutableComboBoxModel 724 */ 725 public void addItem(E item) { 726 checkMutableComboBoxModel(); 727 ((MutableComboBoxModel<E>)dataModel).addElement(item); 728 } 729 730 /** 731 * Inserts an item into the item list at a given index. 732 * This method works only if the <code>JComboBox</code> uses a 733 * mutable data model. 734 * 735 * @param item the item to add to the list 736 * @param index an integer specifying the position at which 737 * to add the item 738 * @see MutableComboBoxModel 739 */ 740 public void insertItemAt(E item, int index) { 741 checkMutableComboBoxModel(); 742 ((MutableComboBoxModel<E>)dataModel).insertElementAt(item,index); 743 } 744 745 /** 746 * Removes an item from the item list. 747 * This method works only if the <code>JComboBox</code> uses a 748 * mutable data model. 749 * 750 * @param anObject the object to remove from the item list 751 * @see MutableComboBoxModel 752 */ 753 public void removeItem(Object anObject) { 754 checkMutableComboBoxModel(); 755 ((MutableComboBoxModel)dataModel).removeElement(anObject); 756 } 757 758 /** 759 * Removes the item at <code>anIndex</code> 760 * This method works only if the <code>JComboBox</code> uses a 761 * mutable data model. 762 * 763 * @param anIndex an int specifying the index of the item to remove, 764 * where 0 765 * indicates the first item in the list 766 * @see MutableComboBoxModel 767 */ 768 public void removeItemAt(int anIndex) { 769 checkMutableComboBoxModel(); 770 ((MutableComboBoxModel<E>)dataModel).removeElementAt( anIndex ); 771 } 772 773 /** 774 * Removes all items from the item list. 775 */ 776 public void removeAllItems() { 777 checkMutableComboBoxModel(); 778 MutableComboBoxModel<E> model = (MutableComboBoxModel<E>)dataModel; 779 int size = model.getSize(); 780 781 if ( model instanceof DefaultComboBoxModel ) { 782 ((DefaultComboBoxModel)model).removeAllElements(); 783 } 784 else { 785 for ( int i = 0; i < size; ++i ) { 786 E element = model.getElementAt( 0 ); 787 model.removeElement( element ); 788 } 789 } 790 selectedItemReminder = null; 791 if (isEditable()) { 792 editor.setItem(null); 793 } 794 } 795 796 /** 797 * Checks that the <code>dataModel</code> is an instance of 798 * <code>MutableComboBoxModel</code>. If not, it throws an exception. 799 * @exception RuntimeException if <code>dataModel</code> is not an 800 * instance of <code>MutableComboBoxModel</code>. 801 */ 802 void checkMutableComboBoxModel() { 803 if ( !(dataModel instanceof MutableComboBoxModel) ) 804 throw new RuntimeException("Cannot use this method with a non-Mutable data model."); 805 } 806 807 /** 808 * Causes the combo box to display its popup window. 809 * @see #setPopupVisible 810 */ 811 public void showPopup() { 812 setPopupVisible(true); 813 } 814 815 /** 816 * Causes the combo box to close its popup window. 817 * @see #setPopupVisible 818 */ 819 public void hidePopup() { 820 setPopupVisible(false); 821 } 822 823 /** 824 * Sets the visibility of the popup. 825 * 826 * @param v if {@code true} shows the popup, otherwise, hides the popup. 827 */ 828 public void setPopupVisible(boolean v) { 829 getUI().setPopupVisible(this, v); 830 } 831 832 /** 833 * Determines the visibility of the popup. 834 * 835 * @return true if the popup is visible, otherwise returns false 836 */ 837 public boolean isPopupVisible() { 838 return getUI().isPopupVisible(this); 839 } 840 841 /** Selection **/ 842 843 /** 844 * Adds an <code>ItemListener</code>. 845 * <p> 846 * <code>aListener</code> will receive one or two <code>ItemEvent</code>s when 847 * the selected item changes. 848 * 849 * @param aListener the <code>ItemListener</code> that is to be notified 850 * @see #setSelectedItem 851 */ 852 public void addItemListener(ItemListener aListener) { 853 listenerList.add(ItemListener.class,aListener); 854 } 855 856 /** Removes an <code>ItemListener</code>. 857 * 858 * @param aListener the <code>ItemListener</code> to remove 859 */ 860 public void removeItemListener(ItemListener aListener) { 861 listenerList.remove(ItemListener.class,aListener); 862 } 863 864 /** 865 * Returns an array of all the <code>ItemListener</code>s added 866 * to this JComboBox with addItemListener(). 867 * 868 * @return all of the <code>ItemListener</code>s added or an empty 869 * array if no listeners have been added 870 * @since 1.4 871 */ 872 public ItemListener[] getItemListeners() { 873 return listenerList.getListeners(ItemListener.class); 874 } 875 876 /** 877 * Adds an <code>ActionListener</code>. 878 * <p> 879 * The <code>ActionListener</code> will receive an <code>ActionEvent</code> 880 * when a selection has been made. If the combo box is editable, then 881 * an <code>ActionEvent</code> will be fired when editing has stopped. 882 * 883 * @param l the <code>ActionListener</code> that is to be notified 884 * @see #setSelectedItem 885 */ 886 public void addActionListener(ActionListener l) { 887 listenerList.add(ActionListener.class,l); 888 } 889 890 /** Removes an <code>ActionListener</code>. 891 * 892 * @param l the <code>ActionListener</code> to remove 893 */ 894 public void removeActionListener(ActionListener l) { 895 if ((l != null) && (getAction() == l)) { 896 setAction(null); 897 } else { 898 listenerList.remove(ActionListener.class, l); 899 } 900 } 901 902 /** 903 * Returns an array of all the <code>ActionListener</code>s added 904 * to this JComboBox with addActionListener(). 905 * 906 * @return all of the <code>ActionListener</code>s added or an empty 907 * array if no listeners have been added 908 * @since 1.4 909 */ 910 public ActionListener[] getActionListeners() { 911 return listenerList.getListeners(ActionListener.class); 912 } 913 914 /** 915 * Adds a <code>PopupMenu</code> listener which will listen to notification 916 * messages from the popup portion of the combo box. 917 * <p> 918 * For all standard look and feels shipped with Java, the popup list 919 * portion of combo box is implemented as a <code>JPopupMenu</code>. 920 * A custom look and feel may not implement it this way and will 921 * therefore not receive the notification. 922 * 923 * @param l the <code>PopupMenuListener</code> to add 924 * @since 1.4 925 */ 926 public void addPopupMenuListener(PopupMenuListener l) { 927 listenerList.add(PopupMenuListener.class,l); 928 } 929 930 /** 931 * Removes a <code>PopupMenuListener</code>. 932 * 933 * @param l the <code>PopupMenuListener</code> to remove 934 * @see #addPopupMenuListener 935 * @since 1.4 936 */ 937 public void removePopupMenuListener(PopupMenuListener l) { 938 listenerList.remove(PopupMenuListener.class,l); 939 } 940 941 /** 942 * Returns an array of all the <code>PopupMenuListener</code>s added 943 * to this JComboBox with addPopupMenuListener(). 944 * 945 * @return all of the <code>PopupMenuListener</code>s added or an empty 946 * array if no listeners have been added 947 * @since 1.4 948 */ 949 public PopupMenuListener[] getPopupMenuListeners() { 950 return listenerList.getListeners(PopupMenuListener.class); 951 } 952 953 /** 954 * Notifies <code>PopupMenuListener</code>s that the popup portion of the 955 * combo box will become visible. 956 * <p> 957 * This method is public but should not be called by anything other than 958 * the UI delegate. 959 * @see #addPopupMenuListener 960 * @since 1.4 961 */ 962 public void firePopupMenuWillBecomeVisible() { 963 Object[] listeners = listenerList.getListenerList(); 964 PopupMenuEvent e=null; 965 for (int i = listeners.length-2; i>=0; i-=2) { 966 if (listeners[i]==PopupMenuListener.class) { 967 if (e == null) 968 e = new PopupMenuEvent(this); 969 ((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeVisible(e); 970 } 971 } 972 } 973 974 /** 975 * Notifies <code>PopupMenuListener</code>s that the popup portion of the 976 * combo box has become invisible. 977 * <p> 978 * This method is public but should not be called by anything other than 979 * the UI delegate. 980 * @see #addPopupMenuListener 981 * @since 1.4 982 */ 983 public void firePopupMenuWillBecomeInvisible() { 984 Object[] listeners = listenerList.getListenerList(); 985 PopupMenuEvent e=null; 986 for (int i = listeners.length-2; i>=0; i-=2) { 987 if (listeners[i]==PopupMenuListener.class) { 988 if (e == null) 989 e = new PopupMenuEvent(this); 990 ((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeInvisible(e); 991 } 992 } 993 } 994 995 /** 996 * Notifies <code>PopupMenuListener</code>s that the popup portion of the 997 * combo box has been canceled. 998 * <p> 999 * This method is public but should not be called by anything other than 1000 * the UI delegate. 1001 * @see #addPopupMenuListener 1002 * @since 1.4 1003 */ 1004 public void firePopupMenuCanceled() { 1005 Object[] listeners = listenerList.getListenerList(); 1006 PopupMenuEvent e=null; 1007 for (int i = listeners.length-2; i>=0; i-=2) { 1008 if (listeners[i]==PopupMenuListener.class) { 1009 if (e == null) 1010 e = new PopupMenuEvent(this); 1011 ((PopupMenuListener)listeners[i+1]).popupMenuCanceled(e); 1012 } 1013 } 1014 } 1015 1016 /** 1017 * Sets the action command that should be included in the event 1018 * sent to action listeners. 1019 * 1020 * @param aCommand a string containing the "command" that is sent 1021 * to action listeners; the same listener can then 1022 * do different things depending on the command it 1023 * receives 1024 */ 1025 public void setActionCommand(String aCommand) { 1026 actionCommand = aCommand; 1027 } 1028 1029 /** 1030 * Returns the action command that is included in the event sent to 1031 * action listeners. 1032 * 1033 * @return the string containing the "command" that is sent 1034 * to action listeners. 1035 */ 1036 public String getActionCommand() { 1037 return actionCommand; 1038 } 1039 1040 private Action action; 1041 private PropertyChangeListener actionPropertyChangeListener; 1042 1043 /** 1044 * Sets the <code>Action</code> for the <code>ActionEvent</code> source. 1045 * The new <code>Action</code> replaces any previously set 1046 * <code>Action</code> but does not affect <code>ActionListeners</code> 1047 * independently added with <code>addActionListener</code>. 1048 * If the <code>Action</code> is already a registered 1049 * <code>ActionListener</code> for the <code>ActionEvent</code> source, 1050 * it is not re-registered. 1051 * <p> 1052 * Setting the <code>Action</code> results in immediately changing 1053 * all the properties described in <a href="Action.html#buttonActions"> 1054 * Swing Components Supporting <code>Action</code></a>. 1055 * Subsequently, the combobox's properties are automatically updated 1056 * as the <code>Action</code>'s properties change. 1057 * <p> 1058 * This method uses three other methods to set 1059 * and help track the <code>Action</code>'s property values. 1060 * It uses the <code>configurePropertiesFromAction</code> method 1061 * to immediately change the combobox's properties. 1062 * To track changes in the <code>Action</code>'s property values, 1063 * this method registers the <code>PropertyChangeListener</code> 1064 * returned by <code>createActionPropertyChangeListener</code>. The 1065 * default {@code PropertyChangeListener} invokes the 1066 * {@code actionPropertyChanged} method when a property in the 1067 * {@code Action} changes. 1068 * 1069 * @param a the <code>Action</code> for the <code>JComboBox</code>, 1070 * or <code>null</code>. 1071 * @since 1.3 1072 * @see Action 1073 * @see #getAction 1074 * @see #configurePropertiesFromAction 1075 * @see #createActionPropertyChangeListener 1076 * @see #actionPropertyChanged 1077 * @beaninfo 1078 * bound: true 1079 * attribute: visualUpdate true 1080 * description: the Action instance connected with this ActionEvent source 1081 */ 1082 public void setAction(Action a) { 1083 Action oldValue = getAction(); 1084 if (action==null || !action.equals(a)) { 1085 action = a; 1086 if (oldValue!=null) { 1087 removeActionListener(oldValue); 1088 oldValue.removePropertyChangeListener(actionPropertyChangeListener); 1089 actionPropertyChangeListener = null; 1090 } 1091 configurePropertiesFromAction(action); 1092 if (action!=null) { 1093 // Don't add if it is already a listener 1094 if (!isListener(ActionListener.class, action)) { 1095 addActionListener(action); 1096 } 1097 // Reverse linkage: 1098 actionPropertyChangeListener = createActionPropertyChangeListener(action); 1099 action.addPropertyChangeListener(actionPropertyChangeListener); 1100 } 1101 firePropertyChange("action", oldValue, action); 1102 } 1103 } 1104 1105 private boolean isListener(Class<?> c, ActionListener a) { 1106 boolean isListener = false; 1107 Object[] listeners = listenerList.getListenerList(); 1108 for (int i = listeners.length-2; i>=0; i-=2) { 1109 if (listeners[i]==c && listeners[i+1]==a) { 1110 isListener=true; 1111 } 1112 } 1113 return isListener; 1114 } 1115 1116 /** 1117 * Returns the currently set <code>Action</code> for this 1118 * <code>ActionEvent</code> source, or <code>null</code> if no 1119 * <code>Action</code> is set. 1120 * 1121 * @return the <code>Action</code> for this <code>ActionEvent</code> 1122 * source; or <code>null</code> 1123 * @since 1.3 1124 * @see Action 1125 * @see #setAction 1126 */ 1127 public Action getAction() { 1128 return action; 1129 } 1130 1131 /** 1132 * Sets the properties on this combobox to match those in the specified 1133 * <code>Action</code>. Refer to <a href="Action.html#buttonActions"> 1134 * Swing Components Supporting <code>Action</code></a> for more 1135 * details as to which properties this sets. 1136 * 1137 * @param a the <code>Action</code> from which to get the properties, 1138 * or <code>null</code> 1139 * @since 1.3 1140 * @see Action 1141 * @see #setAction 1142 */ 1143 protected void configurePropertiesFromAction(Action a) { 1144 AbstractAction.setEnabledFromAction(this, a); 1145 AbstractAction.setToolTipTextFromAction(this, a); 1146 setActionCommandFromAction(a); 1147 } 1148 1149 /** 1150 * Creates and returns a <code>PropertyChangeListener</code> that is 1151 * responsible for listening for changes from the specified 1152 * <code>Action</code> and updating the appropriate properties. 1153 * <p> 1154 * <b>Warning:</b> If you subclass this do not create an anonymous 1155 * inner class. If you do the lifetime of the combobox will be tied to 1156 * that of the <code>Action</code>. 1157 * 1158 * @param a the combobox's action 1159 * @return the {@code PropertyChangeListener} 1160 * @since 1.3 1161 * @see Action 1162 * @see #setAction 1163 */ 1164 protected PropertyChangeListener createActionPropertyChangeListener(Action a) { 1165 return new ComboBoxActionPropertyChangeListener(this, a); 1166 } 1167 1168 /** 1169 * Updates the combobox's state in response to property changes in 1170 * associated action. This method is invoked from the 1171 * {@code PropertyChangeListener} returned from 1172 * {@code createActionPropertyChangeListener}. Subclasses do not normally 1173 * need to invoke this. Subclasses that support additional {@code Action} 1174 * properties should override this and 1175 * {@code configurePropertiesFromAction}. 1176 * <p> 1177 * Refer to the table at <a href="Action.html#buttonActions"> 1178 * Swing Components Supporting <code>Action</code></a> for a list of 1179 * the properties this method sets. 1180 * 1181 * @param action the <code>Action</code> associated with this combobox 1182 * @param propertyName the name of the property that changed 1183 * @since 1.6 1184 * @see Action 1185 * @see #configurePropertiesFromAction 1186 */ 1187 protected void actionPropertyChanged(Action action, String propertyName) { 1188 if (propertyName == Action.ACTION_COMMAND_KEY) { 1189 setActionCommandFromAction(action); 1190 } else if (propertyName == "enabled") { 1191 AbstractAction.setEnabledFromAction(this, action); 1192 } else if (Action.SHORT_DESCRIPTION == propertyName) { 1193 AbstractAction.setToolTipTextFromAction(this, action); 1194 } 1195 } 1196 1197 private void setActionCommandFromAction(Action a) { 1198 setActionCommand((a != null) ? 1199 (String)a.getValue(Action.ACTION_COMMAND_KEY) : 1200 null); 1201 } 1202 1203 1204 private static class ComboBoxActionPropertyChangeListener 1205 extends ActionPropertyChangeListener<JComboBox<?>> { 1206 ComboBoxActionPropertyChangeListener(JComboBox<?> b, Action a) { 1207 super(b, a); 1208 } 1209 protected void actionPropertyChanged(JComboBox<?> cb, 1210 Action action, 1211 PropertyChangeEvent e) { 1212 if (AbstractAction.shouldReconfigure(e)) { 1213 cb.configurePropertiesFromAction(action); 1214 } else { 1215 cb.actionPropertyChanged(action, e.getPropertyName()); 1216 } 1217 } 1218 } 1219 1220 /** 1221 * Notifies all listeners that have registered interest for 1222 * notification on this event type. 1223 * @param e the event of interest 1224 * 1225 * @see EventListenerList 1226 */ 1227 protected void fireItemStateChanged(ItemEvent e) { 1228 // Guaranteed to return a non-null array 1229 Object[] listeners = listenerList.getListenerList(); 1230 // Process the listeners last to first, notifying 1231 // those that are interested in this event 1232 for ( int i = listeners.length-2; i>=0; i-=2 ) { 1233 if ( listeners[i]==ItemListener.class ) { 1234 // Lazily create the event: 1235 // if (changeEvent == null) 1236 // changeEvent = new ChangeEvent(this); 1237 ((ItemListener)listeners[i+1]).itemStateChanged(e); 1238 } 1239 } 1240 } 1241 1242 /** 1243 * Notifies all listeners that have registered interest for 1244 * notification on this event type. 1245 * 1246 * @see EventListenerList 1247 */ 1248 protected void fireActionEvent() { 1249 if (!firingActionEvent) { 1250 // Set flag to ensure that an infinite loop is not created 1251 firingActionEvent = true; 1252 ActionEvent e = null; 1253 // Guaranteed to return a non-null array 1254 Object[] listeners = listenerList.getListenerList(); 1255 long mostRecentEventTime = EventQueue.getMostRecentEventTime(); 1256 int modifiers = 0; 1257 AWTEvent currentEvent = EventQueue.getCurrentEvent(); 1258 if (currentEvent instanceof InputEvent) { 1259 modifiers = ((InputEvent)currentEvent).getModifiers(); 1260 } else if (currentEvent instanceof ActionEvent) { 1261 modifiers = ((ActionEvent)currentEvent).getModifiers(); 1262 } 1263 // Process the listeners last to first, notifying 1264 // those that are interested in this event 1265 for ( int i = listeners.length-2; i>=0; i-=2 ) { 1266 if ( listeners[i]==ActionListener.class ) { 1267 // Lazily create the event: 1268 if ( e == null ) 1269 e = new ActionEvent(this,ActionEvent.ACTION_PERFORMED, 1270 getActionCommand(), 1271 mostRecentEventTime, modifiers); 1272 ((ActionListener)listeners[i+1]).actionPerformed(e); 1273 } 1274 } 1275 firingActionEvent = false; 1276 } 1277 } 1278 1279 /** 1280 * This protected method is implementation specific. Do not access directly 1281 * or override. 1282 */ 1283 protected void selectedItemChanged() { 1284 if (selectedItemReminder != null ) { 1285 fireItemStateChanged(new ItemEvent(this,ItemEvent.ITEM_STATE_CHANGED, 1286 selectedItemReminder, 1287 ItemEvent.DESELECTED)); 1288 } 1289 1290 // set the new selected item. 1291 selectedItemReminder = dataModel.getSelectedItem(); 1292 1293 if (selectedItemReminder != null ) { 1294 fireItemStateChanged(new ItemEvent(this,ItemEvent.ITEM_STATE_CHANGED, 1295 selectedItemReminder, 1296 ItemEvent.SELECTED)); 1297 } 1298 } 1299 1300 /** 1301 * Returns an array containing the selected item. 1302 * This method is implemented for compatibility with 1303 * <code>ItemSelectable</code>. 1304 * 1305 * @return an array of <code>Objects</code> containing one 1306 * element -- the selected item 1307 */ 1308 public Object[] getSelectedObjects() { 1309 Object selectedObject = getSelectedItem(); 1310 if ( selectedObject == null ) 1311 return new Object[0]; 1312 else { 1313 Object result[] = new Object[1]; 1314 result[0] = selectedObject; 1315 return result; 1316 } 1317 } 1318 1319 /** 1320 * This method is public as an implementation side effect. 1321 * do not call or override. 1322 */ 1323 public void actionPerformed(ActionEvent e) { 1324 setPopupVisible(false); 1325 getModel().setSelectedItem(getEditor().getItem()); 1326 String oldCommand = getActionCommand(); 1327 setActionCommand("comboBoxEdited"); 1328 fireActionEvent(); 1329 setActionCommand(oldCommand); 1330 } 1331 1332 /** 1333 * This method is public as an implementation side effect. 1334 * do not call or override. 1335 */ 1336 public void contentsChanged(ListDataEvent e) { 1337 Object oldSelection = selectedItemReminder; 1338 Object newSelection = dataModel.getSelectedItem(); 1339 if (oldSelection == null || !oldSelection.equals(newSelection)) { 1340 selectedItemChanged(); 1341 if (!selectingItem) { 1342 fireActionEvent(); 1343 } 1344 } 1345 } 1346 1347 /** 1348 * This method is public as an implementation side effect. 1349 * do not call or override. 1350 */ 1351 public void intervalAdded(ListDataEvent e) { 1352 if (selectedItemReminder != dataModel.getSelectedItem()) { 1353 selectedItemChanged(); 1354 } 1355 } 1356 1357 /** 1358 * This method is public as an implementation side effect. 1359 * do not call or override. 1360 */ 1361 public void intervalRemoved(ListDataEvent e) { 1362 contentsChanged(e); 1363 } 1364 1365 /** 1366 * Selects the list item that corresponds to the specified keyboard 1367 * character and returns true, if there is an item corresponding 1368 * to that character. Otherwise, returns false. 1369 * 1370 * @param keyChar a char, typically this is a keyboard key 1371 * typed by the user 1372 * @return {@code true} if there is an item corresponding to that character. 1373 * Otherwise, returns {@code false}. 1374 */ 1375 public boolean selectWithKeyChar(char keyChar) { 1376 int index; 1377 1378 if ( keySelectionManager == null ) 1379 keySelectionManager = createDefaultKeySelectionManager(); 1380 1381 index = keySelectionManager.selectionForKey(keyChar,getModel()); 1382 if ( index != -1 ) { 1383 setSelectedIndex(index); 1384 return true; 1385 } 1386 else 1387 return false; 1388 } 1389 1390 /** 1391 * Enables the combo box so that items can be selected. When the 1392 * combo box is disabled, items cannot be selected and values 1393 * cannot be typed into its field (if it is editable). 1394 * 1395 * @param b a boolean value, where true enables the component and 1396 * false disables it 1397 * @beaninfo 1398 * bound: true 1399 * preferred: true 1400 * description: Whether the combo box is enabled. 1401 */ 1402 public void setEnabled(boolean b) { 1403 super.setEnabled(b); 1404 firePropertyChange( "enabled", !isEnabled(), isEnabled() ); 1405 } 1406 1407 /** 1408 * Initializes the editor with the specified item. 1409 * 1410 * @param anEditor the <code>ComboBoxEditor</code> that displays 1411 * the list item in the 1412 * combo box field and allows it to be edited 1413 * @param anItem the object to display and edit in the field 1414 */ 1415 public void configureEditor(ComboBoxEditor anEditor, Object anItem) { 1416 anEditor.setItem(anItem); 1417 } 1418 1419 /** 1420 * Handles <code>KeyEvent</code>s, looking for the Tab key. 1421 * If the Tab key is found, the popup window is closed. 1422 * 1423 * @param e the <code>KeyEvent</code> containing the keyboard 1424 * key that was pressed 1425 */ 1426 public void processKeyEvent(KeyEvent e) { 1427 if ( e.getKeyCode() == KeyEvent.VK_TAB ) { 1428 hidePopup(); 1429 } 1430 super.processKeyEvent(e); 1431 } 1432 1433 /** 1434 * {@inheritDoc} 1435 */ 1436 @Override 1437 protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) { 1438 if (super.processKeyBinding(ks, e, condition, pressed)) { 1439 return true; 1440 } 1441 1442 if (!isEditable() || condition != WHEN_FOCUSED || getEditor() == null 1443 || !Boolean.TRUE.equals(getClientProperty("JComboBox.isTableCellEditor"))) { 1444 return false; 1445 } 1446 1447 Component editorComponent = getEditor().getEditorComponent(); 1448 if (editorComponent instanceof JComponent) { 1449 JComponent component = (JComponent) editorComponent; 1450 return component.processKeyBinding(ks, e, WHEN_FOCUSED, pressed); 1451 } 1452 return false; 1453 } 1454 1455 /** 1456 * Sets the object that translates a keyboard character into a list 1457 * selection. Typically, the first selection with a matching first 1458 * character becomes the selected item. 1459 * 1460 * @param aManager a key selection manager 1461 * @beaninfo 1462 * expert: true 1463 * description: The objects that changes the selection when a key is pressed. 1464 */ 1465 public void setKeySelectionManager(KeySelectionManager aManager) { 1466 keySelectionManager = aManager; 1467 } 1468 1469 /** 1470 * Returns the list's key-selection manager. 1471 * 1472 * @return the <code>KeySelectionManager</code> currently in use 1473 */ 1474 public KeySelectionManager getKeySelectionManager() { 1475 return keySelectionManager; 1476 } 1477 1478 /* Accessing the model */ 1479 /** 1480 * Returns the number of items in the list. 1481 * 1482 * @return an integer equal to the number of items in the list 1483 */ 1484 public int getItemCount() { 1485 return dataModel.getSize(); 1486 } 1487 1488 /** 1489 * Returns the list item at the specified index. If <code>index</code> 1490 * is out of range (less than zero or greater than or equal to size) 1491 * it will return <code>null</code>. 1492 * 1493 * @param index an integer indicating the list position, where the first 1494 * item starts at zero 1495 * @return the item at that list position; or 1496 * <code>null</code> if out of range 1497 */ 1498 public E getItemAt(int index) { 1499 return dataModel.getElementAt(index); 1500 } 1501 1502 /** 1503 * Returns an instance of the default key-selection manager. 1504 * 1505 * @return the <code>KeySelectionManager</code> currently used by the list 1506 * @see #setKeySelectionManager 1507 */ 1508 protected KeySelectionManager createDefaultKeySelectionManager() { 1509 return new DefaultKeySelectionManager(); 1510 } 1511 1512 1513 /** 1514 * The interface that defines a <code>KeySelectionManager</code>. 1515 * To qualify as a <code>KeySelectionManager</code>, 1516 * the class needs to implement the method 1517 * that identifies the list index given a character and the 1518 * combo box data model. 1519 */ 1520 public interface KeySelectionManager { 1521 /** Given <code>aKey</code> and the model, returns the row 1522 * that should become selected. Return -1 if no match was 1523 * found. 1524 * 1525 * @param aKey a char value, usually indicating a keyboard key that 1526 * was pressed 1527 * @param aModel a ComboBoxModel -- the component's data model, containing 1528 * the list of selectable items 1529 * @return an int equal to the selected row, where 0 is the 1530 * first item and -1 is none. 1531 */ 1532 int selectionForKey(char aKey,ComboBoxModel<?> aModel); 1533 } 1534 1535 class DefaultKeySelectionManager implements KeySelectionManager, Serializable { 1536 public int selectionForKey(char aKey,ComboBoxModel<?> aModel) { 1537 int i,c; 1538 int currentSelection = -1; 1539 Object selectedItem = aModel.getSelectedItem(); 1540 String v; 1541 String pattern; 1542 1543 if ( selectedItem != null ) { 1544 for ( i=0,c=aModel.getSize();i<c;i++ ) { 1545 if ( selectedItem == aModel.getElementAt(i) ) { 1546 currentSelection = i; 1547 break; 1548 } 1549 } 1550 } 1551 1552 pattern = ("" + aKey).toLowerCase(); 1553 aKey = pattern.charAt(0); 1554 1555 for ( i = ++currentSelection, c = aModel.getSize() ; i < c ; i++ ) { 1556 Object elem = aModel.getElementAt(i); 1557 if (elem != null && elem.toString() != null) { 1558 v = elem.toString().toLowerCase(); 1559 if ( v.length() > 0 && v.charAt(0) == aKey ) 1560 return i; 1561 } 1562 } 1563 1564 for ( i = 0 ; i < currentSelection ; i ++ ) { 1565 Object elem = aModel.getElementAt(i); 1566 if (elem != null && elem.toString() != null) { 1567 v = elem.toString().toLowerCase(); 1568 if ( v.length() > 0 && v.charAt(0) == aKey ) 1569 return i; 1570 } 1571 } 1572 return -1; 1573 } 1574 } 1575 1576 1577 /** 1578 * See <code>readObject</code> and <code>writeObject</code> in 1579 * <code>JComponent</code> for more 1580 * information about serialization in Swing. 1581 */ 1582 private void writeObject(ObjectOutputStream s) throws IOException { 1583 s.defaultWriteObject(); 1584 if (getUIClassID().equals(uiClassID)) { 1585 byte count = JComponent.getWriteObjCounter(this); 1586 JComponent.setWriteObjCounter(this, --count); 1587 if (count == 0 && ui != null) { 1588 ui.installUI(this); 1589 } 1590 } 1591 } 1592 1593 1594 /** 1595 * Returns a string representation of this <code>JComboBox</code>. 1596 * This method is intended to be used only for debugging purposes, 1597 * and the content and format of the returned string may vary between 1598 * implementations. The returned string may be empty but may not 1599 * be <code>null</code>. 1600 * 1601 * @return a string representation of this <code>JComboBox</code> 1602 */ 1603 protected String paramString() { 1604 String selectedItemReminderString = (selectedItemReminder != null ? 1605 selectedItemReminder.toString() : 1606 ""); 1607 String isEditableString = (isEditable ? "true" : "false"); 1608 String lightWeightPopupEnabledString = (lightWeightPopupEnabled ? 1609 "true" : "false"); 1610 1611 return super.paramString() + 1612 ",isEditable=" + isEditableString + 1613 ",lightWeightPopupEnabled=" + lightWeightPopupEnabledString + 1614 ",maximumRowCount=" + maximumRowCount + 1615 ",selectedItemReminder=" + selectedItemReminderString; 1616 } 1617 1618 1619 /////////////////// 1620 // Accessibility support 1621 /////////////////// 1622 1623 /** 1624 * Gets the AccessibleContext associated with this JComboBox. 1625 * For combo boxes, the AccessibleContext takes the form of an 1626 * AccessibleJComboBox. 1627 * A new AccessibleJComboBox instance is created if necessary. 1628 * 1629 * @return an AccessibleJComboBox that serves as the 1630 * AccessibleContext of this JComboBox 1631 */ 1632 public AccessibleContext getAccessibleContext() { 1633 if ( accessibleContext == null ) { 1634 accessibleContext = new AccessibleJComboBox(); 1635 } 1636 return accessibleContext; 1637 } 1638 1639 /** 1640 * This class implements accessibility support for the 1641 * <code>JComboBox</code> class. It provides an implementation of the 1642 * Java Accessibility API appropriate to Combo Box user-interface elements. 1643 * <p> 1644 * <strong>Warning:</strong> 1645 * Serialized objects of this class will not be compatible with 1646 * future Swing releases. The current serialization support is 1647 * appropriate for short term storage or RMI between applications running 1648 * the same version of Swing. As of 1.4, support for long term storage 1649 * of all JavaBeans™ 1650 * has been added to the <code>java.beans</code> package. 1651 * Please see {@link java.beans.XMLEncoder}. 1652 */ 1653 @SuppressWarnings("serial") // Same-version serialization only 1654 protected class AccessibleJComboBox extends AccessibleJComponent 1655 implements AccessibleAction, AccessibleSelection { 1656 1657 1658 private JList<?> popupList; // combo box popup list 1659 private Accessible previousSelectedAccessible = null; 1660 1661 /** 1662 * Returns an AccessibleJComboBox instance 1663 * @since 1.4 1664 */ 1665 public AccessibleJComboBox() { 1666 // set the combo box editor's accessible name and description 1667 JComboBox.this.addPropertyChangeListener(new AccessibleJComboBoxPropertyChangeListener()); 1668 setEditorNameAndDescription(); 1669 1670 // Get the popup list 1671 Accessible a = getUI().getAccessibleChild(JComboBox.this, 0); 1672 if (a instanceof javax.swing.plaf.basic.ComboPopup) { 1673 // Listen for changes to the popup menu selection. 1674 popupList = ((javax.swing.plaf.basic.ComboPopup)a).getList(); 1675 popupList.addListSelectionListener( 1676 new AccessibleJComboBoxListSelectionListener()); 1677 } 1678 // Listen for popup menu show/hide events 1679 JComboBox.this.addPopupMenuListener( 1680 new AccessibleJComboBoxPopupMenuListener()); 1681 } 1682 1683 /* 1684 * JComboBox PropertyChangeListener 1685 */ 1686 private class AccessibleJComboBoxPropertyChangeListener 1687 implements PropertyChangeListener { 1688 1689 public void propertyChange(PropertyChangeEvent e) { 1690 if (e.getPropertyName() == "editor") { 1691 // set the combo box editor's accessible name 1692 // and description 1693 setEditorNameAndDescription(); 1694 } 1695 } 1696 } 1697 1698 /* 1699 * Sets the combo box editor's accessible name and descripton 1700 */ 1701 private void setEditorNameAndDescription() { 1702 ComboBoxEditor editor = JComboBox.this.getEditor(); 1703 if (editor != null) { 1704 Component comp = editor.getEditorComponent(); 1705 if (comp instanceof Accessible) { 1706 AccessibleContext ac = comp.getAccessibleContext(); 1707 if (ac != null) { // may be null 1708 ac.setAccessibleName(getAccessibleName()); 1709 ac.setAccessibleDescription(getAccessibleDescription()); 1710 } 1711 } 1712 } 1713 } 1714 1715 /* 1716 * Listener for combo box popup menu 1717 * TIGER - 4669379 4894434 1718 */ 1719 private class AccessibleJComboBoxPopupMenuListener 1720 implements PopupMenuListener { 1721 1722 /** 1723 * This method is called before the popup menu becomes visible 1724 */ 1725 public void popupMenuWillBecomeVisible(PopupMenuEvent e) { 1726 // save the initial selection 1727 if (popupList == null) { 1728 return; 1729 } 1730 int selectedIndex = popupList.getSelectedIndex(); 1731 if (selectedIndex < 0) { 1732 return; 1733 } 1734 previousSelectedAccessible = 1735 popupList.getAccessibleContext().getAccessibleChild(selectedIndex); 1736 } 1737 1738 /** 1739 * This method is called before the popup menu becomes invisible 1740 * Note that a JPopupMenu can become invisible any time 1741 */ 1742 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { 1743 // ignore 1744 } 1745 1746 /** 1747 * This method is called when the popup menu is canceled 1748 */ 1749 public void popupMenuCanceled(PopupMenuEvent e) { 1750 // ignore 1751 } 1752 } 1753 1754 /* 1755 * Handles changes to the popup list selection. 1756 * TIGER - 4669379 4894434 4933143 1757 */ 1758 private class AccessibleJComboBoxListSelectionListener 1759 implements ListSelectionListener { 1760 1761 public void valueChanged(ListSelectionEvent e) { 1762 if (popupList == null) { 1763 return; 1764 } 1765 1766 // Get the selected popup list item. 1767 int selectedIndex = popupList.getSelectedIndex(); 1768 if (selectedIndex < 0) { 1769 return; 1770 } 1771 Accessible selectedAccessible = 1772 popupList.getAccessibleContext().getAccessibleChild(selectedIndex); 1773 if (selectedAccessible == null) { 1774 return; 1775 } 1776 1777 // Fire a FOCUSED lost PropertyChangeEvent for the 1778 // previously selected list item. 1779 PropertyChangeEvent pce; 1780 1781 if (previousSelectedAccessible != null) { 1782 pce = new PropertyChangeEvent(previousSelectedAccessible, 1783 AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 1784 AccessibleState.FOCUSED, null); 1785 firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 1786 null, pce); 1787 } 1788 // Fire a FOCUSED gained PropertyChangeEvent for the 1789 // currently selected list item. 1790 pce = new PropertyChangeEvent(selectedAccessible, 1791 AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 1792 null, AccessibleState.FOCUSED); 1793 firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 1794 null, pce); 1795 1796 // Fire the ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY event 1797 // for the combo box. 1798 firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY, 1799 previousSelectedAccessible, selectedAccessible); 1800 1801 // Save the previous selection. 1802 previousSelectedAccessible = selectedAccessible; 1803 } 1804 } 1805 1806 1807 /** 1808 * Returns the number of accessible children in the object. If all 1809 * of the children of this object implement Accessible, than this 1810 * method should return the number of children of this object. 1811 * 1812 * @return the number of accessible children in the object. 1813 */ 1814 public int getAccessibleChildrenCount() { 1815 // Always delegate to the UI if it exists 1816 if (ui != null) { 1817 return ui.getAccessibleChildrenCount(JComboBox.this); 1818 } else { 1819 return super.getAccessibleChildrenCount(); 1820 } 1821 } 1822 1823 /** 1824 * Returns the nth Accessible child of the object. 1825 * The child at index zero represents the popup. 1826 * If the combo box is editable, the child at index one 1827 * represents the editor. 1828 * 1829 * @param i zero-based index of child 1830 * @return the nth Accessible child of the object 1831 */ 1832 public Accessible getAccessibleChild(int i) { 1833 // Always delegate to the UI if it exists 1834 if (ui != null) { 1835 return ui.getAccessibleChild(JComboBox.this, i); 1836 } else { 1837 return super.getAccessibleChild(i); 1838 } 1839 } 1840 1841 /** 1842 * Get the role of this object. 1843 * 1844 * @return an instance of AccessibleRole describing the role of the 1845 * object 1846 * @see AccessibleRole 1847 */ 1848 public AccessibleRole getAccessibleRole() { 1849 return AccessibleRole.COMBO_BOX; 1850 } 1851 1852 /** 1853 * Gets the state set of this object. The AccessibleStateSet of 1854 * an object is composed of a set of unique AccessibleStates. 1855 * A change in the AccessibleStateSet of an object will cause a 1856 * PropertyChangeEvent to be fired for the ACCESSIBLE_STATE_PROPERTY 1857 * property. 1858 * 1859 * @return an instance of AccessibleStateSet containing the 1860 * current state set of the object 1861 * @see AccessibleStateSet 1862 * @see AccessibleState 1863 * @see #addPropertyChangeListener 1864 * 1865 */ 1866 public AccessibleStateSet getAccessibleStateSet() { 1867 // TIGER - 4489748 1868 AccessibleStateSet ass = super.getAccessibleStateSet(); 1869 if (ass == null) { 1870 ass = new AccessibleStateSet(); 1871 } 1872 if (JComboBox.this.isPopupVisible()) { 1873 ass.add(AccessibleState.EXPANDED); 1874 } else { 1875 ass.add(AccessibleState.COLLAPSED); 1876 } 1877 return ass; 1878 } 1879 1880 /** 1881 * Get the AccessibleAction associated with this object. In the 1882 * implementation of the Java Accessibility API for this class, 1883 * return this object, which is responsible for implementing the 1884 * AccessibleAction interface on behalf of itself. 1885 * 1886 * @return this object 1887 */ 1888 public AccessibleAction getAccessibleAction() { 1889 return this; 1890 } 1891 1892 /** 1893 * Return a description of the specified action of the object. 1894 * 1895 * @param i zero-based index of the actions 1896 */ 1897 public String getAccessibleActionDescription(int i) { 1898 if (i == 0) { 1899 return UIManager.getString("ComboBox.togglePopupText"); 1900 } 1901 else { 1902 return null; 1903 } 1904 } 1905 1906 /** 1907 * Returns the number of Actions available in this object. The 1908 * default behavior of a combo box is to have one action. 1909 * 1910 * @return 1, the number of Actions in this object 1911 */ 1912 public int getAccessibleActionCount() { 1913 return 1; 1914 } 1915 1916 /** 1917 * Perform the specified Action on the object 1918 * 1919 * @param i zero-based index of actions 1920 * @return true if the action was performed; else false. 1921 */ 1922 public boolean doAccessibleAction(int i) { 1923 if (i == 0) { 1924 setPopupVisible(!isPopupVisible()); 1925 return true; 1926 } 1927 else { 1928 return false; 1929 } 1930 } 1931 1932 1933 /** 1934 * Get the AccessibleSelection associated with this object. In the 1935 * implementation of the Java Accessibility API for this class, 1936 * return this object, which is responsible for implementing the 1937 * AccessibleSelection interface on behalf of itself. 1938 * 1939 * @return this object 1940 */ 1941 public AccessibleSelection getAccessibleSelection() { 1942 return this; 1943 } 1944 1945 /** 1946 * Returns the number of Accessible children currently selected. 1947 * If no children are selected, the return value will be 0. 1948 * 1949 * @return the number of items currently selected. 1950 * @since 1.3 1951 */ 1952 public int getAccessibleSelectionCount() { 1953 Object o = JComboBox.this.getSelectedItem(); 1954 if (o != null) { 1955 return 1; 1956 } else { 1957 return 0; 1958 } 1959 } 1960 1961 /** 1962 * Returns an Accessible representing the specified selected child 1963 * in the popup. If there isn't a selection, or there are 1964 * fewer children selected than the integer passed in, the return 1965 * value will be null. 1966 * <p>Note that the index represents the i-th selected child, which 1967 * is different from the i-th child. 1968 * 1969 * @param i the zero-based index of selected children 1970 * @return the i-th selected child 1971 * @see #getAccessibleSelectionCount 1972 * @since 1.3 1973 */ 1974 public Accessible getAccessibleSelection(int i) { 1975 // Get the popup 1976 Accessible a = 1977 JComboBox.this.getUI().getAccessibleChild(JComboBox.this, 0); 1978 if (a != null && 1979 a instanceof javax.swing.plaf.basic.ComboPopup) { 1980 1981 // get the popup list 1982 JList<?> list = ((javax.swing.plaf.basic.ComboPopup)a).getList(); 1983 1984 // return the i-th selection in the popup list 1985 AccessibleContext ac = list.getAccessibleContext(); 1986 if (ac != null) { 1987 AccessibleSelection as = ac.getAccessibleSelection(); 1988 if (as != null) { 1989 return as.getAccessibleSelection(i); 1990 } 1991 } 1992 } 1993 return null; 1994 } 1995 1996 /** 1997 * Determines if the current child of this object is selected. 1998 * 1999 * @return true if the current child of this object is selected; 2000 * else false 2001 * @param i the zero-based index of the child in this Accessible 2002 * object. 2003 * @see AccessibleContext#getAccessibleChild 2004 * @since 1.3 2005 */ 2006 public boolean isAccessibleChildSelected(int i) { 2007 return JComboBox.this.getSelectedIndex() == i; 2008 } 2009 2010 /** 2011 * Adds the specified Accessible child of the object to the object's 2012 * selection. If the object supports multiple selections, 2013 * the specified child is added to any existing selection, otherwise 2014 * it replaces any existing selection in the object. If the 2015 * specified child is already selected, this method has no effect. 2016 * 2017 * @param i the zero-based index of the child 2018 * @see AccessibleContext#getAccessibleChild 2019 * @since 1.3 2020 */ 2021 public void addAccessibleSelection(int i) { 2022 // TIGER - 4856195 2023 clearAccessibleSelection(); 2024 JComboBox.this.setSelectedIndex(i); 2025 } 2026 2027 /** 2028 * Removes the specified child of the object from the object's 2029 * selection. If the specified item isn't currently selected, this 2030 * method has no effect. 2031 * 2032 * @param i the zero-based index of the child 2033 * @see AccessibleContext#getAccessibleChild 2034 * @since 1.3 2035 */ 2036 public void removeAccessibleSelection(int i) { 2037 if (JComboBox.this.getSelectedIndex() == i) { 2038 clearAccessibleSelection(); 2039 } 2040 } 2041 2042 /** 2043 * Clears the selection in the object, so that no children in the 2044 * object are selected. 2045 * @since 1.3 2046 */ 2047 public void clearAccessibleSelection() { 2048 JComboBox.this.setSelectedIndex(-1); 2049 } 2050 2051 /** 2052 * Causes every child of the object to be selected 2053 * if the object supports multiple selections. 2054 * @since 1.3 2055 */ 2056 public void selectAllAccessibleSelection() { 2057 // do nothing since multiple selection is not supported 2058 } 2059 2060 // public Accessible getAccessibleAt(Point p) { 2061 // Accessible a = getAccessibleChild(1); 2062 // if ( a != null ) { 2063 // return a; // the editor 2064 // } 2065 // else { 2066 // return getAccessibleChild(0); // the list 2067 // } 2068 // } 2069 private EditorAccessibleContext editorAccessibleContext = null; 2070 2071 private class AccessibleEditor implements Accessible { 2072 public AccessibleContext getAccessibleContext() { 2073 if (editorAccessibleContext == null) { 2074 Component c = JComboBox.this.getEditor().getEditorComponent(); 2075 if (c instanceof Accessible) { 2076 editorAccessibleContext = 2077 new EditorAccessibleContext((Accessible)c); 2078 } 2079 } 2080 return editorAccessibleContext; 2081 } 2082 } 2083 2084 /* 2085 * Wrapper class for the AccessibleContext implemented by the 2086 * combo box editor. Delegates all method calls except 2087 * getAccessibleIndexInParent to the editor. The 2088 * getAccessibleIndexInParent method returns the selected 2089 * index in the combo box. 2090 */ 2091 private class EditorAccessibleContext extends AccessibleContext { 2092 2093 private AccessibleContext ac; 2094 2095 private EditorAccessibleContext() { 2096 } 2097 2098 /* 2099 * @param a the AccessibleContext implemented by the 2100 * combo box editor 2101 */ 2102 EditorAccessibleContext(Accessible a) { 2103 this.ac = a.getAccessibleContext(); 2104 } 2105 2106 /** 2107 * Gets the accessibleName property of this object. The accessibleName 2108 * property of an object is a localized String that designates the purpose 2109 * of the object. For example, the accessibleName property of a label 2110 * or button might be the text of the label or button itself. In the 2111 * case of an object that doesn't display its name, the accessibleName 2112 * should still be set. For example, in the case of a text field used 2113 * to enter the name of a city, the accessibleName for the en_US locale 2114 * could be 'city.' 2115 * 2116 * @return the localized name of the object; null if this 2117 * object does not have a name 2118 * 2119 * @see #setAccessibleName 2120 */ 2121 public String getAccessibleName() { 2122 return ac.getAccessibleName(); 2123 } 2124 2125 /** 2126 * Sets the localized accessible name of this object. Changing the 2127 * name will cause a PropertyChangeEvent to be fired for the 2128 * ACCESSIBLE_NAME_PROPERTY property. 2129 * 2130 * @param s the new localized name of the object. 2131 * 2132 * @see #getAccessibleName 2133 * @see #addPropertyChangeListener 2134 * 2135 * @beaninfo 2136 * preferred: true 2137 * description: Sets the accessible name for the component. 2138 */ 2139 public void setAccessibleName(String s) { 2140 ac.setAccessibleName(s); 2141 } 2142 2143 /** 2144 * Gets the accessibleDescription property of this object. The 2145 * accessibleDescription property of this object is a short localized 2146 * phrase describing the purpose of the object. For example, in the 2147 * case of a 'Cancel' button, the accessibleDescription could be 2148 * 'Ignore changes and close dialog box.' 2149 * 2150 * @return the localized description of the object; null if 2151 * this object does not have a description 2152 * 2153 * @see #setAccessibleDescription 2154 */ 2155 public String getAccessibleDescription() { 2156 return ac.getAccessibleDescription(); 2157 } 2158 2159 /** 2160 * Sets the accessible description of this object. Changing the 2161 * name will cause a PropertyChangeEvent to be fired for the 2162 * ACCESSIBLE_DESCRIPTION_PROPERTY property. 2163 * 2164 * @param s the new localized description of the object 2165 * 2166 * @see #setAccessibleName 2167 * @see #addPropertyChangeListener 2168 * 2169 * @beaninfo 2170 * preferred: true 2171 * description: Sets the accessible description for the component. 2172 */ 2173 public void setAccessibleDescription(String s) { 2174 ac.setAccessibleDescription(s); 2175 } 2176 2177 /** 2178 * Gets the role of this object. The role of the object is the generic 2179 * purpose or use of the class of this object. For example, the role 2180 * of a push button is AccessibleRole.PUSH_BUTTON. The roles in 2181 * AccessibleRole are provided so component developers can pick from 2182 * a set of predefined roles. This enables assistive technologies to 2183 * provide a consistent interface to various tweaked subclasses of 2184 * components (e.g., use AccessibleRole.PUSH_BUTTON for all components 2185 * that act like a push button) as well as distinguish between subclasses 2186 * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes 2187 * and AccessibleRole.RADIO_BUTTON for radio buttons). 2188 * <p>Note that the AccessibleRole class is also extensible, so 2189 * custom component developers can define their own AccessibleRole's 2190 * if the set of predefined roles is inadequate. 2191 * 2192 * @return an instance of AccessibleRole describing the role of the object 2193 * @see AccessibleRole 2194 */ 2195 public AccessibleRole getAccessibleRole() { 2196 return ac.getAccessibleRole(); 2197 } 2198 2199 /** 2200 * Gets the state set of this object. The AccessibleStateSet of an object 2201 * is composed of a set of unique AccessibleStates. A change in the 2202 * AccessibleStateSet of an object will cause a PropertyChangeEvent to 2203 * be fired for the ACCESSIBLE_STATE_PROPERTY property. 2204 * 2205 * @return an instance of AccessibleStateSet containing the 2206 * current state set of the object 2207 * @see AccessibleStateSet 2208 * @see AccessibleState 2209 * @see #addPropertyChangeListener 2210 */ 2211 public AccessibleStateSet getAccessibleStateSet() { 2212 return ac.getAccessibleStateSet(); 2213 } 2214 2215 /** 2216 * Gets the Accessible parent of this object. 2217 * 2218 * @return the Accessible parent of this object; null if this 2219 * object does not have an Accessible parent 2220 */ 2221 public Accessible getAccessibleParent() { 2222 return ac.getAccessibleParent(); 2223 } 2224 2225 /** 2226 * Sets the Accessible parent of this object. This is meant to be used 2227 * only in the situations where the actual component's parent should 2228 * not be treated as the component's accessible parent and is a method 2229 * that should only be called by the parent of the accessible child. 2230 * 2231 * @param a - Accessible to be set as the parent 2232 */ 2233 public void setAccessibleParent(Accessible a) { 2234 ac.setAccessibleParent(a); 2235 } 2236 2237 /** 2238 * Gets the 0-based index of this object in its accessible parent. 2239 * 2240 * @return the 0-based index of this object in its parent; -1 if this 2241 * object does not have an accessible parent. 2242 * 2243 * @see #getAccessibleParent 2244 * @see #getAccessibleChildrenCount 2245 * @see #getAccessibleChild 2246 */ 2247 public int getAccessibleIndexInParent() { 2248 return JComboBox.this.getSelectedIndex(); 2249 } 2250 2251 /** 2252 * Returns the number of accessible children of the object. 2253 * 2254 * @return the number of accessible children of the object. 2255 */ 2256 public int getAccessibleChildrenCount() { 2257 return ac.getAccessibleChildrenCount(); 2258 } 2259 2260 /** 2261 * Returns the specified Accessible child of the object. The Accessible 2262 * children of an Accessible object are zero-based, so the first child 2263 * of an Accessible child is at index 0, the second child is at index 1, 2264 * and so on. 2265 * 2266 * @param i zero-based index of child 2267 * @return the Accessible child of the object 2268 * @see #getAccessibleChildrenCount 2269 */ 2270 public Accessible getAccessibleChild(int i) { 2271 return ac.getAccessibleChild(i); 2272 } 2273 2274 /** 2275 * Gets the locale of the component. If the component does not have a 2276 * locale, then the locale of its parent is returned. 2277 * 2278 * @return this component's locale. If this component does not have 2279 * a locale, the locale of its parent is returned. 2280 * 2281 * @exception IllegalComponentStateException 2282 * If the Component does not have its own locale and has not yet been 2283 * added to a containment hierarchy such that the locale can be 2284 * determined from the containing parent. 2285 */ 2286 public Locale getLocale() throws IllegalComponentStateException { 2287 return ac.getLocale(); 2288 } 2289 2290 /** 2291 * Adds a PropertyChangeListener to the listener list. 2292 * The listener is registered for all Accessible properties and will 2293 * be called when those properties change. 2294 * 2295 * @see #ACCESSIBLE_NAME_PROPERTY 2296 * @see #ACCESSIBLE_DESCRIPTION_PROPERTY 2297 * @see #ACCESSIBLE_STATE_PROPERTY 2298 * @see #ACCESSIBLE_VALUE_PROPERTY 2299 * @see #ACCESSIBLE_SELECTION_PROPERTY 2300 * @see #ACCESSIBLE_TEXT_PROPERTY 2301 * @see #ACCESSIBLE_VISIBLE_DATA_PROPERTY 2302 * 2303 * @param listener The PropertyChangeListener to be added 2304 */ 2305 public void addPropertyChangeListener(PropertyChangeListener listener) { 2306 ac.addPropertyChangeListener(listener); 2307 } 2308 2309 /** 2310 * Removes a PropertyChangeListener from the listener list. 2311 * This removes a PropertyChangeListener that was registered 2312 * for all properties. 2313 * 2314 * @param listener The PropertyChangeListener to be removed 2315 */ 2316 public void removePropertyChangeListener(PropertyChangeListener listener) { 2317 ac.removePropertyChangeListener(listener); 2318 } 2319 2320 /** 2321 * Gets the AccessibleAction associated with this object that supports 2322 * one or more actions. 2323 * 2324 * @return AccessibleAction if supported by object; else return null 2325 * @see AccessibleAction 2326 */ 2327 public AccessibleAction getAccessibleAction() { 2328 return ac.getAccessibleAction(); 2329 } 2330 2331 /** 2332 * Gets the AccessibleComponent associated with this object that has a 2333 * graphical representation. 2334 * 2335 * @return AccessibleComponent if supported by object; else return null 2336 * @see AccessibleComponent 2337 */ 2338 public AccessibleComponent getAccessibleComponent() { 2339 return ac.getAccessibleComponent(); 2340 } 2341 2342 /** 2343 * Gets the AccessibleSelection associated with this object which allows its 2344 * Accessible children to be selected. 2345 * 2346 * @return AccessibleSelection if supported by object; else return null 2347 * @see AccessibleSelection 2348 */ 2349 public AccessibleSelection getAccessibleSelection() { 2350 return ac.getAccessibleSelection(); 2351 } 2352 2353 /** 2354 * Gets the AccessibleText associated with this object presenting 2355 * text on the display. 2356 * 2357 * @return AccessibleText if supported by object; else return null 2358 * @see AccessibleText 2359 */ 2360 public AccessibleText getAccessibleText() { 2361 return ac.getAccessibleText(); 2362 } 2363 2364 /** 2365 * Gets the AccessibleEditableText associated with this object 2366 * presenting editable text on the display. 2367 * 2368 * @return AccessibleEditableText if supported by object; else return null 2369 * @see AccessibleEditableText 2370 */ 2371 public AccessibleEditableText getAccessibleEditableText() { 2372 return ac.getAccessibleEditableText(); 2373 } 2374 2375 /** 2376 * Gets the AccessibleValue associated with this object that supports a 2377 * Numerical value. 2378 * 2379 * @return AccessibleValue if supported by object; else return null 2380 * @see AccessibleValue 2381 */ 2382 public AccessibleValue getAccessibleValue() { 2383 return ac.getAccessibleValue(); 2384 } 2385 2386 /** 2387 * Gets the AccessibleIcons associated with an object that has 2388 * one or more associated icons 2389 * 2390 * @return an array of AccessibleIcon if supported by object; 2391 * otherwise return null 2392 * @see AccessibleIcon 2393 */ 2394 public AccessibleIcon [] getAccessibleIcon() { 2395 return ac.getAccessibleIcon(); 2396 } 2397 2398 /** 2399 * Gets the AccessibleRelationSet associated with an object 2400 * 2401 * @return an AccessibleRelationSet if supported by object; 2402 * otherwise return null 2403 * @see AccessibleRelationSet 2404 */ 2405 public AccessibleRelationSet getAccessibleRelationSet() { 2406 return ac.getAccessibleRelationSet(); 2407 } 2408 2409 /** 2410 * Gets the AccessibleTable associated with an object 2411 * 2412 * @return an AccessibleTable if supported by object; 2413 * otherwise return null 2414 * @see AccessibleTable 2415 */ 2416 public AccessibleTable getAccessibleTable() { 2417 return ac.getAccessibleTable(); 2418 } 2419 2420 /** 2421 * Support for reporting bound property changes. If oldValue and 2422 * newValue are not equal and the PropertyChangeEvent listener list 2423 * is not empty, then fire a PropertyChange event to each listener. 2424 * In general, this is for use by the Accessible objects themselves 2425 * and should not be called by an application program. 2426 * @param propertyName The programmatic name of the property that 2427 * was changed. 2428 * @param oldValue The old value of the property. 2429 * @param newValue The new value of the property. 2430 * @see java.beans.PropertyChangeSupport 2431 * @see #addPropertyChangeListener 2432 * @see #removePropertyChangeListener 2433 * @see #ACCESSIBLE_NAME_PROPERTY 2434 * @see #ACCESSIBLE_DESCRIPTION_PROPERTY 2435 * @see #ACCESSIBLE_STATE_PROPERTY 2436 * @see #ACCESSIBLE_VALUE_PROPERTY 2437 * @see #ACCESSIBLE_SELECTION_PROPERTY 2438 * @see #ACCESSIBLE_TEXT_PROPERTY 2439 * @see #ACCESSIBLE_VISIBLE_DATA_PROPERTY 2440 */ 2441 public void firePropertyChange(String propertyName, 2442 Object oldValue, 2443 Object newValue) { 2444 ac.firePropertyChange(propertyName, oldValue, newValue); 2445 } 2446 } 2447 2448 } // innerclass AccessibleJComboBox 2449 }