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 @SuppressWarnings("deprecation") 1239 protected void fireActionEvent() { 1240 if (!firingActionEvent) { 1241 // Set flag to ensure that an infinite loop is not created 1242 firingActionEvent = true; 1243 ActionEvent e = null; 1244 // Guaranteed to return a non-null array 1245 Object[] listeners = listenerList.getListenerList(); 1246 long mostRecentEventTime = EventQueue.getMostRecentEventTime(); 1247 int modifiers = 0; 1248 AWTEvent currentEvent = EventQueue.getCurrentEvent(); 1249 if (currentEvent instanceof InputEvent) { 1250 modifiers = ((InputEvent)currentEvent).getModifiers(); 1251 } else if (currentEvent instanceof ActionEvent) { 1252 modifiers = ((ActionEvent)currentEvent).getModifiers(); 1253 } 1254 try { 1255 // Process the listeners last to first, notifying 1256 // those that are interested in this event 1257 for ( int i = listeners.length-2; i>=0; i-=2 ) { 1258 if ( listeners[i]==ActionListener.class ) { 1259 // Lazily create the event: 1260 if ( e == null ) 1261 e = new ActionEvent(this,ActionEvent.ACTION_PERFORMED, 1262 getActionCommand(), 1263 mostRecentEventTime, modifiers); 1264 ((ActionListener)listeners[i+1]).actionPerformed(e); 1265 } 1266 } 1267 } finally { 1268 firingActionEvent = false; 1269 } 1270 } 1271 } 1272 1273 /** 1274 * This protected method is implementation specific. Do not access directly 1275 * or override. 1276 */ 1277 protected void selectedItemChanged() { 1278 if (selectedItemReminder != null ) { 1279 fireItemStateChanged(new ItemEvent(this,ItemEvent.ITEM_STATE_CHANGED, 1280 selectedItemReminder, 1281 ItemEvent.DESELECTED)); 1282 } 1283 1284 // set the new selected item. 1285 selectedItemReminder = dataModel.getSelectedItem(); 1286 1287 if (selectedItemReminder != null ) { 1288 fireItemStateChanged(new ItemEvent(this,ItemEvent.ITEM_STATE_CHANGED, 1289 selectedItemReminder, 1290 ItemEvent.SELECTED)); 1291 } 1292 } 1293 1294 /** 1295 * Returns an array containing the selected item. 1296 * This method is implemented for compatibility with 1297 * <code>ItemSelectable</code>. 1298 * 1299 * @return an array of <code>Objects</code> containing one 1300 * element -- the selected item 1301 */ 1302 @BeanProperty(bound = false) 1303 public Object[] getSelectedObjects() { 1304 Object selectedObject = getSelectedItem(); 1305 if ( selectedObject == null ) 1306 return new Object[0]; 1307 else { 1308 Object result[] = new Object[1]; 1309 result[0] = selectedObject; 1310 return result; 1311 } 1312 } 1313 1314 /** 1315 * This method is public as an implementation side effect. 1316 * do not call or override. 1317 */ 1318 public void actionPerformed(ActionEvent e) { 1319 setPopupVisible(false); 1320 getModel().setSelectedItem(getEditor().getItem()); 1321 String oldCommand = getActionCommand(); 1322 setActionCommand("comboBoxEdited"); 1323 fireActionEvent(); 1324 setActionCommand(oldCommand); 1325 } 1326 1327 /** 1328 * This method is public as an implementation side effect. 1329 * do not call or override. 1330 */ 1331 public void contentsChanged(ListDataEvent e) { 1332 Object oldSelection = selectedItemReminder; 1333 Object newSelection = dataModel.getSelectedItem(); 1334 if (oldSelection == null || !oldSelection.equals(newSelection)) { 1335 selectedItemChanged(); 1336 if (!selectingItem) { 1337 fireActionEvent(); 1338 } 1339 } 1340 } 1341 1342 /** 1343 * This method is public as an implementation side effect. 1344 * do not call or override. 1345 */ 1346 public void intervalAdded(ListDataEvent e) { 1347 if (selectedItemReminder != dataModel.getSelectedItem()) { 1348 selectedItemChanged(); 1349 } 1350 } 1351 1352 /** 1353 * This method is public as an implementation side effect. 1354 * do not call or override. 1355 */ 1356 public void intervalRemoved(ListDataEvent e) { 1357 contentsChanged(e); 1358 } 1359 1360 /** 1361 * Selects the list item that corresponds to the specified keyboard 1362 * character and returns true, if there is an item corresponding 1363 * to that character. Otherwise, returns false. 1364 * 1365 * @param keyChar a char, typically this is a keyboard key 1366 * typed by the user 1367 * @return {@code true} if there is an item corresponding to that character. 1368 * Otherwise, returns {@code false}. 1369 */ 1370 public boolean selectWithKeyChar(char keyChar) { 1371 int index; 1372 1373 if ( keySelectionManager == null ) 1374 keySelectionManager = createDefaultKeySelectionManager(); 1375 1376 index = keySelectionManager.selectionForKey(keyChar,getModel()); 1377 if ( index != -1 ) { 1378 setSelectedIndex(index); 1379 return true; 1380 } 1381 else 1382 return false; 1383 } 1384 1385 /** 1386 * Enables the combo box so that items can be selected. When the 1387 * combo box is disabled, items cannot be selected and values 1388 * cannot be typed into its field (if it is editable). 1389 * 1390 * @param b a boolean value, where true enables the component and 1391 * false disables it 1392 */ 1393 @BeanProperty(preferred = true, description 1394 = "The enabled state of the component.") 1395 public void setEnabled(boolean b) { 1396 super.setEnabled(b); 1397 firePropertyChange( "enabled", !isEnabled(), isEnabled() ); 1398 } 1399 1400 /** 1401 * Initializes the editor with the specified item. 1402 * 1403 * @param anEditor the <code>ComboBoxEditor</code> that displays 1404 * the list item in the 1405 * combo box field and allows it to be edited 1406 * @param anItem the object to display and edit in the field 1407 */ 1408 public void configureEditor(ComboBoxEditor anEditor, Object anItem) { 1409 anEditor.setItem(anItem); 1410 } 1411 1412 /** 1413 * Handles <code>KeyEvent</code>s, looking for the Tab key. 1414 * If the Tab key is found, the popup window is closed. 1415 * 1416 * @param e the <code>KeyEvent</code> containing the keyboard 1417 * key that was pressed 1418 */ 1419 public void processKeyEvent(KeyEvent e) { 1420 if ( e.getKeyCode() == KeyEvent.VK_TAB ) { 1421 hidePopup(); 1422 } 1423 super.processKeyEvent(e); 1424 } 1425 1426 /** 1427 * {@inheritDoc} 1428 */ 1429 @Override 1430 protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) { 1431 if (super.processKeyBinding(ks, e, condition, pressed)) { 1432 return true; 1433 } 1434 1435 if (!isEditable() || condition != WHEN_FOCUSED || getEditor() == null 1436 || !Boolean.TRUE.equals(getClientProperty("JComboBox.isTableCellEditor"))) { 1437 return false; 1438 } 1439 1440 Component editorComponent = getEditor().getEditorComponent(); 1441 if (editorComponent instanceof JComponent) { 1442 JComponent component = (JComponent) editorComponent; 1443 return component.processKeyBinding(ks, e, WHEN_FOCUSED, pressed); 1444 } 1445 return false; 1446 } 1447 1448 /** 1449 * Sets the object that translates a keyboard character into a list 1450 * selection. Typically, the first selection with a matching first 1451 * character becomes the selected item. 1452 * 1453 * @param aManager a key selection manager 1454 */ 1455 @BeanProperty(bound = false, expert = true, description 1456 = "The objects that changes the selection when a key is pressed.") 1457 public void setKeySelectionManager(KeySelectionManager aManager) { 1458 keySelectionManager = aManager; 1459 } 1460 1461 /** 1462 * Returns the list's key-selection manager. 1463 * 1464 * @return the <code>KeySelectionManager</code> currently in use 1465 */ 1466 public KeySelectionManager getKeySelectionManager() { 1467 return keySelectionManager; 1468 } 1469 1470 /* Accessing the model */ 1471 /** 1472 * Returns the number of items in the list. 1473 * 1474 * @return an integer equal to the number of items in the list 1475 */ 1476 @BeanProperty(bound = false) 1477 public int getItemCount() { 1478 return dataModel.getSize(); 1479 } 1480 1481 /** 1482 * Returns the list item at the specified index. If <code>index</code> 1483 * is out of range (less than zero or greater than or equal to size) 1484 * it will return <code>null</code>. 1485 * 1486 * @param index an integer indicating the list position, where the first 1487 * item starts at zero 1488 * @return the item at that list position; or 1489 * <code>null</code> if out of range 1490 */ 1491 public E getItemAt(int index) { 1492 return dataModel.getElementAt(index); 1493 } 1494 1495 /** 1496 * Returns an instance of the default key-selection manager. 1497 * 1498 * @return the <code>KeySelectionManager</code> currently used by the list 1499 * @see #setKeySelectionManager 1500 */ 1501 protected KeySelectionManager createDefaultKeySelectionManager() { 1502 return new DefaultKeySelectionManager(); 1503 } 1504 1505 1506 /** 1507 * The interface that defines a <code>KeySelectionManager</code>. 1508 * To qualify as a <code>KeySelectionManager</code>, 1509 * the class needs to implement the method 1510 * that identifies the list index given a character and the 1511 * combo box data model. 1512 */ 1513 public interface KeySelectionManager { 1514 /** Given <code>aKey</code> and the model, returns the row 1515 * that should become selected. Return -1 if no match was 1516 * found. 1517 * 1518 * @param aKey a char value, usually indicating a keyboard key that 1519 * was pressed 1520 * @param aModel a ComboBoxModel -- the component's data model, containing 1521 * the list of selectable items 1522 * @return an int equal to the selected row, where 0 is the 1523 * first item and -1 is none. 1524 */ 1525 int selectionForKey(char aKey,ComboBoxModel<?> aModel); 1526 } 1527 1528 class DefaultKeySelectionManager implements KeySelectionManager, Serializable { 1529 public int selectionForKey(char aKey,ComboBoxModel<?> aModel) { 1530 int i,c; 1531 int currentSelection = -1; 1532 Object selectedItem = aModel.getSelectedItem(); 1533 String v; 1534 String pattern; 1535 1536 if ( selectedItem != null ) { 1537 for ( i=0,c=aModel.getSize();i<c;i++ ) { 1538 if ( selectedItem == aModel.getElementAt(i) ) { 1539 currentSelection = i; 1540 break; 1541 } 1542 } 1543 } 1544 1545 pattern = ("" + aKey).toLowerCase(); 1546 aKey = pattern.charAt(0); 1547 1548 for ( i = ++currentSelection, c = aModel.getSize() ; i < c ; i++ ) { 1549 Object elem = aModel.getElementAt(i); 1550 if (elem != null && elem.toString() != null) { 1551 v = elem.toString().toLowerCase(); 1552 if ( v.length() > 0 && v.charAt(0) == aKey ) 1553 return i; 1554 } 1555 } 1556 1557 for ( i = 0 ; i < currentSelection ; i ++ ) { 1558 Object elem = aModel.getElementAt(i); 1559 if (elem != null && elem.toString() != null) { 1560 v = elem.toString().toLowerCase(); 1561 if ( v.length() > 0 && v.charAt(0) == aKey ) 1562 return i; 1563 } 1564 } 1565 return -1; 1566 } 1567 } 1568 1569 1570 /** 1571 * See <code>readObject</code> and <code>writeObject</code> in 1572 * <code>JComponent</code> for more 1573 * information about serialization in Swing. 1574 */ 1575 private void writeObject(ObjectOutputStream s) throws IOException { 1576 s.defaultWriteObject(); 1577 if (getUIClassID().equals(uiClassID)) { 1578 byte count = JComponent.getWriteObjCounter(this); 1579 JComponent.setWriteObjCounter(this, --count); 1580 if (count == 0 && ui != null) { 1581 ui.installUI(this); 1582 } 1583 } 1584 } 1585 1586 1587 /** 1588 * Returns a string representation of this <code>JComboBox</code>. 1589 * This method is intended to be used only for debugging purposes, 1590 * and the content and format of the returned string may vary between 1591 * implementations. The returned string may be empty but may not 1592 * be <code>null</code>. 1593 * 1594 * @return a string representation of this <code>JComboBox</code> 1595 */ 1596 protected String paramString() { 1597 String selectedItemReminderString = (selectedItemReminder != null ? 1598 selectedItemReminder.toString() : 1599 ""); 1600 String isEditableString = (isEditable ? "true" : "false"); 1601 String lightWeightPopupEnabledString = (lightWeightPopupEnabled ? 1602 "true" : "false"); 1603 1604 return super.paramString() + 1605 ",isEditable=" + isEditableString + 1606 ",lightWeightPopupEnabled=" + lightWeightPopupEnabledString + 1607 ",maximumRowCount=" + maximumRowCount + 1608 ",selectedItemReminder=" + selectedItemReminderString; 1609 } 1610 1611 1612 /////////////////// 1613 // Accessibility support 1614 /////////////////// 1615 1616 /** 1617 * Gets the AccessibleContext associated with this JComboBox. 1618 * For combo boxes, the AccessibleContext takes the form of an 1619 * AccessibleJComboBox. 1620 * A new AccessibleJComboBox instance is created if necessary. 1621 * 1622 * @return an AccessibleJComboBox that serves as the 1623 * AccessibleContext of this JComboBox 1624 */ 1625 @BeanProperty(bound = false) 1626 public AccessibleContext getAccessibleContext() { 1627 if ( accessibleContext == null ) { 1628 accessibleContext = new AccessibleJComboBox(); 1629 } 1630 return accessibleContext; 1631 } 1632 1633 /** 1634 * This class implements accessibility support for the 1635 * <code>JComboBox</code> class. It provides an implementation of the 1636 * Java Accessibility API appropriate to Combo Box user-interface elements. 1637 * <p> 1638 * <strong>Warning:</strong> 1639 * Serialized objects of this class will not be compatible with 1640 * future Swing releases. The current serialization support is 1641 * appropriate for short term storage or RMI between applications running 1642 * the same version of Swing. As of 1.4, support for long term storage 1643 * of all JavaBeans™ 1644 * has been added to the <code>java.beans</code> package. 1645 * Please see {@link java.beans.XMLEncoder}. 1646 */ 1647 @SuppressWarnings("serial") // Same-version serialization only 1648 protected class AccessibleJComboBox extends AccessibleJComponent 1649 implements AccessibleAction, AccessibleSelection { 1650 1651 1652 private JList<?> popupList; // combo box popup list 1653 private Accessible previousSelectedAccessible = null; 1654 1655 /** 1656 * Returns an AccessibleJComboBox instance 1657 * @since 1.4 1658 */ 1659 public AccessibleJComboBox() { 1660 // set the combo box editor's accessible name and description 1661 JComboBox.this.addPropertyChangeListener(new AccessibleJComboBoxPropertyChangeListener()); 1662 setEditorNameAndDescription(); 1663 1664 // Get the popup list 1665 Accessible a = getUI().getAccessibleChild(JComboBox.this, 0); 1666 if (a instanceof javax.swing.plaf.basic.ComboPopup) { 1667 // Listen for changes to the popup menu selection. 1668 popupList = ((javax.swing.plaf.basic.ComboPopup)a).getList(); 1669 popupList.addListSelectionListener( 1670 new AccessibleJComboBoxListSelectionListener()); 1671 } 1672 // Listen for popup menu show/hide events 1673 JComboBox.this.addPopupMenuListener( 1674 new AccessibleJComboBoxPopupMenuListener()); 1675 } 1676 1677 /* 1678 * JComboBox PropertyChangeListener 1679 */ 1680 private class AccessibleJComboBoxPropertyChangeListener 1681 implements PropertyChangeListener { 1682 1683 public void propertyChange(PropertyChangeEvent e) { 1684 if (e.getPropertyName() == "editor") { 1685 // set the combo box editor's accessible name 1686 // and description 1687 setEditorNameAndDescription(); 1688 } 1689 } 1690 } 1691 1692 /* 1693 * Sets the combo box editor's accessible name and descripton 1694 */ 1695 private void setEditorNameAndDescription() { 1696 ComboBoxEditor editor = JComboBox.this.getEditor(); 1697 if (editor != null) { 1698 Component comp = editor.getEditorComponent(); 1699 if (comp instanceof Accessible) { 1700 AccessibleContext ac = comp.getAccessibleContext(); 1701 if (ac != null) { // may be null 1702 ac.setAccessibleName(getAccessibleName()); 1703 ac.setAccessibleDescription(getAccessibleDescription()); 1704 } 1705 } 1706 } 1707 } 1708 1709 /* 1710 * Listener for combo box popup menu 1711 * TIGER - 4669379 4894434 1712 */ 1713 private class AccessibleJComboBoxPopupMenuListener 1714 implements PopupMenuListener { 1715 1716 /** 1717 * This method is called before the popup menu becomes visible 1718 */ 1719 public void popupMenuWillBecomeVisible(PopupMenuEvent e) { 1720 // save the initial selection 1721 if (popupList == null) { 1722 return; 1723 } 1724 int selectedIndex = popupList.getSelectedIndex(); 1725 if (selectedIndex < 0) { 1726 return; 1727 } 1728 previousSelectedAccessible = 1729 popupList.getAccessibleContext().getAccessibleChild(selectedIndex); 1730 } 1731 1732 /** 1733 * This method is called before the popup menu becomes invisible 1734 * Note that a JPopupMenu can become invisible any time 1735 */ 1736 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { 1737 // ignore 1738 } 1739 1740 /** 1741 * This method is called when the popup menu is canceled 1742 */ 1743 public void popupMenuCanceled(PopupMenuEvent e) { 1744 // ignore 1745 } 1746 } 1747 1748 /* 1749 * Handles changes to the popup list selection. 1750 * TIGER - 4669379 4894434 4933143 1751 */ 1752 private class AccessibleJComboBoxListSelectionListener 1753 implements ListSelectionListener { 1754 1755 public void valueChanged(ListSelectionEvent e) { 1756 if (popupList == null) { 1757 return; 1758 } 1759 1760 // Get the selected popup list item. 1761 int selectedIndex = popupList.getSelectedIndex(); 1762 if (selectedIndex < 0) { 1763 return; 1764 } 1765 Accessible selectedAccessible = 1766 popupList.getAccessibleContext().getAccessibleChild(selectedIndex); 1767 if (selectedAccessible == null) { 1768 return; 1769 } 1770 1771 // Fire a FOCUSED lost PropertyChangeEvent for the 1772 // previously selected list item. 1773 PropertyChangeEvent pce; 1774 1775 if (previousSelectedAccessible != null) { 1776 pce = new PropertyChangeEvent(previousSelectedAccessible, 1777 AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 1778 AccessibleState.FOCUSED, null); 1779 firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 1780 null, pce); 1781 } 1782 // Fire a FOCUSED gained PropertyChangeEvent for the 1783 // currently selected list item. 1784 pce = new PropertyChangeEvent(selectedAccessible, 1785 AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 1786 null, AccessibleState.FOCUSED); 1787 firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 1788 null, pce); 1789 1790 // Fire the ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY event 1791 // for the combo box. 1792 firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY, 1793 previousSelectedAccessible, selectedAccessible); 1794 1795 // Save the previous selection. 1796 previousSelectedAccessible = selectedAccessible; 1797 } 1798 } 1799 1800 1801 /** 1802 * Returns the number of accessible children in the object. If all 1803 * of the children of this object implement Accessible, than this 1804 * method should return the number of children of this object. 1805 * 1806 * @return the number of accessible children in the object. 1807 */ 1808 public int getAccessibleChildrenCount() { 1809 // Always delegate to the UI if it exists 1810 if (ui != null) { 1811 return ui.getAccessibleChildrenCount(JComboBox.this); 1812 } else { 1813 return super.getAccessibleChildrenCount(); 1814 } 1815 } 1816 1817 /** 1818 * Returns the nth Accessible child of the object. 1819 * The child at index zero represents the popup. 1820 * If the combo box is editable, the child at index one 1821 * represents the editor. 1822 * 1823 * @param i zero-based index of child 1824 * @return the nth Accessible child of the object 1825 */ 1826 public Accessible getAccessibleChild(int i) { 1827 // Always delegate to the UI if it exists 1828 if (ui != null) { 1829 return ui.getAccessibleChild(JComboBox.this, i); 1830 } else { 1831 return super.getAccessibleChild(i); 1832 } 1833 } 1834 1835 /** 1836 * Get the role of this object. 1837 * 1838 * @return an instance of AccessibleRole describing the role of the 1839 * object 1840 * @see AccessibleRole 1841 */ 1842 public AccessibleRole getAccessibleRole() { 1843 return AccessibleRole.COMBO_BOX; 1844 } 1845 1846 /** 1847 * Gets the state set of this object. The AccessibleStateSet of 1848 * an object is composed of a set of unique AccessibleStates. 1849 * A change in the AccessibleStateSet of an object will cause a 1850 * PropertyChangeEvent to be fired for the ACCESSIBLE_STATE_PROPERTY 1851 * property. 1852 * 1853 * @return an instance of AccessibleStateSet containing the 1854 * current state set of the object 1855 * @see AccessibleStateSet 1856 * @see AccessibleState 1857 * @see #addPropertyChangeListener 1858 * 1859 */ 1860 public AccessibleStateSet getAccessibleStateSet() { 1861 // TIGER - 4489748 1862 AccessibleStateSet ass = super.getAccessibleStateSet(); 1863 if (ass == null) { 1864 ass = new AccessibleStateSet(); 1865 } 1866 if (JComboBox.this.isPopupVisible()) { 1867 ass.add(AccessibleState.EXPANDED); 1868 } else { 1869 ass.add(AccessibleState.COLLAPSED); 1870 } 1871 return ass; 1872 } 1873 1874 /** 1875 * Get the AccessibleAction associated with this object. In the 1876 * implementation of the Java Accessibility API for this class, 1877 * return this object, which is responsible for implementing the 1878 * AccessibleAction interface on behalf of itself. 1879 * 1880 * @return this object 1881 */ 1882 public AccessibleAction getAccessibleAction() { 1883 return this; 1884 } 1885 1886 /** 1887 * Return a description of the specified action of the object. 1888 * 1889 * @param i zero-based index of the actions 1890 */ 1891 public String getAccessibleActionDescription(int i) { 1892 if (i == 0) { 1893 return UIManager.getString("ComboBox.togglePopupText"); 1894 } 1895 else { 1896 return null; 1897 } 1898 } 1899 1900 /** 1901 * Returns the number of Actions available in this object. The 1902 * default behavior of a combo box is to have one action. 1903 * 1904 * @return 1, the number of Actions in this object 1905 */ 1906 public int getAccessibleActionCount() { 1907 return 1; 1908 } 1909 1910 /** 1911 * Perform the specified Action on the object 1912 * 1913 * @param i zero-based index of actions 1914 * @return true if the action was performed; else false. 1915 */ 1916 public boolean doAccessibleAction(int i) { 1917 if (i == 0) { 1918 setPopupVisible(!isPopupVisible()); 1919 return true; 1920 } 1921 else { 1922 return false; 1923 } 1924 } 1925 1926 1927 /** 1928 * Get the AccessibleSelection associated with this object. In the 1929 * implementation of the Java Accessibility API for this class, 1930 * return this object, which is responsible for implementing the 1931 * AccessibleSelection interface on behalf of itself. 1932 * 1933 * @return this object 1934 */ 1935 public AccessibleSelection getAccessibleSelection() { 1936 return this; 1937 } 1938 1939 /** 1940 * Returns the number of Accessible children currently selected. 1941 * If no children are selected, the return value will be 0. 1942 * 1943 * @return the number of items currently selected. 1944 * @since 1.3 1945 */ 1946 public int getAccessibleSelectionCount() { 1947 Object o = JComboBox.this.getSelectedItem(); 1948 if (o != null) { 1949 return 1; 1950 } else { 1951 return 0; 1952 } 1953 } 1954 1955 /** 1956 * Returns an Accessible representing the specified selected child 1957 * in the popup. If there isn't a selection, or there are 1958 * fewer children selected than the integer passed in, the return 1959 * value will be null. 1960 * <p>Note that the index represents the i-th selected child, which 1961 * is different from the i-th child. 1962 * 1963 * @param i the zero-based index of selected children 1964 * @return the i-th selected child 1965 * @see #getAccessibleSelectionCount 1966 * @since 1.3 1967 */ 1968 public Accessible getAccessibleSelection(int i) { 1969 // Get the popup 1970 Accessible a = 1971 JComboBox.this.getUI().getAccessibleChild(JComboBox.this, 0); 1972 if (a != null && 1973 a instanceof javax.swing.plaf.basic.ComboPopup) { 1974 1975 // get the popup list 1976 JList<?> list = ((javax.swing.plaf.basic.ComboPopup)a).getList(); 1977 1978 // return the i-th selection in the popup list 1979 AccessibleContext ac = list.getAccessibleContext(); 1980 if (ac != null) { 1981 AccessibleSelection as = ac.getAccessibleSelection(); 1982 if (as != null) { 1983 return as.getAccessibleSelection(i); 1984 } 1985 } 1986 } 1987 return null; 1988 } 1989 1990 /** 1991 * Determines if the current child of this object is selected. 1992 * 1993 * @return true if the current child of this object is selected; 1994 * else false 1995 * @param i the zero-based index of the child in this Accessible 1996 * object. 1997 * @see AccessibleContext#getAccessibleChild 1998 * @since 1.3 1999 */ 2000 public boolean isAccessibleChildSelected(int i) { 2001 return JComboBox.this.getSelectedIndex() == i; 2002 } 2003 2004 /** 2005 * Adds the specified Accessible child of the object to the object's 2006 * selection. If the object supports multiple selections, 2007 * the specified child is added to any existing selection, otherwise 2008 * it replaces any existing selection in the object. If the 2009 * specified child is already selected, this method has no effect. 2010 * 2011 * @param i the zero-based index of the child 2012 * @see AccessibleContext#getAccessibleChild 2013 * @since 1.3 2014 */ 2015 public void addAccessibleSelection(int i) { 2016 // TIGER - 4856195 2017 clearAccessibleSelection(); 2018 JComboBox.this.setSelectedIndex(i); 2019 } 2020 2021 /** 2022 * Removes the specified child of the object from the object's 2023 * selection. If the specified item isn't currently selected, this 2024 * method has no effect. 2025 * 2026 * @param i the zero-based index of the child 2027 * @see AccessibleContext#getAccessibleChild 2028 * @since 1.3 2029 */ 2030 public void removeAccessibleSelection(int i) { 2031 if (JComboBox.this.getSelectedIndex() == i) { 2032 clearAccessibleSelection(); 2033 } 2034 } 2035 2036 /** 2037 * Clears the selection in the object, so that no children in the 2038 * object are selected. 2039 * @since 1.3 2040 */ 2041 public void clearAccessibleSelection() { 2042 JComboBox.this.setSelectedIndex(-1); 2043 } 2044 2045 /** 2046 * Causes every child of the object to be selected 2047 * if the object supports multiple selections. 2048 * @since 1.3 2049 */ 2050 public void selectAllAccessibleSelection() { 2051 // do nothing since multiple selection is not supported 2052 } 2053 2054 // public Accessible getAccessibleAt(Point p) { 2055 // Accessible a = getAccessibleChild(1); 2056 // if ( a != null ) { 2057 // return a; // the editor 2058 // } 2059 // else { 2060 // return getAccessibleChild(0); // the list 2061 // } 2062 // } 2063 private EditorAccessibleContext editorAccessibleContext = null; 2064 2065 private class AccessibleEditor implements Accessible { 2066 public AccessibleContext getAccessibleContext() { 2067 if (editorAccessibleContext == null) { 2068 Component c = JComboBox.this.getEditor().getEditorComponent(); 2069 if (c instanceof Accessible) { 2070 editorAccessibleContext = 2071 new EditorAccessibleContext((Accessible)c); 2072 } 2073 } 2074 return editorAccessibleContext; 2075 } 2076 } 2077 2078 /* 2079 * Wrapper class for the AccessibleContext implemented by the 2080 * combo box editor. Delegates all method calls except 2081 * getAccessibleIndexInParent to the editor. The 2082 * getAccessibleIndexInParent method returns the selected 2083 * index in the combo box. 2084 */ 2085 private class EditorAccessibleContext extends AccessibleContext { 2086 2087 private AccessibleContext ac; 2088 2089 private EditorAccessibleContext() { 2090 } 2091 2092 /* 2093 * @param a the AccessibleContext implemented by the 2094 * combo box editor 2095 */ 2096 EditorAccessibleContext(Accessible a) { 2097 this.ac = a.getAccessibleContext(); 2098 } 2099 2100 /** 2101 * Gets the accessibleName property of this object. The accessibleName 2102 * property of an object is a localized String that designates the purpose 2103 * of the object. For example, the accessibleName property of a label 2104 * or button might be the text of the label or button itself. In the 2105 * case of an object that doesn't display its name, the accessibleName 2106 * should still be set. For example, in the case of a text field used 2107 * to enter the name of a city, the accessibleName for the en_US locale 2108 * could be 'city.' 2109 * 2110 * @return the localized name of the object; null if this 2111 * object does not have a name 2112 * 2113 * @see #setAccessibleName 2114 */ 2115 public String getAccessibleName() { 2116 return ac.getAccessibleName(); 2117 } 2118 2119 /** 2120 * Sets the localized accessible name of this object. Changing the 2121 * name will cause a PropertyChangeEvent to be fired for the 2122 * ACCESSIBLE_NAME_PROPERTY property. 2123 * 2124 * @param s the new localized name of the object. 2125 * 2126 * @see #getAccessibleName 2127 * @see #addPropertyChangeListener 2128 */ 2129 @BeanProperty(preferred = true, description 2130 = "Sets the accessible name for the component.") 2131 public void setAccessibleName(String s) { 2132 ac.setAccessibleName(s); 2133 } 2134 2135 /** 2136 * Gets the accessibleDescription property of this object. The 2137 * accessibleDescription property of this object is a short localized 2138 * phrase describing the purpose of the object. For example, in the 2139 * case of a 'Cancel' button, the accessibleDescription could be 2140 * 'Ignore changes and close dialog box.' 2141 * 2142 * @return the localized description of the object; null if 2143 * this object does not have a description 2144 * 2145 * @see #setAccessibleDescription 2146 */ 2147 public String getAccessibleDescription() { 2148 return ac.getAccessibleDescription(); 2149 } 2150 2151 /** 2152 * Sets the accessible description of this object. Changing the 2153 * name will cause a PropertyChangeEvent to be fired for the 2154 * ACCESSIBLE_DESCRIPTION_PROPERTY property. 2155 * 2156 * @param s the new localized description of the object 2157 * 2158 * @see #setAccessibleName 2159 * @see #addPropertyChangeListener 2160 */ 2161 @BeanProperty(preferred = true, description 2162 = "Sets the accessible description for the component.") 2163 public void setAccessibleDescription(String s) { 2164 ac.setAccessibleDescription(s); 2165 } 2166 2167 /** 2168 * Gets the role of this object. The role of the object is the generic 2169 * purpose or use of the class of this object. For example, the role 2170 * of a push button is AccessibleRole.PUSH_BUTTON. The roles in 2171 * AccessibleRole are provided so component developers can pick from 2172 * a set of predefined roles. This enables assistive technologies to 2173 * provide a consistent interface to various tweaked subclasses of 2174 * components (e.g., use AccessibleRole.PUSH_BUTTON for all components 2175 * that act like a push button) as well as distinguish between subclasses 2176 * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes 2177 * and AccessibleRole.RADIO_BUTTON for radio buttons). 2178 * <p>Note that the AccessibleRole class is also extensible, so 2179 * custom component developers can define their own AccessibleRole's 2180 * if the set of predefined roles is inadequate. 2181 * 2182 * @return an instance of AccessibleRole describing the role of the object 2183 * @see AccessibleRole 2184 */ 2185 public AccessibleRole getAccessibleRole() { 2186 return ac.getAccessibleRole(); 2187 } 2188 2189 /** 2190 * Gets the state set of this object. The AccessibleStateSet of an object 2191 * is composed of a set of unique AccessibleStates. A change in the 2192 * AccessibleStateSet of an object will cause a PropertyChangeEvent to 2193 * be fired for the ACCESSIBLE_STATE_PROPERTY property. 2194 * 2195 * @return an instance of AccessibleStateSet containing the 2196 * current state set of the object 2197 * @see AccessibleStateSet 2198 * @see AccessibleState 2199 * @see #addPropertyChangeListener 2200 */ 2201 public AccessibleStateSet getAccessibleStateSet() { 2202 return ac.getAccessibleStateSet(); 2203 } 2204 2205 /** 2206 * Gets the Accessible parent of this object. 2207 * 2208 * @return the Accessible parent of this object; null if this 2209 * object does not have an Accessible parent 2210 */ 2211 public Accessible getAccessibleParent() { 2212 return ac.getAccessibleParent(); 2213 } 2214 2215 /** 2216 * Sets the Accessible parent of this object. This is meant to be used 2217 * only in the situations where the actual component's parent should 2218 * not be treated as the component's accessible parent and is a method 2219 * that should only be called by the parent of the accessible child. 2220 * 2221 * @param a - Accessible to be set as the parent 2222 */ 2223 public void setAccessibleParent(Accessible a) { 2224 ac.setAccessibleParent(a); 2225 } 2226 2227 /** 2228 * Gets the 0-based index of this object in its accessible parent. 2229 * 2230 * @return the 0-based index of this object in its parent; -1 if this 2231 * object does not have an accessible parent. 2232 * 2233 * @see #getAccessibleParent 2234 * @see #getAccessibleChildrenCount 2235 * @see #getAccessibleChild 2236 */ 2237 public int getAccessibleIndexInParent() { 2238 return JComboBox.this.getSelectedIndex(); 2239 } 2240 2241 /** 2242 * Returns the number of accessible children of the object. 2243 * 2244 * @return the number of accessible children of the object. 2245 */ 2246 public int getAccessibleChildrenCount() { 2247 return ac.getAccessibleChildrenCount(); 2248 } 2249 2250 /** 2251 * Returns the specified Accessible child of the object. The Accessible 2252 * children of an Accessible object are zero-based, so the first child 2253 * of an Accessible child is at index 0, the second child is at index 1, 2254 * and so on. 2255 * 2256 * @param i zero-based index of child 2257 * @return the Accessible child of the object 2258 * @see #getAccessibleChildrenCount 2259 */ 2260 public Accessible getAccessibleChild(int i) { 2261 return ac.getAccessibleChild(i); 2262 } 2263 2264 /** 2265 * Gets the locale of the component. If the component does not have a 2266 * locale, then the locale of its parent is returned. 2267 * 2268 * @return this component's locale. If this component does not have 2269 * a locale, the locale of its parent is returned. 2270 * 2271 * @exception IllegalComponentStateException 2272 * If the Component does not have its own locale and has not yet been 2273 * added to a containment hierarchy such that the locale can be 2274 * determined from the containing parent. 2275 */ 2276 public Locale getLocale() throws IllegalComponentStateException { 2277 return ac.getLocale(); 2278 } 2279 2280 /** 2281 * Adds a PropertyChangeListener to the listener list. 2282 * The listener is registered for all Accessible properties and will 2283 * be called when those properties change. 2284 * 2285 * @see #ACCESSIBLE_NAME_PROPERTY 2286 * @see #ACCESSIBLE_DESCRIPTION_PROPERTY 2287 * @see #ACCESSIBLE_STATE_PROPERTY 2288 * @see #ACCESSIBLE_VALUE_PROPERTY 2289 * @see #ACCESSIBLE_SELECTION_PROPERTY 2290 * @see #ACCESSIBLE_TEXT_PROPERTY 2291 * @see #ACCESSIBLE_VISIBLE_DATA_PROPERTY 2292 * 2293 * @param listener The PropertyChangeListener to be added 2294 */ 2295 public void addPropertyChangeListener(PropertyChangeListener listener) { 2296 ac.addPropertyChangeListener(listener); 2297 } 2298 2299 /** 2300 * Removes a PropertyChangeListener from the listener list. 2301 * This removes a PropertyChangeListener that was registered 2302 * for all properties. 2303 * 2304 * @param listener The PropertyChangeListener to be removed 2305 */ 2306 public void removePropertyChangeListener(PropertyChangeListener listener) { 2307 ac.removePropertyChangeListener(listener); 2308 } 2309 2310 /** 2311 * Gets the AccessibleAction associated with this object that supports 2312 * one or more actions. 2313 * 2314 * @return AccessibleAction if supported by object; else return null 2315 * @see AccessibleAction 2316 */ 2317 public AccessibleAction getAccessibleAction() { 2318 return ac.getAccessibleAction(); 2319 } 2320 2321 /** 2322 * Gets the AccessibleComponent associated with this object that has a 2323 * graphical representation. 2324 * 2325 * @return AccessibleComponent if supported by object; else return null 2326 * @see AccessibleComponent 2327 */ 2328 public AccessibleComponent getAccessibleComponent() { 2329 return ac.getAccessibleComponent(); 2330 } 2331 2332 /** 2333 * Gets the AccessibleSelection associated with this object which allows its 2334 * Accessible children to be selected. 2335 * 2336 * @return AccessibleSelection if supported by object; else return null 2337 * @see AccessibleSelection 2338 */ 2339 public AccessibleSelection getAccessibleSelection() { 2340 return ac.getAccessibleSelection(); 2341 } 2342 2343 /** 2344 * Gets the AccessibleText associated with this object presenting 2345 * text on the display. 2346 * 2347 * @return AccessibleText if supported by object; else return null 2348 * @see AccessibleText 2349 */ 2350 public AccessibleText getAccessibleText() { 2351 return ac.getAccessibleText(); 2352 } 2353 2354 /** 2355 * Gets the AccessibleEditableText associated with this object 2356 * presenting editable text on the display. 2357 * 2358 * @return AccessibleEditableText if supported by object; else return null 2359 * @see AccessibleEditableText 2360 */ 2361 public AccessibleEditableText getAccessibleEditableText() { 2362 return ac.getAccessibleEditableText(); 2363 } 2364 2365 /** 2366 * Gets the AccessibleValue associated with this object that supports a 2367 * Numerical value. 2368 * 2369 * @return AccessibleValue if supported by object; else return null 2370 * @see AccessibleValue 2371 */ 2372 public AccessibleValue getAccessibleValue() { 2373 return ac.getAccessibleValue(); 2374 } 2375 2376 /** 2377 * Gets the AccessibleIcons associated with an object that has 2378 * one or more associated icons 2379 * 2380 * @return an array of AccessibleIcon if supported by object; 2381 * otherwise return null 2382 * @see AccessibleIcon 2383 */ 2384 public AccessibleIcon [] getAccessibleIcon() { 2385 return ac.getAccessibleIcon(); 2386 } 2387 2388 /** 2389 * Gets the AccessibleRelationSet associated with an object 2390 * 2391 * @return an AccessibleRelationSet if supported by object; 2392 * otherwise return null 2393 * @see AccessibleRelationSet 2394 */ 2395 public AccessibleRelationSet getAccessibleRelationSet() { 2396 return ac.getAccessibleRelationSet(); 2397 } 2398 2399 /** 2400 * Gets the AccessibleTable associated with an object 2401 * 2402 * @return an AccessibleTable if supported by object; 2403 * otherwise return null 2404 * @see AccessibleTable 2405 */ 2406 public AccessibleTable getAccessibleTable() { 2407 return ac.getAccessibleTable(); 2408 } 2409 2410 /** 2411 * Support for reporting bound property changes. If oldValue and 2412 * newValue are not equal and the PropertyChangeEvent listener list 2413 * is not empty, then fire a PropertyChange event to each listener. 2414 * In general, this is for use by the Accessible objects themselves 2415 * and should not be called by an application program. 2416 * @param propertyName The programmatic name of the property that 2417 * was changed. 2418 * @param oldValue The old value of the property. 2419 * @param newValue The new value of the property. 2420 * @see java.beans.PropertyChangeSupport 2421 * @see #addPropertyChangeListener 2422 * @see #removePropertyChangeListener 2423 * @see #ACCESSIBLE_NAME_PROPERTY 2424 * @see #ACCESSIBLE_DESCRIPTION_PROPERTY 2425 * @see #ACCESSIBLE_STATE_PROPERTY 2426 * @see #ACCESSIBLE_VALUE_PROPERTY 2427 * @see #ACCESSIBLE_SELECTION_PROPERTY 2428 * @see #ACCESSIBLE_TEXT_PROPERTY 2429 * @see #ACCESSIBLE_VISIBLE_DATA_PROPERTY 2430 */ 2431 public void firePropertyChange(String propertyName, 2432 Object oldValue, 2433 Object newValue) { 2434 ac.firePropertyChange(propertyName, oldValue, newValue); 2435 } 2436 } 2437 2438 } // innerclass AccessibleJComboBox 2439 }