0001 /*
0002 * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025 package javax.swing;
0026
0027 import java.beans.*;
0028 import java.util.*;
0029
0030 import java.awt.*;
0031 import java.awt.event.*;
0032
0033 import java.io.Serializable;
0034 import java.io.ObjectOutputStream;
0035 import java.io.ObjectInputStream;
0036 import java.io.IOException;
0037
0038 import javax.swing.event.*;
0039 import javax.swing.plaf.*;
0040 import javax.swing.border.*;
0041
0042 import javax.accessibility.*;
0043
0044 /**
0045 * A component that combines a button or editable field and a drop-down list.
0046 * The user can select a value from the drop-down list, which appears at the
0047 * user's request. If you make the combo box editable, then the combo box
0048 * includes an editable field into which the user can type a value.
0049 * <p>
0050 * <strong>Warning:</strong> Swing is not thread safe. For more
0051 * information see <a
0052 * href="package-summary.html#threading">Swing's Threading
0053 * Policy</a>.
0054 * <p>
0055 * <strong>Warning:</strong>
0056 * Serialized objects of this class will not be compatible with
0057 * future Swing releases. The current serialization support is
0058 * appropriate for short term storage or RMI between applications running
0059 * the same version of Swing. As of 1.4, support for long term storage
0060 * of all JavaBeans<sup><font size="-2">TM</font></sup>
0061 * has been added to the <code>java.beans</code> package.
0062 * Please see {@link java.beans.XMLEncoder}.
0063 *
0064 * <p>
0065 * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/combobox.html">How to Use Combo Boxes</a>
0066 * in <a href="http://java.sun.com/Series/Tutorial/index.html"><em>The Java Tutorial</em></a>
0067 * for further information.
0068 * <p>
0069 * @see ComboBoxModel
0070 * @see DefaultComboBoxModel
0071 *
0072 * @beaninfo
0073 * attribute: isContainer false
0074 * description: A combination of a text field and a drop-down list.
0075 *
0076 * @version 1.147 05/05/07
0077 * @author Arnaud Weber
0078 * @author Mark Davidson
0079 */
0080 public class JComboBox extends JComponent implements ItemSelectable,
0081 ListDataListener, ActionListener, Accessible {
0082 /**
0083 * @see #getUIClassID
0084 * @see #readObject
0085 */
0086 private static final String uiClassID = "ComboBoxUI";
0087
0088 /**
0089 * This protected field is implementation specific. Do not access directly
0090 * or override. Use the accessor methods instead.
0091 *
0092 * @see #getModel
0093 * @see #setModel
0094 */
0095 protected ComboBoxModel dataModel;
0096 /**
0097 * This protected field is implementation specific. Do not access directly
0098 * or override. Use the accessor methods instead.
0099 *
0100 * @see #getRenderer
0101 * @see #setRenderer
0102 */
0103 protected ListCellRenderer renderer;
0104 /**
0105 * This protected field is implementation specific. Do not access directly
0106 * or override. Use the accessor methods instead.
0107 *
0108 * @see #getEditor
0109 * @see #setEditor
0110 */
0111 protected ComboBoxEditor editor;
0112 /**
0113 * This protected field is implementation specific. Do not access directly
0114 * or override. Use the accessor methods instead.
0115 *
0116 * @see #getMaximumRowCount
0117 * @see #setMaximumRowCount
0118 */
0119 protected int maximumRowCount = 8;
0120
0121 /**
0122 * This protected field is implementation specific. Do not access directly
0123 * or override. Use the accessor methods instead.
0124 *
0125 * @see #isEditable
0126 * @see #setEditable
0127 */
0128 protected boolean isEditable = false;
0129 /**
0130 * This protected field is implementation specific. Do not access directly
0131 * or override. Use the accessor methods instead.
0132 *
0133 * @see #setKeySelectionManager
0134 * @see #getKeySelectionManager
0135 */
0136 protected KeySelectionManager keySelectionManager = null;
0137 /**
0138 * This protected field is implementation specific. Do not access directly
0139 * or override. Use the accessor methods instead.
0140 *
0141 * @see #setActionCommand
0142 * @see #getActionCommand
0143 */
0144 protected String actionCommand = "comboBoxChanged";
0145 /**
0146 * This protected field is implementation specific. Do not access directly
0147 * or override. Use the accessor methods instead.
0148 *
0149 * @see #setLightWeightPopupEnabled
0150 * @see #isLightWeightPopupEnabled
0151 */
0152 protected boolean lightWeightPopupEnabled = JPopupMenu
0153 .getDefaultLightWeightPopupEnabled();
0154
0155 /**
0156 * This protected field is implementation specific. Do not access directly
0157 * or override.
0158 */
0159 protected Object selectedItemReminder = null;
0160
0161 private Object prototypeDisplayValue;
0162
0163 // Flag to ensure that infinite loops do not occur with ActionEvents.
0164 private boolean firingActionEvent = false;
0165
0166 // Flag to ensure the we don't get multiple ActionEvents on item selection.
0167 private boolean selectingItem = false;
0168
0169 /**
0170 * Creates a <code>JComboBox</code> that takes its items from an
0171 * existing <code>ComboBoxModel</code>. Since the
0172 * <code>ComboBoxModel</code> is provided, a combo box created using
0173 * this constructor does not create a default combo box model and
0174 * may impact how the insert, remove and add methods behave.
0175 *
0176 * @param aModel the <code>ComboBoxModel</code> that provides the
0177 * displayed list of items
0178 * @see DefaultComboBoxModel
0179 */
0180 public JComboBox(ComboBoxModel aModel) {
0181 super ();
0182 setModel(aModel);
0183 init();
0184 }
0185
0186 /**
0187 * Creates a <code>JComboBox</code> that contains the elements
0188 * in the specified array. By default the first item in the array
0189 * (and therefore the data model) becomes selected.
0190 *
0191 * @param items an array of objects to insert into the combo box
0192 * @see DefaultComboBoxModel
0193 */
0194 public JComboBox(final Object items[]) {
0195 super ();
0196 setModel(new DefaultComboBoxModel(items));
0197 init();
0198 }
0199
0200 /**
0201 * Creates a <code>JComboBox</code> that contains the elements
0202 * in the specified Vector. By default the first item in the vector
0203 * (and therefore the data model) becomes selected.
0204 *
0205 * @param items an array of vectors to insert into the combo box
0206 * @see DefaultComboBoxModel
0207 */
0208 public JComboBox(Vector<?> items) {
0209 super ();
0210 setModel(new DefaultComboBoxModel(items));
0211 init();
0212 }
0213
0214 /**
0215 * Creates a <code>JComboBox</code> with a default data model.
0216 * The default data model is an empty list of objects.
0217 * Use <code>addItem</code> to add items. By default the first item
0218 * in the data model becomes selected.
0219 *
0220 * @see DefaultComboBoxModel
0221 */
0222 public JComboBox() {
0223 super ();
0224 setModel(new DefaultComboBoxModel());
0225 init();
0226 }
0227
0228 private void init() {
0229 installAncestorListener();
0230 setOpaque(true);
0231 updateUI();
0232 }
0233
0234 protected void installAncestorListener() {
0235 addAncestorListener(new AncestorListener() {
0236 public void ancestorAdded(AncestorEvent event) {
0237 hidePopup();
0238 }
0239
0240 public void ancestorRemoved(AncestorEvent event) {
0241 hidePopup();
0242 }
0243
0244 public void ancestorMoved(AncestorEvent event) {
0245 if (event.getSource() != JComboBox.this )
0246 hidePopup();
0247 }
0248 });
0249 }
0250
0251 /**
0252 * Sets the L&F object that renders this component.
0253 *
0254 * @param ui the <code>ComboBoxUI</code> L&F object
0255 * @see UIDefaults#getUI
0256 *
0257 * @beaninfo
0258 * bound: true
0259 * hidden: true
0260 * attribute: visualUpdate true
0261 * description: The UI object that implements the Component's LookAndFeel.
0262 */
0263 public void setUI(ComboBoxUI ui) {
0264 super .setUI(ui);
0265 }
0266
0267 /**
0268 * Resets the UI property to a value from the current look and feel.
0269 *
0270 * @see JComponent#updateUI
0271 */
0272 public void updateUI() {
0273 setUI((ComboBoxUI) UIManager.getUI(this ));
0274
0275 ListCellRenderer renderer = getRenderer();
0276 if (renderer instanceof Component) {
0277 SwingUtilities.updateComponentTreeUI((Component) renderer);
0278 }
0279 }
0280
0281 /**
0282 * Returns the name of the L&F class that renders this component.
0283 *
0284 * @return the string "ComboBoxUI"
0285 * @see JComponent#getUIClassID
0286 * @see UIDefaults#getUI
0287 */
0288 public String getUIClassID() {
0289 return uiClassID;
0290 }
0291
0292 /**
0293 * Returns the L&F object that renders this component.
0294 *
0295 * @return the ComboBoxUI object that renders this component
0296 */
0297 public ComboBoxUI getUI() {
0298 return (ComboBoxUI) ui;
0299 }
0300
0301 /**
0302 * Sets the data model that the <code>JComboBox</code> uses to obtain
0303 * the list of items.
0304 *
0305 * @param aModel the <code>ComboBoxModel</code> that provides the
0306 * displayed list of items
0307 *
0308 * @beaninfo
0309 * bound: true
0310 * description: Model that the combo box uses to get data to display.
0311 */
0312 public void setModel(ComboBoxModel aModel) {
0313 ComboBoxModel oldModel = dataModel;
0314 if (oldModel != null) {
0315 oldModel.removeListDataListener(this );
0316 }
0317 dataModel = aModel;
0318 dataModel.addListDataListener(this );
0319
0320 // set the current selected item.
0321 selectedItemReminder = dataModel.getSelectedItem();
0322
0323 firePropertyChange("model", oldModel, dataModel);
0324 }
0325
0326 /**
0327 * Returns the data model currently used by the <code>JComboBox</code>.
0328 *
0329 * @return the <code>ComboBoxModel</code> that provides the displayed
0330 * list of items
0331 */
0332 public ComboBoxModel getModel() {
0333 return dataModel;
0334 }
0335
0336 /*
0337 * Properties
0338 */
0339
0340 /**
0341 * Sets the <code>lightWeightPopupEnabled</code> property, which
0342 * provides a hint as to whether or not a lightweight
0343 * <code>Component</code> should be used to contain the
0344 * <code>JComboBox</code>, versus a heavyweight
0345 * <code>Component</code> such as a <code>Panel</code>
0346 * or a <code>Window</code>. The decision of lightweight
0347 * versus heavyweight is ultimately up to the
0348 * <code>JComboBox</code>. Lightweight windows are more
0349 * efficient than heavyweight windows, but lightweight
0350 * and heavyweight components do not mix well in a GUI.
0351 * If your application mixes lightweight and heavyweight
0352 * components, you should disable lightweight popups.
0353 * The default value for the <code>lightWeightPopupEnabled</code>
0354 * property is <code>true</code>, unless otherwise specified
0355 * by the look and feel. Some look and feels always use
0356 * heavyweight popups, no matter what the value of this property.
0357 * <p>
0358 * See the article <a href="http://java.sun.com/products/jfc/tsc/articles/mixing/index.html">Mixing Heavy and Light Components</a>
0359 * on <a href="http://java.sun.com/products/jfc/tsc">
0360 * <em>The Swing Connection</em></a>
0361 * This method fires a property changed event.
0362 *
0363 * @param aFlag if <code>true</code>, lightweight popups are desired
0364 *
0365 * @beaninfo
0366 * bound: true
0367 * expert: true
0368 * description: Set to <code>false</code> to require heavyweight popups.
0369 */
0370 public void setLightWeightPopupEnabled(boolean aFlag) {
0371 boolean oldFlag = lightWeightPopupEnabled;
0372 lightWeightPopupEnabled = aFlag;
0373 firePropertyChange("lightWeightPopupEnabled", oldFlag,
0374 lightWeightPopupEnabled);
0375 }
0376
0377 /**
0378 * Gets the value of the <code>lightWeightPopupEnabled</code>
0379 * property.
0380 *
0381 * @return the value of the <code>lightWeightPopupEnabled</code>
0382 * property
0383 * @see #setLightWeightPopupEnabled
0384 */
0385 public boolean isLightWeightPopupEnabled() {
0386 return lightWeightPopupEnabled;
0387 }
0388
0389 /**
0390 * Determines whether the <code>JComboBox</code> field is editable.
0391 * An editable <code>JComboBox</code> allows the user to type into the
0392 * field or selected an item from the list to initialize the field,
0393 * after which it can be edited. (The editing affects only the field,
0394 * the list item remains intact.) A non editable <code>JComboBox</code>
0395 * displays the selected item in the field,
0396 * but the selection cannot be modified.
0397 *
0398 * @param aFlag a boolean value, where true indicates that the
0399 * field is editable
0400 *
0401 * @beaninfo
0402 * bound: true
0403 * preferred: true
0404 * description: If true, the user can type a new value in the combo box.
0405 */
0406 public void setEditable(boolean aFlag) {
0407 boolean oldFlag = isEditable;
0408 isEditable = aFlag;
0409 firePropertyChange("editable", oldFlag, isEditable);
0410 }
0411
0412 /**
0413 * Returns true if the <code>JComboBox</code> is editable.
0414 * By default, a combo box is not editable.
0415 *
0416 * @return true if the <code>JComboBox</code> is editable, else false
0417 */
0418 public boolean isEditable() {
0419 return isEditable;
0420 }
0421
0422 /**
0423 * Sets the maximum number of rows the <code>JComboBox</code> displays.
0424 * If the number of objects in the model is greater than count,
0425 * the combo box uses a scrollbar.
0426 *
0427 * @param count an integer specifying the maximum number of items to
0428 * display in the list before using a scrollbar
0429 * @beaninfo
0430 * bound: true
0431 * preferred: true
0432 * description: The maximum number of rows the popup should have
0433 */
0434 public void setMaximumRowCount(int count) {
0435 int oldCount = maximumRowCount;
0436 maximumRowCount = count;
0437 firePropertyChange("maximumRowCount", oldCount, maximumRowCount);
0438 }
0439
0440 /**
0441 * Returns the maximum number of items the combo box can display
0442 * without a scrollbar
0443 *
0444 * @return an integer specifying the maximum number of items that are
0445 * displayed in the list before using a scrollbar
0446 */
0447 public int getMaximumRowCount() {
0448 return maximumRowCount;
0449 }
0450
0451 /**
0452 * Sets the renderer that paints the list items and the item selected from the list in
0453 * the JComboBox field. The renderer is used if the JComboBox is not
0454 * editable. If it is editable, the editor is used to render and edit
0455 * the selected item.
0456 * <p>
0457 * The default renderer displays a string or an icon.
0458 * Other renderers can handle graphic images and composite items.
0459 * <p>
0460 * To display the selected item,
0461 * <code>aRenderer.getListCellRendererComponent</code>
0462 * is called, passing the list object and an index of -1.
0463 *
0464 * @param aRenderer the <code>ListCellRenderer</code> that
0465 * displays the selected item
0466 * @see #setEditor
0467 * @beaninfo
0468 * bound: true
0469 * expert: true
0470 * description: The renderer that paints the item selected in the list.
0471 */
0472 public void setRenderer(ListCellRenderer aRenderer) {
0473 ListCellRenderer oldRenderer = renderer;
0474 renderer = aRenderer;
0475 firePropertyChange("renderer", oldRenderer, renderer);
0476 invalidate();
0477 }
0478
0479 /**
0480 * Returns the renderer used to display the selected item in the
0481 * <code>JComboBox</code> field.
0482 *
0483 * @return the <code>ListCellRenderer</code> that displays
0484 * the selected item.
0485 */
0486 public ListCellRenderer getRenderer() {
0487 return renderer;
0488 }
0489
0490 /**
0491 * Sets the editor used to paint and edit the selected item in the
0492 * <code>JComboBox</code> field. The editor is used only if the
0493 * receiving <code>JComboBox</code> is editable. If not editable,
0494 * the combo box uses the renderer to paint the selected item.
0495 *
0496 * @param anEditor the <code>ComboBoxEditor</code> that
0497 * displays the selected item
0498 * @see #setRenderer
0499 * @beaninfo
0500 * bound: true
0501 * expert: true
0502 * description: The editor that combo box uses to edit the current value
0503 */
0504 public void setEditor(ComboBoxEditor anEditor) {
0505 ComboBoxEditor oldEditor = editor;
0506
0507 if (editor != null) {
0508 editor.removeActionListener(this );
0509 }
0510 editor = anEditor;
0511 if (editor != null) {
0512 editor.addActionListener(this );
0513 }
0514 firePropertyChange("editor", oldEditor, editor);
0515 }
0516
0517 /**
0518 * Returns the editor used to paint and edit the selected item in the
0519 * <code>JComboBox</code> field.
0520 *
0521 * @return the <code>ComboBoxEditor</code> that displays the selected item
0522 */
0523 public ComboBoxEditor getEditor() {
0524 return editor;
0525 }
0526
0527 //
0528 // Selection
0529 //
0530
0531 /**
0532 * Sets the selected item in the combo box display area to the object in
0533 * the argument.
0534 * If <code>anObject</code> is in the list, the display area shows
0535 * <code>anObject</code> selected.
0536 * <p>
0537 * If <code>anObject</code> is <i>not</i> in the list and the combo box is
0538 * uneditable, it will not change the current selection. For editable
0539 * combo boxes, the selection will change to <code>anObject</code>.
0540 * <p>
0541 * If this constitutes a change in the selected item,
0542 * <code>ItemListener</code>s added to the combo box will be notified with
0543 * one or two <code>ItemEvent</code>s.
0544 * If there is a current selected item, an <code>ItemEvent</code> will be
0545 * fired and the state change will be <code>ItemEvent.DESELECTED</code>.
0546 * If <code>anObject</code> is in the list and is not currently selected
0547 * then an <code>ItemEvent</code> will be fired and the state change will
0548 * be <code>ItemEvent.SELECTED</code>.
0549 * <p>
0550 * <code>ActionListener</code>s added to the combo box will be notified
0551 * with an <code>ActionEvent</code> when this method is called.
0552 *
0553 * @param anObject the list object to select; use <code>null</code> to
0554 clear the selection
0555 * @beaninfo
0556 * preferred: true
0557 * description: Sets the selected item in the JComboBox.
0558 */
0559 public void setSelectedItem(Object anObject) {
0560 Object oldSelection = selectedItemReminder;
0561 Object objectToSelect = anObject;
0562 if (oldSelection == null || !oldSelection.equals(anObject)) {
0563
0564 if (anObject != null && !isEditable()) {
0565 // For non editable combo boxes, an invalid selection
0566 // will be rejected.
0567 boolean found = false;
0568 for (int i = 0; i < dataModel.getSize(); i++) {
0569 Object element = dataModel.getElementAt(i);
0570 if (anObject.equals(element)) {
0571 found = true;
0572 objectToSelect = element;
0573 break;
0574 }
0575 }
0576 if (!found) {
0577 return;
0578 }
0579 }
0580
0581 // Must toggle the state of this flag since this method
0582 // call may result in ListDataEvents being fired.
0583 selectingItem = true;
0584 dataModel.setSelectedItem(objectToSelect);
0585 selectingItem = false;
0586
0587 if (selectedItemReminder != dataModel.getSelectedItem()) {
0588 // in case a users implementation of ComboBoxModel
0589 // doesn't fire a ListDataEvent when the selection
0590 // changes.
0591 selectedItemChanged();
0592 }
0593 }
0594 fireActionEvent();
0595 }
0596
0597 /**
0598 * Returns the current selected item.
0599 * <p>
0600 * If the combo box is editable, then this value may not have been added
0601 * to the combo box with <code>addItem</code>, <code>insertItemAt</code>
0602 * or the data constructors.
0603 *
0604 * @return the current selected Object
0605 * @see #setSelectedItem
0606 */
0607 public Object getSelectedItem() {
0608 return dataModel.getSelectedItem();
0609 }
0610
0611 /**
0612 * Selects the item at index <code>anIndex</code>.
0613 *
0614 * @param anIndex an integer specifying the list item to select,
0615 * where 0 specifies the first item in the list and -1 indicates no selection
0616 * @exception IllegalArgumentException if <code>anIndex</code> < -1 or
0617 * <code>anIndex</code> is greater than or equal to size
0618 * @beaninfo
0619 * preferred: true
0620 * description: The item at index is selected.
0621 */
0622 public void setSelectedIndex(int anIndex) {
0623 int size = dataModel.getSize();
0624
0625 if (anIndex == -1) {
0626 setSelectedItem(null);
0627 } else if (anIndex < -1 || anIndex >= size) {
0628 throw new IllegalArgumentException("setSelectedIndex: "
0629 + anIndex + " out of bounds");
0630 } else {
0631 setSelectedItem(dataModel.getElementAt(anIndex));
0632 }
0633 }
0634
0635 /**
0636 * Returns the first item in the list that matches the given item.
0637 * The result is not always defined if the <code>JComboBox</code>
0638 * allows selected items that are not in the list.
0639 * Returns -1 if there is no selected item or if the user specified
0640 * an item which is not in the list.
0641
0642 * @return an integer specifying the currently selected list item,
0643 * where 0 specifies
0644 * the first item in the list;
0645 * or -1 if no item is selected or if
0646 * the currently selected item is not in the list
0647 */
0648 public int getSelectedIndex() {
0649 Object sObject = dataModel.getSelectedItem();
0650 int i, c;
0651 Object obj;
0652
0653 for (i = 0, c = dataModel.getSize(); i < c; i++) {
0654 obj = dataModel.getElementAt(i);
0655 if (obj != null && obj.equals(sObject))
0656 return i;
0657 }
0658 return -1;
0659 }
0660
0661 /**
0662 * Returns the "prototypical display" value - an Object used
0663 * for the calculation of the display height and width.
0664 *
0665 * @return the value of the <code>prototypeDisplayValue</code> property
0666 * @see #setPrototypeDisplayValue
0667 * @since 1.4
0668 */
0669 public Object getPrototypeDisplayValue() {
0670 return prototypeDisplayValue;
0671 }
0672
0673 /**
0674 * Sets the prototype display value used to calculate the size of the display
0675 * for the UI portion.
0676 * <p>
0677 * If a prototype display value is specified, the preferred size of
0678 * the combo box is calculated by configuring the renderer with the
0679 * prototype display value and obtaining its preferred size. Specifying
0680 * the preferred display value is often useful when the combo box will be
0681 * displaying large amounts of data. If no prototype display value has
0682 * been specified, the renderer must be configured for each value from
0683 * the model and its preferred size obtained, which can be
0684 * relatively expensive.
0685 *
0686 * @param prototypeDisplayValue
0687 * @see #getPrototypeDisplayValue
0688 * @since 1.4
0689 * @beaninfo
0690 * bound: true
0691 * attribute: visualUpdate true
0692 * description: The display prototype value, used to compute display width and height.
0693 */
0694 public void setPrototypeDisplayValue(Object prototypeDisplayValue) {
0695 Object oldValue = this .prototypeDisplayValue;
0696 this .prototypeDisplayValue = prototypeDisplayValue;
0697 firePropertyChange("prototypeDisplayValue", oldValue,
0698 prototypeDisplayValue);
0699 }
0700
0701 /**
0702 * Adds an item to the item list.
0703 * This method works only if the <code>JComboBox</code> uses a
0704 * mutable data model.
0705 * <p>
0706 * <strong>Warning:</strong>
0707 * Focus and keyboard navigation problems may arise if you add duplicate
0708 * String objects. A workaround is to add new objects instead of String
0709 * objects and make sure that the toString() method is defined.
0710 * For example:
0711 * <pre>
0712 * comboBox.addItem(makeObj("Item 1"));
0713 * comboBox.addItem(makeObj("Item 1"));
0714 * ...
0715 * private Object makeObj(final String item) {
0716 * return new Object() { public String toString() { return item; } };
0717 * }
0718 * </pre>
0719 *
0720 * @param anObject the Object to add to the list
0721 * @see MutableComboBoxModel
0722 */
0723 public void addItem(Object anObject) {
0724 checkMutableComboBoxModel();
0725 ((MutableComboBoxModel) dataModel).addElement(anObject);
0726 }
0727
0728 /**
0729 * Inserts an item into the item list at a given index.
0730 * This method works only if the <code>JComboBox</code> uses a
0731 * mutable data model.
0732 *
0733 * @param anObject the <code>Object</code> to add to the list
0734 * @param index an integer specifying the position at which
0735 * to add the item
0736 * @see MutableComboBoxModel
0737 */
0738 public void insertItemAt(Object anObject, int index) {
0739 checkMutableComboBoxModel();
0740 ((MutableComboBoxModel) dataModel).insertElementAt(anObject,
0741 index);
0742 }
0743
0744 /**
0745 * Removes an item from the item list.
0746 * This method works only if the <code>JComboBox</code> uses a
0747 * mutable data model.
0748 *
0749 * @param anObject the object to remove from the item list
0750 * @see MutableComboBoxModel
0751 */
0752 public void removeItem(Object anObject) {
0753 checkMutableComboBoxModel();
0754 ((MutableComboBoxModel) dataModel).removeElement(anObject);
0755 }
0756
0757 /**
0758 * Removes the item at <code>anIndex</code>
0759 * This method works only if the <code>JComboBox</code> uses a
0760 * mutable data model.
0761 *
0762 * @param anIndex an int specifying the index of the item to remove,
0763 * where 0
0764 * indicates the first item in the list
0765 * @see MutableComboBoxModel
0766 */
0767 public void removeItemAt(int anIndex) {
0768 checkMutableComboBoxModel();
0769 ((MutableComboBoxModel) dataModel).removeElementAt(anIndex);
0770 }
0771
0772 /**
0773 * Removes all items from the item list.
0774 */
0775 public void removeAllItems() {
0776 checkMutableComboBoxModel();
0777 MutableComboBoxModel model = (MutableComboBoxModel) dataModel;
0778 int size = model.getSize();
0779
0780 if (model instanceof DefaultComboBoxModel) {
0781 ((DefaultComboBoxModel) model).removeAllElements();
0782 } else {
0783 for (int i = 0; i < size; ++i) {
0784 Object element = model.getElementAt(0);
0785 model.removeElement(element);
0786 }
0787 }
0788 selectedItemReminder = null;
0789 if (isEditable()) {
0790 editor.setItem(null);
0791 }
0792 }
0793
0794 /**
0795 * Checks that the <code>dataModel</code> is an instance of
0796 * <code>MutableComboBoxModel</code>. If not, it throws an exception.
0797 * @exception RuntimeException if <code>dataModel</code> is not an
0798 * instance of <code>MutableComboBoxModel</code>.
0799 */
0800 void checkMutableComboBoxModel() {
0801 if (!(dataModel instanceof MutableComboBoxModel))
0802 throw new RuntimeException(
0803 "Cannot use this method with a non-Mutable data model.");
0804 }
0805
0806 /**
0807 * Causes the combo box to display its popup window.
0808 * @see #setPopupVisible
0809 */
0810 public void showPopup() {
0811 setPopupVisible(true);
0812 }
0813
0814 /**
0815 * Causes the combo box to close its popup window.
0816 * @see #setPopupVisible
0817 */
0818 public void hidePopup() {
0819 setPopupVisible(false);
0820 }
0821
0822 /**
0823 * Sets the visibility of the popup.
0824 */
0825 public void setPopupVisible(boolean v) {
0826 getUI().setPopupVisible(this , v);
0827 }
0828
0829 /**
0830 * Determines the visibility of the popup.
0831 *
0832 * @return true if the popup is visible, otherwise returns false
0833 */
0834 public boolean isPopupVisible() {
0835 return getUI().isPopupVisible(this );
0836 }
0837
0838 /** Selection **/
0839
0840 /**
0841 * Adds an <code>ItemListener</code>.
0842 * <p>
0843 * <code>aListener</code> will receive one or two <code>ItemEvent</code>s when
0844 * the selected item changes.
0845 *
0846 * @param aListener the <code>ItemListener</code> that is to be notified
0847 * @see #setSelectedItem
0848 */
0849 public void addItemListener(ItemListener aListener) {
0850 listenerList.add(ItemListener.class, aListener);
0851 }
0852
0853 /** Removes an <code>ItemListener</code>.
0854 *
0855 * @param aListener the <code>ItemListener</code> to remove
0856 */
0857 public void removeItemListener(ItemListener aListener) {
0858 listenerList.remove(ItemListener.class, aListener);
0859 }
0860
0861 /**
0862 * Returns an array of all the <code>ItemListener</code>s added
0863 * to this JComboBox with addItemListener().
0864 *
0865 * @return all of the <code>ItemListener</code>s added or an empty
0866 * array if no listeners have been added
0867 * @since 1.4
0868 */
0869 public ItemListener[] getItemListeners() {
0870 return (ItemListener[]) listenerList
0871 .getListeners(ItemListener.class);
0872 }
0873
0874 /**
0875 * Adds an <code>ActionListener</code>.
0876 * <p>
0877 * The <code>ActionListener</code> will receive an <code>ActionEvent</code>
0878 * when a selection has been made. If the combo box is editable, then
0879 * an <code>ActionEvent</code> will be fired when editing has stopped.
0880 *
0881 * @param l the <code>ActionListener</code> that is to be notified
0882 * @see #setSelectedItem
0883 */
0884 public void addActionListener(ActionListener l) {
0885 listenerList.add(ActionListener.class, l);
0886 }
0887
0888 /** Removes an <code>ActionListener</code>.
0889 *
0890 * @param l the <code>ActionListener</code> to remove
0891 */
0892 public void removeActionListener(ActionListener l) {
0893 if ((l != null) && (getAction() == l)) {
0894 setAction(null);
0895 } else {
0896 listenerList.remove(ActionListener.class, l);
0897 }
0898 }
0899
0900 /**
0901 * Returns an array of all the <code>ActionListener</code>s added
0902 * to this JComboBox with addActionListener().
0903 *
0904 * @return all of the <code>ActionListener</code>s added or an empty
0905 * array if no listeners have been added
0906 * @since 1.4
0907 */
0908 public ActionListener[] getActionListeners() {
0909 return (ActionListener[]) listenerList
0910 .getListeners(ActionListener.class);
0911 }
0912
0913 /**
0914 * Adds a <code>PopupMenu</code> listener which will listen to notification
0915 * messages from the popup portion of the combo box.
0916 * <p>
0917 * For all standard look and feels shipped with Java, the popup list
0918 * portion of combo box is implemented as a <code>JPopupMenu</code>.
0919 * A custom look and feel may not implement it this way and will
0920 * therefore not receive the notification.
0921 *
0922 * @param l the <code>PopupMenuListener</code> to add
0923 * @since 1.4
0924 */
0925 public void addPopupMenuListener(PopupMenuListener l) {
0926 listenerList.add(PopupMenuListener.class, l);
0927 }
0928
0929 /**
0930 * Removes a <code>PopupMenuListener</code>.
0931 *
0932 * @param l the <code>PopupMenuListener</code> to remove
0933 * @see #addPopupMenuListener
0934 * @since 1.4
0935 */
0936 public void removePopupMenuListener(PopupMenuListener l) {
0937 listenerList.remove(PopupMenuListener.class, l);
0938 }
0939
0940 /**
0941 * Returns an array of all the <code>PopupMenuListener</code>s added
0942 * to this JComboBox with addPopupMenuListener().
0943 *
0944 * @return all of the <code>PopupMenuListener</code>s added or an empty
0945 * array if no listeners have been added
0946 * @since 1.4
0947 */
0948 public PopupMenuListener[] getPopupMenuListeners() {
0949 return (PopupMenuListener[]) listenerList
0950 .getListeners(PopupMenuListener.class);
0951 }
0952
0953 /**
0954 * Notifies <code>PopupMenuListener</code>s that the popup portion of the
0955 * combo box will become visible.
0956 * <p>
0957 * This method is public but should not be called by anything other than
0958 * the UI delegate.
0959 * @see #addPopupMenuListener
0960 * @since 1.4
0961 */
0962 public void firePopupMenuWillBecomeVisible() {
0963 Object[] listeners = listenerList.getListenerList();
0964 PopupMenuEvent e = null;
0965 for (int i = listeners.length - 2; i >= 0; i -= 2) {
0966 if (listeners[i] == PopupMenuListener.class) {
0967 if (e == null)
0968 e = new PopupMenuEvent(this );
0969 ((PopupMenuListener) listeners[i + 1])
0970 .popupMenuWillBecomeVisible(e);
0971 }
0972 }
0973 }
0974
0975 /**
0976 * Notifies <code>PopupMenuListener</code>s that the popup portion of the
0977 * combo box has become invisible.
0978 * <p>
0979 * This method is public but should not be called by anything other than
0980 * the UI delegate.
0981 * @see #addPopupMenuListener
0982 * @since 1.4
0983 */
0984 public void firePopupMenuWillBecomeInvisible() {
0985 Object[] listeners = listenerList.getListenerList();
0986 PopupMenuEvent e = null;
0987 for (int i = listeners.length - 2; i >= 0; i -= 2) {
0988 if (listeners[i] == PopupMenuListener.class) {
0989 if (e == null)
0990 e = new PopupMenuEvent(this );
0991 ((PopupMenuListener) listeners[i + 1])
0992 .popupMenuWillBecomeInvisible(e);
0993 }
0994 }
0995 }
0996
0997 /**
0998 * Notifies <code>PopupMenuListener</code>s that the popup portion of the
0999 * combo box has been canceled.
1000 * <p>
1001 * This method is public but should not be called by anything other than
1002 * the UI delegate.
1003 * @see #addPopupMenuListener
1004 * @since 1.4
1005 */
1006 public void firePopupMenuCanceled() {
1007 Object[] listeners = listenerList.getListenerList();
1008 PopupMenuEvent e = null;
1009 for (int i = listeners.length - 2; i >= 0; i -= 2) {
1010 if (listeners[i] == PopupMenuListener.class) {
1011 if (e == null)
1012 e = new PopupMenuEvent(this );
1013 ((PopupMenuListener) listeners[i + 1])
1014 .popupMenuCanceled(e);
1015 }
1016 }
1017 }
1018
1019 /**
1020 * Sets the action command that should be included in the event
1021 * sent to action listeners.
1022 *
1023 * @param aCommand a string containing the "command" that is sent
1024 * to action listeners; the same listener can then
1025 * do different things depending on the command it
1026 * receives
1027 */
1028 public void setActionCommand(String aCommand) {
1029 actionCommand = aCommand;
1030 }
1031
1032 /**
1033 * Returns the action command that is included in the event sent to
1034 * action listeners.
1035 *
1036 * @return the string containing the "command" that is sent
1037 * to action listeners.
1038 */
1039 public String getActionCommand() {
1040 return actionCommand;
1041 }
1042
1043 private Action action;
1044 private PropertyChangeListener actionPropertyChangeListener;
1045
1046 /**
1047 * Sets the <code>Action</code> for the <code>ActionEvent</code> source.
1048 * The new <code>Action</code> replaces any previously set
1049 * <code>Action</code> but does not affect <code>ActionListeners</code>
1050 * independently added with <code>addActionListener</code>.
1051 * If the <code>Action</code> is already a registered
1052 * <code>ActionListener</code> for the <code>ActionEvent</code> source,
1053 * it is not re-registered.
1054 * <p>
1055 * Setting the <code>Action</code> results in immediately changing
1056 * all the properties described in <a href="Action.html#buttonActions">
1057 * Swing Components Supporting <code>Action</code></a>.
1058 * Subsequently, the combobox's properties are automatically updated
1059 * as the <code>Action</code>'s properties change.
1060 * <p>
1061 * This method uses three other methods to set
1062 * and help track the <code>Action</code>'s property values.
1063 * It uses the <code>configurePropertiesFromAction</code> method
1064 * to immediately change the combobox's properties.
1065 * To track changes in the <code>Action</code>'s property values,
1066 * this method registers the <code>PropertyChangeListener</code>
1067 * returned by <code>createActionPropertyChangeListener</code>. The
1068 * default {@code PropertyChangeListener} invokes the
1069 * {@code actionPropertyChanged} method when a property in the
1070 * {@code Action} changes.
1071 *
1072 * @param a the <code>Action</code> for the <code>JComboBox</code>,
1073 * or <code>null</code>.
1074 * @since 1.3
1075 * @see Action
1076 * @see #getAction
1077 * @see #configurePropertiesFromAction
1078 * @see #createActionPropertyChangeListener
1079 * @see #actionPropertyChanged
1080 * @beaninfo
1081 * bound: true
1082 * attribute: visualUpdate true
1083 * description: the Action instance connected with this ActionEvent source
1084 */
1085 public void setAction(Action a) {
1086 Action oldValue = getAction();
1087 if (action == null || !action.equals(a)) {
1088 action = a;
1089 if (oldValue != null) {
1090 removeActionListener(oldValue);
1091 oldValue
1092 .removePropertyChangeListener(actionPropertyChangeListener);
1093 actionPropertyChangeListener = null;
1094 }
1095 configurePropertiesFromAction(action);
1096 if (action != null) {
1097 // Don't add if it is already a listener
1098 if (!isListener(ActionListener.class, action)) {
1099 addActionListener(action);
1100 }
1101 // Reverse linkage:
1102 actionPropertyChangeListener = createActionPropertyChangeListener(action);
1103 action
1104 .addPropertyChangeListener(actionPropertyChangeListener);
1105 }
1106 firePropertyChange("action", oldValue, action);
1107 }
1108 }
1109
1110 private boolean isListener(Class c, ActionListener a) {
1111 boolean isListener = false;
1112 Object[] listeners = listenerList.getListenerList();
1113 for (int i = listeners.length - 2; i >= 0; i -= 2) {
1114 if (listeners[i] == c && listeners[i + 1] == a) {
1115 isListener = true;
1116 }
1117 }
1118 return isListener;
1119 }
1120
1121 /**
1122 * Returns the currently set <code>Action</code> for this
1123 * <code>ActionEvent</code> source, or <code>null</code> if no
1124 * <code>Action</code> is set.
1125 *
1126 * @return the <code>Action</code> for this <code>ActionEvent</code>
1127 * source; or <code>null</code>
1128 * @since 1.3
1129 * @see Action
1130 * @see #setAction
1131 */
1132 public Action getAction() {
1133 return action;
1134 }
1135
1136 /**
1137 * Sets the properties on this combobox to match those in the specified
1138 * <code>Action</code>. Refer to <a href="Action.html#buttonActions">
1139 * Swing Components Supporting <code>Action</code></a> for more
1140 * details as to which properties this sets.
1141 *
1142 * @param a the <code>Action</code> from which to get the properties,
1143 * or <code>null</code>
1144 * @since 1.3
1145 * @see Action
1146 * @see #setAction
1147 */
1148 protected void configurePropertiesFromAction(Action a) {
1149 AbstractAction.setEnabledFromAction(this , a);
1150 AbstractAction.setToolTipTextFromAction(this , a);
1151 setActionCommandFromAction(a);
1152 }
1153
1154 /**
1155 * Creates and returns a <code>PropertyChangeListener</code> that is
1156 * responsible for listening for changes from the specified
1157 * <code>Action</code> and updating the appropriate properties.
1158 * <p>
1159 * <b>Warning:</b> If you subclass this do not create an anonymous
1160 * inner class. If you do the lifetime of the combobox will be tied to
1161 * that of the <code>Action</code>.
1162 *
1163 * @param a the combobox's action
1164 * @since 1.3
1165 * @see Action
1166 * @see #setAction
1167 */
1168 protected PropertyChangeListener createActionPropertyChangeListener(
1169 Action a) {
1170 return new ComboBoxActionPropertyChangeListener(this , a);
1171 }
1172
1173 /**
1174 * Updates the combobox's state in response to property changes in
1175 * associated action. This method is invoked from the
1176 * {@code PropertyChangeListener} returned from
1177 * {@code createActionPropertyChangeListener}. Subclasses do not normally
1178 * need to invoke this. Subclasses that support additional {@code Action}
1179 * properties should override this and
1180 * {@code configurePropertiesFromAction}.
1181 * <p>
1182 * Refer to the table at <a href="Action.html#buttonActions">
1183 * Swing Components Supporting <code>Action</code></a> for a list of
1184 * the properties this method sets.
1185 *
1186 * @param action the <code>Action</code> associated with this combobox
1187 * @param propertyName the name of the property that changed
1188 * @since 1.6
1189 * @see Action
1190 * @see #configurePropertiesFromAction
1191 */
1192 protected void actionPropertyChanged(Action action,
1193 String propertyName) {
1194 if (propertyName == Action.ACTION_COMMAND_KEY) {
1195 setActionCommandFromAction(action);
1196 } else if (propertyName == "enabled") {
1197 AbstractAction.setEnabledFromAction(this , action);
1198 } else if (Action.SHORT_DESCRIPTION == propertyName) {
1199 AbstractAction.setToolTipTextFromAction(this , action);
1200 }
1201 }
1202
1203 private void setActionCommandFromAction(Action a) {
1204 setActionCommand((a != null) ? (String) a
1205 .getValue(Action.ACTION_COMMAND_KEY) : null);
1206 }
1207
1208 private static class ComboBoxActionPropertyChangeListener extends
1209 ActionPropertyChangeListener<JComboBox> {
1210 ComboBoxActionPropertyChangeListener(JComboBox b, Action a) {
1211 super (b, a);
1212 }
1213
1214 protected void actionPropertyChanged(JComboBox cb,
1215 Action action, PropertyChangeEvent e) {
1216 if (AbstractAction.shouldReconfigure(e)) {
1217 cb.configurePropertiesFromAction(action);
1218 } else {
1219 cb.actionPropertyChanged(action, e.getPropertyName());
1220 }
1221 }
1222 }
1223
1224 /**
1225 * Notifies all listeners that have registered interest for
1226 * notification on this event type.
1227 * @param e the event of interest
1228 *
1229 * @see EventListenerList
1230 */
1231 protected void fireItemStateChanged(ItemEvent e) {
1232 // Guaranteed to return a non-null array
1233 Object[] listeners = listenerList.getListenerList();
1234 // Process the listeners last to first, notifying
1235 // those that are interested in this event
1236 for (int i = listeners.length - 2; i >= 0; i -= 2) {
1237 if (listeners[i] == ItemListener.class) {
1238 // Lazily create the event:
1239 // if (changeEvent == null)
1240 // changeEvent = new ChangeEvent(this);
1241 ((ItemListener) listeners[i + 1]).itemStateChanged(e);
1242 }
1243 }
1244 }
1245
1246 /**
1247 * Notifies all listeners that have registered interest for
1248 * notification on this event type.
1249 *
1250 * @see EventListenerList
1251 */
1252 protected void fireActionEvent() {
1253 if (!firingActionEvent) {
1254 // Set flag to ensure that an infinite loop is not created
1255 firingActionEvent = true;
1256 ActionEvent e = null;
1257 // Guaranteed to return a non-null array
1258 Object[] listeners = listenerList.getListenerList();
1259 long mostRecentEventTime = EventQueue
1260 .getMostRecentEventTime();
1261 int modifiers = 0;
1262 AWTEvent currentEvent = EventQueue.getCurrentEvent();
1263 if (currentEvent instanceof InputEvent) {
1264 modifiers = ((InputEvent) currentEvent).getModifiers();
1265 } else if (currentEvent instanceof ActionEvent) {
1266 modifiers = ((ActionEvent) currentEvent).getModifiers();
1267 }
1268 // Process the listeners last to first, notifying
1269 // those that are interested in this event
1270 for (int i = listeners.length - 2; i >= 0; i -= 2) {
1271 if (listeners[i] == ActionListener.class) {
1272 // Lazily create the event:
1273 if (e == null)
1274 e = new ActionEvent(this ,
1275 ActionEvent.ACTION_PERFORMED,
1276 getActionCommand(),
1277 mostRecentEventTime, modifiers);
1278 ((ActionListener) listeners[i + 1])
1279 .actionPerformed(e);
1280 }
1281 }
1282 firingActionEvent = false;
1283 }
1284 }
1285
1286 /**
1287 * This protected method is implementation specific. Do not access directly
1288 * or override.
1289 */
1290 protected void selectedItemChanged() {
1291 if (selectedItemReminder != null) {
1292 fireItemStateChanged(new ItemEvent(this ,
1293 ItemEvent.ITEM_STATE_CHANGED, selectedItemReminder,
1294 ItemEvent.DESELECTED));
1295 }
1296
1297 // set the new selected item.
1298 selectedItemReminder = dataModel.getSelectedItem();
1299
1300 if (selectedItemReminder != null) {
1301 fireItemStateChanged(new ItemEvent(this ,
1302 ItemEvent.ITEM_STATE_CHANGED, selectedItemReminder,
1303 ItemEvent.SELECTED));
1304 }
1305 }
1306
1307 /**
1308 * Returns an array containing the selected item.
1309 * This method is implemented for compatibility with
1310 * <code>ItemSelectable</code>.
1311 *
1312 * @return an array of <code>Objects</code> containing one
1313 * element -- the selected item
1314 */
1315 public Object[] getSelectedObjects() {
1316 Object selectedObject = getSelectedItem();
1317 if (selectedObject == null)
1318 return new Object[0];
1319 else {
1320 Object result[] = new Object[1];
1321 result[0] = selectedObject;
1322 return result;
1323 }
1324 }
1325
1326 /**
1327 * This method is public as an implementation side effect.
1328 * do not call or override.
1329 */
1330 public void actionPerformed(ActionEvent e) {
1331 Object newItem = getEditor().getItem();
1332 setPopupVisible(false);
1333 getModel().setSelectedItem(newItem);
1334 String oldCommand = getActionCommand();
1335 setActionCommand("comboBoxEdited");
1336 fireActionEvent();
1337 setActionCommand(oldCommand);
1338 }
1339
1340 /**
1341 * This method is public as an implementation side effect.
1342 * do not call or override.
1343 */
1344 public void contentsChanged(ListDataEvent e) {
1345 Object oldSelection = selectedItemReminder;
1346 Object newSelection = dataModel.getSelectedItem();
1347 if (oldSelection == null || !oldSelection.equals(newSelection)) {
1348 selectedItemChanged();
1349 if (!selectingItem) {
1350 fireActionEvent();
1351 }
1352 }
1353 }
1354
1355 /**
1356 * This method is public as an implementation side effect.
1357 * do not call or override.
1358 */
1359 public void intervalAdded(ListDataEvent e) {
1360 if (selectedItemReminder != dataModel.getSelectedItem()) {
1361 selectedItemChanged();
1362 }
1363 }
1364
1365 /**
1366 * This method is public as an implementation side effect.
1367 * do not call or override.
1368 */
1369 public void intervalRemoved(ListDataEvent e) {
1370 contentsChanged(e);
1371 }
1372
1373 /**
1374 * Selects the list item that corresponds to the specified keyboard
1375 * character and returns true, if there is an item corresponding
1376 * to that character. Otherwise, returns false.
1377 *
1378 * @param keyChar a char, typically this is a keyboard key
1379 * typed by the user
1380 */
1381 public boolean selectWithKeyChar(char keyChar) {
1382 int index;
1383
1384 if (keySelectionManager == null)
1385 keySelectionManager = createDefaultKeySelectionManager();
1386
1387 index = keySelectionManager
1388 .selectionForKey(keyChar, getModel());
1389 if (index != -1) {
1390 setSelectedIndex(index);
1391 return true;
1392 } else
1393 return false;
1394 }
1395
1396 /**
1397 * Enables the combo box so that items can be selected. When the
1398 * combo box is disabled, items cannot be selected and values
1399 * cannot be typed into its field (if it is editable).
1400 *
1401 * @param b a boolean value, where true enables the component and
1402 * false disables it
1403 * @beaninfo
1404 * bound: true
1405 * preferred: true
1406 * description: Whether the combo box is enabled.
1407 */
1408 public void setEnabled(boolean b) {
1409 super .setEnabled(b);
1410 firePropertyChange("enabled", !isEnabled(), isEnabled());
1411 }
1412
1413 /**
1414 * Initializes the editor with the specified item.
1415 *
1416 * @param anEditor the <code>ComboBoxEditor</code> that displays
1417 * the list item in the
1418 * combo box field and allows it to be edited
1419 * @param anItem the object to display and edit in the field
1420 */
1421 public void configureEditor(ComboBoxEditor anEditor, Object anItem) {
1422 anEditor.setItem(anItem);
1423 }
1424
1425 /**
1426 * Handles <code>KeyEvent</code>s, looking for the Tab key.
1427 * If the Tab key is found, the popup window is closed.
1428 *
1429 * @param e the <code>KeyEvent</code> containing the keyboard
1430 * key that was pressed
1431 */
1432 public void processKeyEvent(KeyEvent e) {
1433 if (e.getKeyCode() == KeyEvent.VK_TAB) {
1434 hidePopup();
1435 }
1436 super .processKeyEvent(e);
1437 }
1438
1439 /**
1440 * Sets the object that translates a keyboard character into a list
1441 * selection. Typically, the first selection with a matching first
1442 * character becomes the selected item.
1443 *
1444 * @beaninfo
1445 * expert: true
1446 * description: The objects that changes the selection when a key is pressed.
1447 */
1448 public void setKeySelectionManager(KeySelectionManager aManager) {
1449 keySelectionManager = aManager;
1450 }
1451
1452 /**
1453 * Returns the list's key-selection manager.
1454 *
1455 * @return the <code>KeySelectionManager</code> currently in use
1456 */
1457 public KeySelectionManager getKeySelectionManager() {
1458 return keySelectionManager;
1459 }
1460
1461 /* Accessing the model */
1462 /**
1463 * Returns the number of items in the list.
1464 *
1465 * @return an integer equal to the number of items in the list
1466 */
1467 public int getItemCount() {
1468 return dataModel.getSize();
1469 }
1470
1471 /**
1472 * Returns the list item at the specified index. If <code>index</code>
1473 * is out of range (less than zero or greater than or equal to size)
1474 * it will return <code>null</code>.
1475 *
1476 * @param index an integer indicating the list position, where the first
1477 * item starts at zero
1478 * @return the <code>Object</code> at that list position; or
1479 * <code>null</code> if out of range
1480 */
1481 public Object getItemAt(int index) {
1482 return dataModel.getElementAt(index);
1483 }
1484
1485 /**
1486 * Returns an instance of the default key-selection manager.
1487 *
1488 * @return the <code>KeySelectionManager</code> currently used by the list
1489 * @see #setKeySelectionManager
1490 */
1491 protected KeySelectionManager createDefaultKeySelectionManager() {
1492 return new DefaultKeySelectionManager();
1493 }
1494
1495 /**
1496 * The interface that defines a <code>KeySelectionManager</code>.
1497 * To qualify as a <code>KeySelectionManager</code>,
1498 * the class needs to implement the method
1499 * that identifies the list index given a character and the
1500 * combo box data model.
1501 */
1502 public interface KeySelectionManager {
1503 /** Given <code>aKey</code> and the model, returns the row
1504 * that should become selected. Return -1 if no match was
1505 * found.
1506 *
1507 * @param aKey a char value, usually indicating a keyboard key that
1508 * was pressed
1509 * @param aModel a ComboBoxModel -- the component's data model, containing
1510 * the list of selectable items
1511 * @return an int equal to the selected row, where 0 is the
1512 * first item and -1 is none.
1513 */
1514 int selectionForKey(char aKey, ComboBoxModel aModel);
1515 }
1516
1517 class DefaultKeySelectionManager implements KeySelectionManager,
1518 Serializable {
1519 public int selectionForKey(char aKey, ComboBoxModel aModel) {
1520 int i, c;
1521 int currentSelection = -1;
1522 Object selectedItem = aModel.getSelectedItem();
1523 String v;
1524 String pattern;
1525
1526 if (selectedItem != null) {
1527 for (i = 0, c = aModel.getSize(); i < c; i++) {
1528 if (selectedItem == aModel.getElementAt(i)) {
1529 currentSelection = i;
1530 break;
1531 }
1532 }
1533 }
1534
1535 pattern = ("" + aKey).toLowerCase();
1536 aKey = pattern.charAt(0);
1537
1538 for (i = ++currentSelection, c = aModel.getSize(); i < c; i++) {
1539 Object elem = aModel.getElementAt(i);
1540 if (elem != null && elem.toString() != null) {
1541 v = elem.toString().toLowerCase();
1542 if (v.length() > 0 && v.charAt(0) == aKey)
1543 return i;
1544 }
1545 }
1546
1547 for (i = 0; i < currentSelection; 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 return -1;
1556 }
1557 }
1558
1559 /**
1560 * See <code>readObject</code> and <code>writeObject</code> in
1561 * <code>JComponent</code> for more
1562 * information about serialization in Swing.
1563 */
1564 private void writeObject(ObjectOutputStream s) throws IOException {
1565 s.defaultWriteObject();
1566 if (getUIClassID().equals(uiClassID)) {
1567 byte count = JComponent.getWriteObjCounter(this );
1568 JComponent.setWriteObjCounter(this , --count);
1569 if (count == 0 && ui != null) {
1570 ui.installUI(this );
1571 }
1572 }
1573 }
1574
1575 /**
1576 * Returns a string representation of this <code>JComboBox</code>.
1577 * This method is intended to be used only for debugging purposes,
1578 * and the content and format of the returned string may vary between
1579 * implementations. The returned string may be empty but may not
1580 * be <code>null</code>.
1581 *
1582 * @return a string representation of this <code>JComboBox</code>
1583 */
1584 protected String paramString() {
1585 String selectedItemReminderString = (selectedItemReminder != null ? selectedItemReminder
1586 .toString()
1587 : "");
1588 String isEditableString = (isEditable ? "true" : "false");
1589 String lightWeightPopupEnabledString = (lightWeightPopupEnabled ? "true"
1590 : "false");
1591
1592 return super .paramString() + ",isEditable=" + isEditableString
1593 + ",lightWeightPopupEnabled="
1594 + lightWeightPopupEnabledString + ",maximumRowCount="
1595 + maximumRowCount + ",selectedItemReminder="
1596 + selectedItemReminderString;
1597 }
1598
1599 ///////////////////
1600 // Accessibility support
1601 ///////////////////
1602
1603 /**
1604 * Gets the AccessibleContext associated with this JComboBox.
1605 * For combo boxes, the AccessibleContext takes the form of an
1606 * AccessibleJComboBox.
1607 * A new AccessibleJComboBox instance is created if necessary.
1608 *
1609 * @return an AccessibleJComboBox that serves as the
1610 * AccessibleContext of this JComboBox
1611 */
1612 public AccessibleContext getAccessibleContext() {
1613 if (accessibleContext == null) {
1614 accessibleContext = new AccessibleJComboBox();
1615 }
1616 return accessibleContext;
1617 }
1618
1619 /**
1620 * This class implements accessibility support for the
1621 * <code>JComboBox</code> class. It provides an implementation of the
1622 * Java Accessibility API appropriate to Combo Box user-interface elements.
1623 * <p>
1624 * <strong>Warning:</strong>
1625 * Serialized objects of this class will not be compatible with
1626 * future Swing releases. The current serialization support is
1627 * appropriate for short term storage or RMI between applications running
1628 * the same version of Swing. As of 1.4, support for long term storage
1629 * of all JavaBeans<sup><font size="-2">TM</font></sup>
1630 * has been added to the <code>java.beans</code> package.
1631 * Please see {@link java.beans.XMLEncoder}.
1632 */
1633 protected class AccessibleJComboBox extends AccessibleJComponent
1634 implements AccessibleAction, AccessibleSelection {
1635
1636 private JList popupList; // combo box popup list
1637 private Accessible previousSelectedAccessible = null;
1638
1639 /**
1640 * Returns an AccessibleJComboBox instance
1641 * @since 1.4
1642 */
1643 public AccessibleJComboBox() {
1644 // set the combo box editor's accessible name and description
1645 JComboBox.this
1646 .addPropertyChangeListener(new AccessibleJComboBoxPropertyChangeListener());
1647 setEditorNameAndDescription();
1648
1649 // Get the popup list
1650 Accessible a = getUI()
1651 .getAccessibleChild(JComboBox.this , 0);
1652 if (a instanceof javax.swing.plaf.basic.ComboPopup) {
1653 // Listen for changes to the popup menu selection.
1654 popupList = ((javax.swing.plaf.basic.ComboPopup) a)
1655 .getList();
1656 popupList
1657 .addListSelectionListener(new AccessibleJComboBoxListSelectionListener());
1658 }
1659 // Listen for popup menu show/hide events
1660 JComboBox.this
1661 .addPopupMenuListener(new AccessibleJComboBoxPopupMenuListener());
1662 }
1663
1664 /*
1665 * JComboBox PropertyChangeListener
1666 */
1667 private class AccessibleJComboBoxPropertyChangeListener
1668 implements PropertyChangeListener {
1669
1670 public void propertyChange(PropertyChangeEvent e) {
1671 if (e.getPropertyName() == "editor") {
1672 // set the combo box editor's accessible name
1673 // and description
1674 setEditorNameAndDescription();
1675 }
1676 }
1677 }
1678
1679 /*
1680 * Sets the combo box editor's accessible name and descripton
1681 */
1682 private void setEditorNameAndDescription() {
1683 ComboBoxEditor editor = JComboBox.this .getEditor();
1684 if (editor != null) {
1685 Component comp = editor.getEditorComponent();
1686 if (comp instanceof Accessible) {
1687 AccessibleContext ac = ((Accessible) comp)
1688 .getAccessibleContext();
1689 if (ac != null) { // may be null
1690 ac.setAccessibleName(getAccessibleName());
1691 ac
1692 .setAccessibleDescription(getAccessibleDescription());
1693 }
1694 }
1695 }
1696 }
1697
1698 /*
1699 * Listener for combo box popup menu
1700 * TIGER - 4669379 4894434
1701 */
1702 private class AccessibleJComboBoxPopupMenuListener implements
1703 PopupMenuListener {
1704
1705 /**
1706 * This method is called before the popup menu becomes visible
1707 */
1708 public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
1709 // save the initial selection
1710 if (popupList == null) {
1711 return;
1712 }
1713 int selectedIndex = popupList.getSelectedIndex();
1714 if (selectedIndex < 0) {
1715 return;
1716 }
1717 previousSelectedAccessible = popupList
1718 .getAccessibleContext().getAccessibleChild(
1719 selectedIndex);
1720 }
1721
1722 /**
1723 * This method is called before the popup menu becomes invisible
1724 * Note that a JPopupMenu can become invisible any time
1725 */
1726 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
1727 // ignore
1728 }
1729
1730 /**
1731 * This method is called when the popup menu is canceled
1732 */
1733 public void popupMenuCanceled(PopupMenuEvent e) {
1734 // ignore
1735 }
1736 }
1737
1738 /*
1739 * Handles changes to the popup list selection.
1740 * TIGER - 4669379 4894434 4933143
1741 */
1742 private class AccessibleJComboBoxListSelectionListener
1743 implements ListSelectionListener {
1744
1745 public void valueChanged(ListSelectionEvent e) {
1746 if (popupList == null) {
1747 return;
1748 }
1749
1750 // Get the selected popup list item.
1751 int selectedIndex = popupList.getSelectedIndex();
1752 if (selectedIndex < 0) {
1753 return;
1754 }
1755 Accessible selectedAccessible = popupList
1756 .getAccessibleContext().getAccessibleChild(
1757 selectedIndex);
1758 if (selectedAccessible == null) {
1759 return;
1760 }
1761
1762 // Fire a FOCUSED lost PropertyChangeEvent for the
1763 // previously selected list item.
1764 PropertyChangeEvent pce = null;
1765
1766 if (previousSelectedAccessible != null) {
1767 pce = new PropertyChangeEvent(
1768 previousSelectedAccessible,
1769 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
1770 AccessibleState.FOCUSED, null);
1771 firePropertyChange(
1772 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
1773 null, pce);
1774 }
1775 // Fire a FOCUSED gained PropertyChangeEvent for the
1776 // currently selected list item.
1777 pce = new PropertyChangeEvent(selectedAccessible,
1778 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
1779 null, AccessibleState.FOCUSED);
1780 firePropertyChange(
1781 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
1782 null, pce);
1783
1784 // Fire the ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY event
1785 // for the combo box.
1786 firePropertyChange(
1787 AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
1788 previousSelectedAccessible, selectedAccessible);
1789
1790 // Save the previous selection.
1791 previousSelectedAccessible = selectedAccessible;
1792 }
1793 }
1794
1795 /**
1796 * Returns the number of accessible children in the object. If all
1797 * of the children of this object implement Accessible, than this
1798 * method should return the number of children of this object.
1799 *
1800 * @return the number of accessible children in the object.
1801 */
1802 public int getAccessibleChildrenCount() {
1803 // Always delegate to the UI if it exists
1804 if (ui != null) {
1805 return ui.getAccessibleChildrenCount(JComboBox.this );
1806 } else {
1807 return super .getAccessibleChildrenCount();
1808 }
1809 }
1810
1811 /**
1812 * Returns the nth Accessible child of the object.
1813 * The child at index zero represents the popup.
1814 * If the combo box is editable, the child at index one
1815 * represents the editor.
1816 *
1817 * @param i zero-based index of child
1818 * @return the nth Accessible child of the object
1819 */
1820 public Accessible getAccessibleChild(int i) {
1821 // Always delegate to the UI if it exists
1822 if (ui != null) {
1823 return ui.getAccessibleChild(JComboBox.this , i);
1824 } else {
1825 return super .getAccessibleChild(i);
1826 }
1827 }
1828
1829 /**
1830 * Get the role of this object.
1831 *
1832 * @return an instance of AccessibleRole describing the role of the
1833 * object
1834 * @see AccessibleRole
1835 */
1836 public AccessibleRole getAccessibleRole() {
1837 return AccessibleRole.COMBO_BOX;
1838 }
1839
1840 /**
1841 * Gets the state set of this object. The AccessibleStateSet of
1842 * an object is composed of a set of unique AccessibleStates.
1843 * A change in the AccessibleStateSet of an object will cause a
1844 * PropertyChangeEvent to be fired for the ACCESSIBLE_STATE_PROPERTY
1845 * property.
1846 *
1847 * @return an instance of AccessibleStateSet containing the
1848 * current state set of the object
1849 * @see AccessibleStateSet
1850 * @see AccessibleState
1851 * @see #addPropertyChangeListener
1852 *
1853 */
1854 public AccessibleStateSet getAccessibleStateSet() {
1855 // TIGER - 4489748
1856 AccessibleStateSet ass = super .getAccessibleStateSet();
1857 if (ass == null) {
1858 ass = new AccessibleStateSet();
1859 }
1860 if (JComboBox.this .isPopupVisible()) {
1861 ass.add(AccessibleState.EXPANDED);
1862 } else {
1863 ass.add(AccessibleState.COLLAPSED);
1864 }
1865 return ass;
1866 }
1867
1868 /**
1869 * Get the AccessibleAction associated with this object. In the
1870 * implementation of the Java Accessibility API for this class,
1871 * return this object, which is responsible for implementing the
1872 * AccessibleAction interface on behalf of itself.
1873 *
1874 * @return this object
1875 */
1876 public AccessibleAction getAccessibleAction() {
1877 return this ;
1878 }
1879
1880 /**
1881 * Return a description of the specified action of the object.
1882 *
1883 * @param i zero-based index of the actions
1884 */
1885 public String getAccessibleActionDescription(int i) {
1886 if (i == 0) {
1887 return UIManager.getString("ComboBox.togglePopupText");
1888 } else {
1889 return null;
1890 }
1891 }
1892
1893 /**
1894 * Returns the number of Actions available in this object. The
1895 * default behavior of a combo box is to have one action.
1896 *
1897 * @return 1, the number of Actions in this object
1898 */
1899 public int getAccessibleActionCount() {
1900 return 1;
1901 }
1902
1903 /**
1904 * Perform the specified Action on the object
1905 *
1906 * @param i zero-based index of actions
1907 * @return true if the the action was performed; else false.
1908 */
1909 public boolean doAccessibleAction(int i) {
1910 if (i == 0) {
1911 setPopupVisible(!isPopupVisible());
1912 return true;
1913 } else {
1914 return false;
1915 }
1916 }
1917
1918 /**
1919 * Get the AccessibleSelection associated with this object. In the
1920 * implementation of the Java Accessibility API for this class,
1921 * return this object, which is responsible for implementing the
1922 * AccessibleSelection interface on behalf of itself.
1923 *
1924 * @return this object
1925 */
1926 public AccessibleSelection getAccessibleSelection() {
1927 return this ;
1928 }
1929
1930 /**
1931 * Returns the number of Accessible children currently selected.
1932 * If no children are selected, the return value will be 0.
1933 *
1934 * @return the number of items currently selected.
1935 * @since 1.3
1936 */
1937 public int getAccessibleSelectionCount() {
1938 Object o = JComboBox.this .getSelectedItem();
1939 if (o != null) {
1940 return 1;
1941 } else {
1942 return 0;
1943 }
1944 }
1945
1946 /**
1947 * Returns an Accessible representing the specified selected child
1948 * in the popup. If there isn't a selection, or there are
1949 * fewer children selected than the integer passed in, the return
1950 * value will be null.
1951 * <p>Note that the index represents the i-th selected child, which
1952 * is different from the i-th child.
1953 *
1954 * @param i the zero-based index of selected children
1955 * @return the i-th selected child
1956 * @see #getAccessibleSelectionCount
1957 * @since 1.3
1958 */
1959 public Accessible getAccessibleSelection(int i) {
1960 // Get the popup
1961 Accessible a = JComboBox.this .getUI().getAccessibleChild(
1962 JComboBox.this , 0);
1963 if (a != null
1964 && a instanceof javax.swing.plaf.basic.ComboPopup) {
1965
1966 // get the popup list
1967 JList list = ((javax.swing.plaf.basic.ComboPopup) a)
1968 .getList();
1969
1970 // return the i-th selection in the popup list
1971 AccessibleContext ac = list.getAccessibleContext();
1972 if (ac != null) {
1973 AccessibleSelection as = ac
1974 .getAccessibleSelection();
1975 if (as != null) {
1976 return as.getAccessibleSelection(i);
1977 }
1978 }
1979 }
1980 return null;
1981 }
1982
1983 /**
1984 * Determines if the current child of this object is selected.
1985 *
1986 * @return true if the current child of this object is selected;
1987 * else false
1988 * @param i the zero-based index of the child in this Accessible
1989 * object.
1990 * @see AccessibleContext#getAccessibleChild
1991 * @since 1.3
1992 */
1993 public boolean isAccessibleChildSelected(int i) {
1994 return JComboBox.this .getSelectedIndex() == i;
1995 }
1996
1997 /**
1998 * Adds the specified Accessible child of the object to the object's
1999 * selection. If the object supports multiple selections,
2000 * the specified child is added to any existing selection, otherwise
2001 * it replaces any existing selection in the object. If the
2002 * specified child is already selected, this method has no effect.
2003 *
2004 * @param i the zero-based index of the child
2005 * @see AccessibleContext#getAccessibleChild
2006 * @since 1.3
2007 */
2008 public void addAccessibleSelection(int i) {
2009 // TIGER - 4856195
2010 clearAccessibleSelection();
2011 JComboBox.this .setSelectedIndex(i);
2012 }
2013
2014 /**
2015 * Removes the specified child of the object from the object's
2016 * selection. If the specified item isn't currently selected, this
2017 * method has no effect.
2018 *
2019 * @param i the zero-based index of the child
2020 * @see AccessibleContext#getAccessibleChild
2021 * @since 1.3
2022 */
2023 public void removeAccessibleSelection(int i) {
2024 if (JComboBox.this .getSelectedIndex() == i) {
2025 clearAccessibleSelection();
2026 }
2027 }
2028
2029 /**
2030 * Clears the selection in the object, so that no children in the
2031 * object are selected.
2032 * @since 1.3
2033 */
2034 public void clearAccessibleSelection() {
2035 JComboBox.this .setSelectedIndex(-1);
2036 }
2037
2038 /**
2039 * Causes every child of the object to be selected
2040 * if the object supports multiple selections.
2041 * @since 1.3
2042 */
2043 public void selectAllAccessibleSelection() {
2044 // do nothing since multiple selection is not supported
2045 }
2046
2047 // public Accessible getAccessibleAt(Point p) {
2048 // Accessible a = getAccessibleChild(1);
2049 // if ( a != null ) {
2050 // return a; // the editor
2051 // }
2052 // else {
2053 // return getAccessibleChild(0); // the list
2054 // }
2055 // }
2056 private EditorAccessibleContext editorAccessibleContext = null;
2057
2058 private class AccessibleEditor implements Accessible {
2059 public AccessibleContext getAccessibleContext() {
2060 if (editorAccessibleContext == null) {
2061 Component c = JComboBox.this .getEditor()
2062 .getEditorComponent();
2063 if (c instanceof Accessible) {
2064 editorAccessibleContext = new EditorAccessibleContext(
2065 (Accessible) c);
2066 }
2067 }
2068 return editorAccessibleContext;
2069 }
2070 }
2071
2072 /*
2073 * Wrapper class for the AccessibleContext implemented by the
2074 * combo box editor. Delegates all method calls except
2075 * getAccessibleIndexInParent to the editor. The
2076 * getAccessibleIndexInParent method returns the selected
2077 * index in the combo box.
2078 */
2079 private class EditorAccessibleContext extends AccessibleContext {
2080
2081 private AccessibleContext ac;
2082
2083 private EditorAccessibleContext() {
2084 }
2085
2086 /*
2087 * @param a the AccessibleContext implemented by the
2088 * combo box editor
2089 */
2090 EditorAccessibleContext(Accessible a) {
2091 this .ac = a.getAccessibleContext();
2092 }
2093
2094 /**
2095 * Gets the accessibleName property of this object. The accessibleName
2096 * property of an object is a localized String that designates the purpose
2097 * of the object. For example, the accessibleName property of a label
2098 * or button might be the text of the label or button itself. In the
2099 * case of an object that doesn't display its name, the accessibleName
2100 * should still be set. For example, in the case of a text field used
2101 * to enter the name of a city, the accessibleName for the en_US locale
2102 * could be 'city.'
2103 *
2104 * @return the localized name of the object; null if this
2105 * object does not have a name
2106 *
2107 * @see #setAccessibleName
2108 */
2109 public String getAccessibleName() {
2110 return ac.getAccessibleName();
2111 }
2112
2113 /**
2114 * Sets the localized accessible name of this object. Changing the
2115 * name will cause a PropertyChangeEvent to be fired for the
2116 * ACCESSIBLE_NAME_PROPERTY property.
2117 *
2118 * @param s the new localized name of the object.
2119 *
2120 * @see #getAccessibleName
2121 * @see #addPropertyChangeListener
2122 *
2123 * @beaninfo
2124 * preferred: true
2125 * description: Sets the accessible name for the component.
2126 */
2127 public void setAccessibleName(String s) {
2128 ac.setAccessibleName(s);
2129 }
2130
2131 /**
2132 * Gets the accessibleDescription property of this object. The
2133 * accessibleDescription property of this object is a short localized
2134 * phrase describing the purpose of the object. For example, in the
2135 * case of a 'Cancel' button, the accessibleDescription could be
2136 * 'Ignore changes and close dialog box.'
2137 *
2138 * @return the localized description of the object; null if
2139 * this object does not have a description
2140 *
2141 * @see #setAccessibleDescription
2142 */
2143 public String getAccessibleDescription() {
2144 return ac.getAccessibleDescription();
2145 }
2146
2147 /**
2148 * Sets the accessible description of this object. Changing the
2149 * name will cause a PropertyChangeEvent to be fired for the
2150 * ACCESSIBLE_DESCRIPTION_PROPERTY property.
2151 *
2152 * @param s the new localized description of the object
2153 *
2154 * @see #setAccessibleName
2155 * @see #addPropertyChangeListener
2156 *
2157 * @beaninfo
2158 * preferred: true
2159 * description: Sets the accessible description for the component.
2160 */
2161 public void setAccessibleDescription(String s) {
2162 ac.setAccessibleDescription(s);
2163 }
2164
2165 /**
2166 * Gets the role of this object. The role of the object is the generic
2167 * purpose or use of the class of this object. For example, the role
2168 * of a push button is AccessibleRole.PUSH_BUTTON. The roles in
2169 * AccessibleRole are provided so component developers can pick from
2170 * a set of predefined roles. This enables assistive technologies to
2171 * provide a consistent interface to various tweaked subclasses of
2172 * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
2173 * that act like a push button) as well as distinguish between sublasses
2174 * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
2175 * and AccessibleRole.RADIO_BUTTON for radio buttons).
2176 * <p>Note that the AccessibleRole class is also extensible, so
2177 * custom component developers can define their own AccessibleRole's
2178 * if the set of predefined roles is inadequate.
2179 *
2180 * @return an instance of AccessibleRole describing the role of the object
2181 * @see AccessibleRole
2182 */
2183 public AccessibleRole getAccessibleRole() {
2184 return ac.getAccessibleRole();
2185 }
2186
2187 /**
2188 * Gets the state set of this object. The AccessibleStateSet of an object
2189 * is composed of a set of unique AccessibleStates. A change in the
2190 * AccessibleStateSet of an object will cause a PropertyChangeEvent to
2191 * be fired for the ACCESSIBLE_STATE_PROPERTY property.
2192 *
2193 * @return an instance of AccessibleStateSet containing the
2194 * current state set of the object
2195 * @see AccessibleStateSet
2196 * @see AccessibleState
2197 * @see #addPropertyChangeListener
2198 */
2199 public AccessibleStateSet getAccessibleStateSet() {
2200 return ac.getAccessibleStateSet();
2201 }
2202
2203 /**
2204 * Gets the Accessible parent of this object.
2205 *
2206 * @return the Accessible parent of this object; null if this
2207 * object does not have an Accessible parent
2208 */
2209 public Accessible getAccessibleParent() {
2210 return ac.getAccessibleParent();
2211 }
2212
2213 /**
2214 * Sets the Accessible parent of this object. This is meant to be used
2215 * only in the situations where the actual component's parent should
2216 * not be treated as the component's accessible parent and is a method
2217 * that should only be called by the parent of the accessible child.
2218 *
2219 * @param a - Accessible to be set as the parent
2220 */
2221 public void setAccessibleParent(Accessible a) {
2222 ac.setAccessibleParent(a);
2223 }
2224
2225 /**
2226 * Gets the 0-based index of this object in its accessible parent.
2227 *
2228 * @return the 0-based index of this object in its parent; -1 if this
2229 * object does not have an accessible parent.
2230 *
2231 * @see #getAccessibleParent
2232 * @see #getAccessibleChildrenCount
2233 * @see #getAccessibleChild
2234 */
2235 public int getAccessibleIndexInParent() {
2236 return JComboBox.this .getSelectedIndex();
2237 }
2238
2239 /**
2240 * Returns the number of accessible children of the object.
2241 *
2242 * @return the number of accessible children of the object.
2243 */
2244 public int getAccessibleChildrenCount() {
2245 return ac.getAccessibleChildrenCount();
2246 }
2247
2248 /**
2249 * Returns the specified Accessible child of the object. The Accessible
2250 * children of an Accessible object are zero-based, so the first child
2251 * of an Accessible child is at index 0, the second child is at index 1,
2252 * and so on.
2253 *
2254 * @param i zero-based index of child
2255 * @return the Accessible child of the object
2256 * @see #getAccessibleChildrenCount
2257 */
2258 public Accessible getAccessibleChild(int i) {
2259 return ac.getAccessibleChild(i);
2260 }
2261
2262 /**
2263 * Gets the locale of the component. If the component does not have a
2264 * locale, then the locale of its parent is returned.
2265 *
2266 * @return this component's locale. If this component does not have
2267 * a locale, the locale of its parent is returned.
2268 *
2269 * @exception IllegalComponentStateException
2270 * If the Component does not have its own locale and has not yet been
2271 * added to a containment hierarchy such that the locale can be
2272 * determined from the containing parent.
2273 */
2274 public Locale getLocale()
2275 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(
2295 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(
2307 PropertyChangeListener listener) {
2308 ac.removePropertyChangeListener(listener);
2309 }
2310
2311 /**
2312 * Gets the AccessibleAction associated with this object that supports
2313 * one or more actions.
2314 *
2315 * @return AccessibleAction if supported by object; else return null
2316 * @see AccessibleAction
2317 */
2318 public AccessibleAction getAccessibleAction() {
2319 return ac.getAccessibleAction();
2320 }
2321
2322 /**
2323 * Gets the AccessibleComponent associated with this object that has a
2324 * graphical representation.
2325 *
2326 * @return AccessibleComponent if supported by object; else return null
2327 * @see AccessibleComponent
2328 */
2329 public AccessibleComponent getAccessibleComponent() {
2330 return ac.getAccessibleComponent();
2331 }
2332
2333 /**
2334 * Gets the AccessibleSelection associated with this object which allows its
2335 * Accessible children to be selected.
2336 *
2337 * @return AccessibleSelection if supported by object; else return null
2338 * @see AccessibleSelection
2339 */
2340 public AccessibleSelection getAccessibleSelection() {
2341 return ac.getAccessibleSelection();
2342 }
2343
2344 /**
2345 * Gets the AccessibleText associated with this object presenting
2346 * text on the display.
2347 *
2348 * @return AccessibleText if supported by object; else return null
2349 * @see AccessibleText
2350 */
2351 public AccessibleText getAccessibleText() {
2352 return ac.getAccessibleText();
2353 }
2354
2355 /**
2356 * Gets the AccessibleEditableText associated with this object
2357 * presenting editable text on the display.
2358 *
2359 * @return AccessibleEditableText if supported by object; else return null
2360 * @see AccessibleEditableText
2361 */
2362 public AccessibleEditableText getAccessibleEditableText() {
2363 return ac.getAccessibleEditableText();
2364 }
2365
2366 /**
2367 * Gets the AccessibleValue associated with this object that supports a
2368 * Numerical value.
2369 *
2370 * @return AccessibleValue if supported by object; else return null
2371 * @see AccessibleValue
2372 */
2373 public AccessibleValue getAccessibleValue() {
2374 return ac.getAccessibleValue();
2375 }
2376
2377 /**
2378 * Gets the AccessibleIcons associated with an object that has
2379 * one or more associated icons
2380 *
2381 * @return an array of AccessibleIcon if supported by object;
2382 * otherwise return null
2383 * @see AccessibleIcon
2384 */
2385 public AccessibleIcon[] getAccessibleIcon() {
2386 return ac.getAccessibleIcon();
2387 }
2388
2389 /**
2390 * Gets the AccessibleRelationSet associated with an object
2391 *
2392 * @return an AccessibleRelationSet if supported by object;
2393 * otherwise return null
2394 * @see AccessibleRelationSet
2395 */
2396 public AccessibleRelationSet getAccessibleRelationSet() {
2397 return ac.getAccessibleRelationSet();
2398 }
2399
2400 /**
2401 * Gets the AccessibleTable associated with an object
2402 *
2403 * @return an AccessibleTable if supported by object;
2404 * otherwise return null
2405 * @see AccessibleTable
2406 */
2407 public AccessibleTable getAccessibleTable() {
2408 return ac.getAccessibleTable();
2409 }
2410
2411 /**
2412 * Support for reporting bound property changes. If oldValue and
2413 * newValue are not equal and the PropertyChangeEvent listener list
2414 * is not empty, then fire a PropertyChange event to each listener.
2415 * In general, this is for use by the Accessible objects themselves
2416 * and should not be called by an application program.
2417 * @param propertyName The programmatic name of the property that
2418 * was changed.
2419 * @param oldValue The old value of the property.
2420 * @param newValue The new value of the property.
2421 * @see java.beans.PropertyChangeSupport
2422 * @see #addPropertyChangeListener
2423 * @see #removePropertyChangeListener
2424 * @see #ACCESSIBLE_NAME_PROPERTY
2425 * @see #ACCESSIBLE_DESCRIPTION_PROPERTY
2426 * @see #ACCESSIBLE_STATE_PROPERTY
2427 * @see #ACCESSIBLE_VALUE_PROPERTY
2428 * @see #ACCESSIBLE_SELECTION_PROPERTY
2429 * @see #ACCESSIBLE_TEXT_PROPERTY
2430 * @see #ACCESSIBLE_VISIBLE_DATA_PROPERTY
2431 */
2432 public void firePropertyChange(String propertyName,
2433 Object oldValue, Object newValue) {
2434 ac.firePropertyChange(propertyName, oldValue, newValue);
2435 }
2436 }
2437
2438 } // innerclass AccessibleJComboBox
2439 }
|