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