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