1 /* 2 * Copyright (c) 1995, 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 26 package java.awt; 27 28 import java.awt.event.ActionEvent; 29 import java.awt.event.ActionListener; 30 import java.awt.event.InputEvent; 31 import java.awt.event.KeyEvent; 32 import java.awt.peer.MenuItemPeer; 33 import java.io.IOException; 34 import java.io.ObjectInputStream; 35 import java.io.ObjectOutputStream; 36 import java.util.EventListener; 37 38 import javax.accessibility.Accessible; 39 import javax.accessibility.AccessibleAction; 40 import javax.accessibility.AccessibleContext; 41 import javax.accessibility.AccessibleRole; 42 import javax.accessibility.AccessibleValue; 43 44 import sun.awt.AWTAccessor; 45 46 /** 47 * All items in a menu must belong to the class 48 * {@code MenuItem}, or one of its subclasses. 49 * <p> 50 * The default {@code MenuItem} object embodies 51 * a simple labeled menu item. 52 * <p> 53 * This picture of a menu bar shows five menu items: 54 * <IMG SRC="doc-files/MenuBar-1.gif" alt="The following text describes this graphic." 55 * style="float:center; margin: 7px 10px;"> 56 * <br style="clear:left;"> 57 * The first two items are simple menu items, labeled 58 * {@code "Basic"} and {@code "Simple"}. 59 * Following these two items is a separator, which is itself 60 * a menu item, created with the label {@code "-"}. 61 * Next is an instance of {@code CheckboxMenuItem} 62 * labeled {@code "Check"}. The final menu item is a 63 * submenu labeled <code>"More Examples"</code>, 64 * and this submenu is an instance of {@code Menu}. 65 * <p> 66 * When a menu item is selected, AWT sends an action event to 67 * the menu item. Since the event is an 68 * instance of {@code ActionEvent}, the {@code processEvent} 69 * method examines the event and passes it along to 70 * {@code processActionEvent}. The latter method redirects the 71 * event to any {@code ActionListener} objects that have 72 * registered an interest in action events generated by this 73 * menu item. 74 * <P> 75 * Note that the subclass {@code Menu} overrides this behavior and 76 * does not send any event to the frame until one of its subitems is 77 * selected. 78 * 79 * @author Sami Shaio 80 */ 81 public class MenuItem extends MenuComponent implements Accessible { 82 83 static { 84 /* ensure that the necessary native libraries are loaded */ 85 Toolkit.loadLibraries(); 86 if (!GraphicsEnvironment.isHeadless()) { 87 initIDs(); 88 } 89 90 AWTAccessor.setMenuItemAccessor( 91 new AWTAccessor.MenuItemAccessor() { 92 public boolean isEnabled(MenuItem item) { 93 return item.enabled; 94 } 95 96 public String getLabel(MenuItem item) { 97 return item.label; 98 } 99 100 public MenuShortcut getShortcut(MenuItem item) { 101 return item.shortcut; 102 } 103 104 public String getActionCommandImpl(MenuItem item) { 105 return item.getActionCommandImpl(); 106 } 107 108 public boolean isItemEnabled(MenuItem item) { 109 return item.isItemEnabled(); 110 } 111 }); 112 } 113 114 /** 115 * A value to indicate whether a menu item is enabled 116 * or not. If it is enabled, {@code enabled} will 117 * be set to true. Else {@code enabled} will 118 * be set to false. 119 * 120 * @serial 121 * @see #isEnabled() 122 * @see #setEnabled(boolean) 123 */ 124 private volatile boolean enabled = true; 125 126 /** 127 * {@code label} is the label of a menu item. 128 * It can be any string. 129 * 130 * @serial 131 * @see #getLabel() 132 * @see #setLabel(String) 133 */ 134 volatile String label; 135 136 /** 137 * This field indicates the command that has been issued 138 * by a particular menu item. 139 * By default the {@code actionCommand} 140 * is the label of the menu item, unless it has been 141 * set using setActionCommand. 142 * 143 * @serial 144 * @see #setActionCommand(String) 145 * @see #getActionCommand() 146 */ 147 private volatile String actionCommand; 148 149 /** 150 * The eventMask is ONLY set by subclasses via enableEvents. 151 * The mask should NOT be set when listeners are registered 152 * so that we can distinguish the difference between when 153 * listeners request events and subclasses request them. 154 * 155 * @serial 156 */ 157 volatile long eventMask; 158 159 private transient volatile ActionListener actionListener; 160 161 /** 162 * A sequence of key stokes that ia associated with 163 * a menu item. 164 * Note :in 1.1.2 you must use setActionCommand() 165 * on a menu item in order for its shortcut to 166 * work. 167 * 168 * @serial 169 * @see #getShortcut() 170 * @see #setShortcut(MenuShortcut) 171 * @see #deleteShortcut() 172 */ 173 private volatile MenuShortcut shortcut; 174 175 private static final String base = "menuitem"; 176 private static int nameCounter = 0; 177 178 /* 179 * JDK 1.1 serialVersionUID 180 */ 181 private static final long serialVersionUID = -21757335363267194L; 182 183 /** 184 * Constructs a new MenuItem with an empty label and no keyboard 185 * shortcut. 186 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 187 * returns true. 188 * @see java.awt.GraphicsEnvironment#isHeadless 189 * @since 1.1 190 */ 191 public MenuItem() throws HeadlessException { 192 this("", null); 193 } 194 195 /** 196 * Constructs a new MenuItem with the specified label 197 * and no keyboard shortcut. Note that use of "-" in 198 * a label is reserved to indicate a separator between 199 * menu items. By default, all menu items except for 200 * separators are enabled. 201 * @param label the label for this menu item. 202 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 203 * returns true. 204 * @see java.awt.GraphicsEnvironment#isHeadless 205 * @since 1.0 206 */ 207 public MenuItem(String label) throws HeadlessException { 208 this(label, null); 209 } 210 211 /** 212 * Create a menu item with an associated keyboard shortcut. 213 * Note that use of "-" in a label is reserved to indicate 214 * a separator between menu items. By default, all menu 215 * items except for separators are enabled. 216 * @param label the label for this menu item. 217 * @param s the instance of {@code MenuShortcut} 218 * associated with this menu item. 219 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 220 * returns true. 221 * @see java.awt.GraphicsEnvironment#isHeadless 222 * @since 1.1 223 */ 224 public MenuItem(String label, MenuShortcut s) throws HeadlessException { 225 this.label = label; 226 this.shortcut = s; 227 } 228 229 /** 230 * Construct a name for this MenuComponent. Called by getName() when 231 * the name is null. 232 */ 233 String constructComponentName() { 234 synchronized (MenuItem.class) { 235 return base + nameCounter++; 236 } 237 } 238 239 /** 240 * Creates the menu item's peer. The peer allows us to modify the 241 * appearance of the menu item without changing its functionality. 242 */ 243 public void addNotify() { 244 synchronized (getTreeLock()) { 245 if (peer == null) 246 peer = getComponentFactory().createMenuItem(this); 247 } 248 } 249 250 /** 251 * Gets the label for this menu item. 252 * @return the label of this menu item, or {@code null} 253 if this menu item has no label. 254 * @see java.awt.MenuItem#setLabel 255 * @since 1.0 256 */ 257 public String getLabel() { 258 return label; 259 } 260 261 /** 262 * Sets the label for this menu item to the specified label. 263 * @param label the new label, or {@code null} for no label. 264 * @see java.awt.MenuItem#getLabel 265 * @since 1.0 266 */ 267 public synchronized void setLabel(String label) { 268 this.label = label; 269 MenuItemPeer peer = (MenuItemPeer)this.peer; 270 if (peer != null) { 271 peer.setLabel(label); 272 } 273 } 274 275 /** 276 * Checks whether this menu item is enabled. 277 * 278 * @return {@code true} if the item is enabled; 279 * otherwise {@code false} 280 * @see java.awt.MenuItem#setEnabled 281 * @since 1.0 282 */ 283 public boolean isEnabled() { 284 return enabled; 285 } 286 287 /** 288 * Sets whether or not this menu item can be chosen. 289 * @param b if {@code true}, enables this menu item; 290 * if {@code false}, disables it. 291 * @see java.awt.MenuItem#isEnabled 292 * @since 1.1 293 */ 294 public synchronized void setEnabled(boolean b) { 295 enable(b); 296 } 297 298 /** 299 * @deprecated As of JDK version 1.1, 300 * replaced by {@code setEnabled(boolean)}. 301 */ 302 @Deprecated 303 public synchronized void enable() { 304 enabled = true; 305 MenuItemPeer peer = (MenuItemPeer)this.peer; 306 if (peer != null) { 307 peer.setEnabled(true); 308 } 309 } 310 311 /** 312 * Sets whether or not this menu item can be chosen. 313 * 314 * @param b if {@code true}, enables this menu item; 315 * otherwise disables 316 * @deprecated As of JDK version 1.1, 317 * replaced by {@code setEnabled(boolean)}. 318 */ 319 @Deprecated 320 public void enable(boolean b) { 321 if (b) { 322 enable(); 323 } else { 324 disable(); 325 } 326 } 327 328 /** 329 * @deprecated As of JDK version 1.1, 330 * replaced by {@code setEnabled(boolean)}. 331 */ 332 @Deprecated 333 public synchronized void disable() { 334 enabled = false; 335 MenuItemPeer peer = (MenuItemPeer)this.peer; 336 if (peer != null) { 337 peer.setEnabled(false); 338 } 339 } 340 341 /** 342 * Get the {@code MenuShortcut} object associated with this 343 * menu item, 344 * @return the menu shortcut associated with this menu item, 345 * or {@code null} if none has been specified. 346 * @see java.awt.MenuItem#setShortcut 347 * @since 1.1 348 */ 349 public MenuShortcut getShortcut() { 350 return shortcut; 351 } 352 353 /** 354 * Set the {@code MenuShortcut} object associated with this 355 * menu item. If a menu shortcut is already associated with 356 * this menu item, it is replaced. 357 * @param s the menu shortcut to associate 358 * with this menu item. 359 * @see java.awt.MenuItem#getShortcut 360 * @since 1.1 361 */ 362 public void setShortcut(MenuShortcut s) { 363 shortcut = s; 364 MenuItemPeer peer = (MenuItemPeer)this.peer; 365 if (peer != null) { 366 peer.setLabel(label); 367 } 368 } 369 370 /** 371 * Delete any {@code MenuShortcut} object associated 372 * with this menu item. 373 * @since 1.1 374 */ 375 public void deleteShortcut() { 376 shortcut = null; 377 MenuItemPeer peer = (MenuItemPeer)this.peer; 378 if (peer != null) { 379 peer.setLabel(label); 380 } 381 } 382 383 /* 384 * Delete a matching MenuShortcut associated with this MenuItem. 385 * Used when iterating Menus. 386 */ 387 void deleteShortcut(MenuShortcut s) { 388 if (s.equals(shortcut)) { 389 shortcut = null; 390 MenuItemPeer peer = (MenuItemPeer)this.peer; 391 if (peer != null) { 392 peer.setLabel(label); 393 } 394 } 395 } 396 397 /* 398 * The main goal of this method is to post an appropriate event 399 * to the event queue when menu shortcut is pressed. However, 400 * in subclasses this method may do more than just posting 401 * an event. 402 */ 403 void doMenuEvent(long when, int modifiers) { 404 Toolkit.getEventQueue().postEvent( 405 new ActionEvent(this, ActionEvent.ACTION_PERFORMED, 406 getActionCommand(), when, modifiers)); 407 } 408 409 /* 410 * Returns true if the item and all its ancestors are 411 * enabled, false otherwise 412 */ 413 private final boolean isItemEnabled() { 414 // Fix For 6185151: Menu shortcuts of all menuitems within a menu 415 // should be disabled when the menu itself is disabled 416 if (!isEnabled()) { 417 return false; 418 } 419 MenuContainer container = getParent_NoClientCode(); 420 do { 421 if (!(container instanceof Menu)) { 422 return true; 423 } 424 Menu menu = (Menu)container; 425 if (!menu.isEnabled()) { 426 return false; 427 } 428 container = menu.getParent_NoClientCode(); 429 } while (container != null); 430 return true; 431 } 432 433 /* 434 * Post an ActionEvent to the target (on 435 * keydown) and the item is enabled. 436 * Returns true if there is an associated shortcut. 437 */ 438 @SuppressWarnings("deprecation") 439 boolean handleShortcut(KeyEvent e) { 440 MenuShortcut s = new MenuShortcut(e.getKeyCode(), 441 (e.getModifiers() & InputEvent.SHIFT_MASK) > 0); 442 MenuShortcut sE = new MenuShortcut(e.getExtendedKeyCode(), 443 (e.getModifiers() & InputEvent.SHIFT_MASK) > 0); 444 // Fix For 6185151: Menu shortcuts of all menuitems within a menu 445 // should be disabled when the menu itself is disabled 446 if ((s.equals(shortcut) || sE.equals(shortcut)) && isItemEnabled()) { 447 // MenuShortcut match -- issue an event on keydown. 448 if (e.getID() == KeyEvent.KEY_PRESSED) { 449 doMenuEvent(e.getWhen(), e.getModifiers()); 450 } else { 451 // silently eat key release. 452 } 453 return true; 454 } 455 return false; 456 } 457 458 MenuItem getShortcutMenuItem(MenuShortcut s) { 459 return (s.equals(shortcut)) ? this : null; 460 } 461 462 /** 463 * Enables event delivery to this menu item for events 464 * to be defined by the specified event mask parameter 465 * <p> 466 * Since event types are automatically enabled when a listener for 467 * that type is added to the menu item, this method only needs 468 * to be invoked by subclasses of {@code MenuItem} which desire to 469 * have the specified event types delivered to {@code processEvent} 470 * regardless of whether a listener is registered. 471 * 472 * @param eventsToEnable the event mask defining the event types 473 * @see java.awt.MenuItem#processEvent 474 * @see java.awt.MenuItem#disableEvents 475 * @see java.awt.Component#enableEvents 476 * @since 1.1 477 */ 478 protected final void enableEvents(long eventsToEnable) { 479 eventMask |= eventsToEnable; 480 newEventsOnly = true; 481 } 482 483 /** 484 * Disables event delivery to this menu item for events 485 * defined by the specified event mask parameter. 486 * 487 * @param eventsToDisable the event mask defining the event types 488 * @see java.awt.MenuItem#processEvent 489 * @see java.awt.MenuItem#enableEvents 490 * @see java.awt.Component#disableEvents 491 * @since 1.1 492 */ 493 protected final void disableEvents(long eventsToDisable) { 494 eventMask &= ~eventsToDisable; 495 } 496 497 /** 498 * Sets the command name of the action event that is fired 499 * by this menu item. 500 * <p> 501 * By default, the action command is set to the label of 502 * the menu item. 503 * @param command the action command to be set 504 * for this menu item. 505 * @see java.awt.MenuItem#getActionCommand 506 * @since 1.1 507 */ 508 public void setActionCommand(String command) { 509 actionCommand = command; 510 } 511 512 /** 513 * Gets the command name of the action event that is fired 514 * by this menu item. 515 * 516 * @return the action command name 517 * @see java.awt.MenuItem#setActionCommand 518 * @since 1.1 519 */ 520 public String getActionCommand() { 521 return getActionCommandImpl(); 522 } 523 524 // This is final so it can be called on the Toolkit thread. 525 final String getActionCommandImpl() { 526 return (actionCommand == null? label : actionCommand); 527 } 528 529 /** 530 * Adds the specified action listener to receive action events 531 * from this menu item. 532 * If l is null, no exception is thrown and no action is performed. 533 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads" 534 * >AWT Threading Issues</a> for details on AWT's threading model. 535 * 536 * @param l the action listener. 537 * @see #removeActionListener 538 * @see #getActionListeners 539 * @see java.awt.event.ActionEvent 540 * @see java.awt.event.ActionListener 541 * @since 1.1 542 */ 543 public synchronized void addActionListener(ActionListener l) { 544 if (l == null) { 545 return; 546 } 547 actionListener = AWTEventMulticaster.add(actionListener, l); 548 newEventsOnly = true; 549 } 550 551 /** 552 * Removes the specified action listener so it no longer receives 553 * action events from this menu item. 554 * If l is null, no exception is thrown and no action is performed. 555 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads" 556 * >AWT Threading Issues</a> for details on AWT's threading model. 557 * 558 * @param l the action listener. 559 * @see #addActionListener 560 * @see #getActionListeners 561 * @see java.awt.event.ActionEvent 562 * @see java.awt.event.ActionListener 563 * @since 1.1 564 */ 565 public synchronized void removeActionListener(ActionListener l) { 566 if (l == null) { 567 return; 568 } 569 actionListener = AWTEventMulticaster.remove(actionListener, l); 570 } 571 572 /** 573 * Returns an array of all the action listeners 574 * registered on this menu item. 575 * 576 * @return all of this menu item's {@code ActionListener}s 577 * or an empty array if no action 578 * listeners are currently registered 579 * 580 * @see #addActionListener 581 * @see #removeActionListener 582 * @see java.awt.event.ActionEvent 583 * @see java.awt.event.ActionListener 584 * @since 1.4 585 */ 586 public synchronized ActionListener[] getActionListeners() { 587 return getListeners(ActionListener.class); 588 } 589 590 /** 591 * Returns an array of all the objects currently registered 592 * as <code><em>Foo</em>Listener</code>s 593 * upon this {@code MenuItem}. 594 * <code><em>Foo</em>Listener</code>s are registered using the 595 * <code>add<em>Foo</em>Listener</code> method. 596 * 597 * <p> 598 * You can specify the {@code listenerType} argument 599 * with a class literal, such as 600 * <code><em>Foo</em>Listener.class</code>. 601 * For example, you can query a 602 * {@code MenuItem m} 603 * for its action listeners with the following code: 604 * 605 * <pre>ActionListener[] als = (ActionListener[])(m.getListeners(ActionListener.class));</pre> 606 * 607 * If no such listeners exist, this method returns an empty array. 608 * 609 * @param <T> the type of the listeners 610 * @param listenerType the type of listeners requested; this parameter 611 * should specify an interface that descends from 612 * {@code java.util.EventListener} 613 * @return an array of all objects registered as 614 * <code><em>Foo</em>Listener</code>s on this menu item, 615 * or an empty array if no such 616 * listeners have been added 617 * @exception ClassCastException if {@code listenerType} 618 * doesn't specify a class or interface that implements 619 * {@code java.util.EventListener} 620 * 621 * @see #getActionListeners 622 * @since 1.3 623 */ 624 public <T extends EventListener> T[] getListeners(Class<T> listenerType) { 625 EventListener l = null; 626 if (listenerType == ActionListener.class) { 627 l = actionListener; 628 } 629 return AWTEventMulticaster.getListeners(l, listenerType); 630 } 631 632 /** 633 * Processes events on this menu item. If the event is an 634 * instance of {@code ActionEvent}, it invokes 635 * {@code processActionEvent}, another method 636 * defined by {@code MenuItem}. 637 * <p> 638 * Currently, menu items only support action events. 639 * <p>Note that if the event parameter is {@code null} 640 * the behavior is unspecified and may result in an 641 * exception. 642 * 643 * @param e the event 644 * @see java.awt.MenuItem#processActionEvent 645 * @since 1.1 646 */ 647 protected void processEvent(AWTEvent e) { 648 if (e instanceof ActionEvent) { 649 processActionEvent((ActionEvent)e); 650 } 651 } 652 653 // REMIND: remove when filtering is done at lower level 654 boolean eventEnabled(AWTEvent e) { 655 if (e.id == ActionEvent.ACTION_PERFORMED) { 656 if ((eventMask & AWTEvent.ACTION_EVENT_MASK) != 0 || 657 actionListener != null) { 658 return true; 659 } 660 return false; 661 } 662 return super.eventEnabled(e); 663 } 664 665 /** 666 * Processes action events occurring on this menu item, 667 * by dispatching them to any registered 668 * {@code ActionListener} objects. 669 * This method is not called unless action events are 670 * enabled for this component. Action events are enabled 671 * when one of the following occurs: 672 * <ul> 673 * <li>An {@code ActionListener} object is registered 674 * via {@code addActionListener}. 675 * <li>Action events are enabled via {@code enableEvents}. 676 * </ul> 677 * <p>Note that if the event parameter is {@code null} 678 * the behavior is unspecified and may result in an 679 * exception. 680 * 681 * @param e the action event 682 * @see java.awt.event.ActionEvent 683 * @see java.awt.event.ActionListener 684 * @see java.awt.MenuItem#enableEvents 685 * @since 1.1 686 */ 687 protected void processActionEvent(ActionEvent e) { 688 ActionListener listener = actionListener; 689 if (listener != null) { 690 listener.actionPerformed(e); 691 } 692 } 693 694 /** 695 * Returns a string representing the state of this {@code MenuItem}. 696 * This method is intended to be used only for debugging purposes, and the 697 * content and format of the returned string may vary between 698 * implementations. The returned string may be empty but may not be 699 * {@code null}. 700 * 701 * @return the parameter string of this menu item 702 */ 703 public String paramString() { 704 String str = ",label=" + label; 705 if (shortcut != null) { 706 str += ",shortcut=" + shortcut; 707 } 708 return super.paramString() + str; 709 } 710 711 712 /* Serialization support. 713 */ 714 715 /** 716 * Menu item serialized data version. 717 * 718 * @serial 719 */ 720 private int menuItemSerializedDataVersion = 1; 721 722 /** 723 * Writes default serializable fields to stream. Writes 724 * a list of serializable {@code ActionListeners} 725 * as optional data. The non-serializable listeners are 726 * detected and no attempt is made to serialize them. 727 * 728 * @param s the {@code ObjectOutputStream} to write 729 * @serialData {@code null} terminated sequence of 0 730 * or more pairs; the pair consists of a {@code String} 731 * and an {@code Object}; the {@code String} 732 * indicates the type of object and is one of the following: 733 * {@code actionListenerK} indicating an 734 * {@code ActionListener} object 735 * 736 * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener) 737 * @see #readObject(ObjectInputStream) 738 */ 739 private void writeObject(ObjectOutputStream s) 740 throws IOException 741 { 742 s.defaultWriteObject(); 743 744 AWTEventMulticaster.save(s, actionListenerK, actionListener); 745 s.writeObject(null); 746 } 747 748 /** 749 * Reads the {@code ObjectInputStream} and if it 750 * isn't {@code null} adds a listener to receive 751 * action events fired by the {@code Menu} Item. 752 * Unrecognized keys or values will be ignored. 753 * 754 * @param s the {@code ObjectInputStream} to read 755 * @exception HeadlessException if 756 * {@code GraphicsEnvironment.isHeadless} returns 757 * {@code true} 758 * @see #removeActionListener(ActionListener) 759 * @see #addActionListener(ActionListener) 760 * @see #writeObject(ObjectOutputStream) 761 */ 762 private void readObject(ObjectInputStream s) 763 throws ClassNotFoundException, IOException, HeadlessException 764 { 765 // HeadlessException will be thrown from MenuComponent's readObject 766 s.defaultReadObject(); 767 768 Object keyOrNull; 769 while(null != (keyOrNull = s.readObject())) { 770 String key = ((String)keyOrNull).intern(); 771 772 if (actionListenerK == key) 773 addActionListener((ActionListener)(s.readObject())); 774 775 else // skip value for unrecognized key 776 s.readObject(); 777 } 778 } 779 780 /** 781 * Initialize JNI field and method IDs 782 */ 783 private static native void initIDs(); 784 785 786 ///////////////// 787 // Accessibility support 788 //////////////// 789 790 /** 791 * Gets the AccessibleContext associated with this MenuItem. 792 * For menu items, the AccessibleContext takes the form of an 793 * AccessibleAWTMenuItem. 794 * A new AccessibleAWTMenuItem instance is created if necessary. 795 * 796 * @return an AccessibleAWTMenuItem that serves as the 797 * AccessibleContext of this MenuItem 798 * @since 1.3 799 */ 800 public AccessibleContext getAccessibleContext() { 801 if (accessibleContext == null) { 802 accessibleContext = new AccessibleAWTMenuItem(); 803 } 804 return accessibleContext; 805 } 806 807 /** 808 * Inner class of MenuItem used to provide default support for 809 * accessibility. This class is not meant to be used directly by 810 * application developers, but is instead meant only to be 811 * subclassed by menu component developers. 812 * <p> 813 * This class implements accessibility support for the 814 * {@code MenuItem} class. It provides an implementation of the 815 * Java Accessibility API appropriate to menu item user-interface elements. 816 * @since 1.3 817 */ 818 protected class AccessibleAWTMenuItem extends AccessibleAWTMenuComponent 819 implements AccessibleAction, AccessibleValue 820 { 821 /* 822 * JDK 1.3 serialVersionUID 823 */ 824 private static final long serialVersionUID = -217847831945965825L; 825 826 /** 827 * Get the accessible name of this object. 828 * 829 * @return the localized name of the object -- can be null if this 830 * object does not have a name 831 */ 832 public String getAccessibleName() { 833 if (accessibleName != null) { 834 return accessibleName; 835 } else { 836 if (getLabel() == null) { 837 return super.getAccessibleName(); 838 } else { 839 return getLabel(); 840 } 841 } 842 } 843 844 /** 845 * Get the role of this object. 846 * 847 * @return an instance of AccessibleRole describing the role of the 848 * object 849 */ 850 public AccessibleRole getAccessibleRole() { 851 return AccessibleRole.MENU_ITEM; 852 } 853 854 /** 855 * Get the AccessibleAction associated with this object. In the 856 * implementation of the Java Accessibility API for this class, 857 * return this object, which is responsible for implementing the 858 * AccessibleAction interface on behalf of itself. 859 * 860 * @return this object 861 */ 862 public AccessibleAction getAccessibleAction() { 863 return this; 864 } 865 866 /** 867 * Get the AccessibleValue associated with this object. In the 868 * implementation of the Java Accessibility API for this class, 869 * return this object, which is responsible for implementing the 870 * AccessibleValue interface on behalf of itself. 871 * 872 * @return this object 873 */ 874 public AccessibleValue getAccessibleValue() { 875 return this; 876 } 877 878 /** 879 * Returns the number of Actions available in this object. The 880 * default behavior of a menu item is to have one action. 881 * 882 * @return 1, the number of Actions in this object 883 */ 884 public int getAccessibleActionCount() { 885 return 1; 886 } 887 888 /** 889 * Return a description of the specified action of the object. 890 * 891 * @param i zero-based index of the actions 892 */ 893 public String getAccessibleActionDescription(int i) { 894 if (i == 0) { 895 // [[[PENDING: WDW -- need to provide a localized string]]] 896 return "click"; 897 } else { 898 return null; 899 } 900 } 901 902 /** 903 * Perform the specified Action on the object 904 * 905 * @param i zero-based index of actions 906 * @return true if the action was performed; otherwise false. 907 */ 908 public boolean doAccessibleAction(int i) { 909 if (i == 0) { 910 // Simulate a button click 911 Toolkit.getEventQueue().postEvent( 912 new ActionEvent(MenuItem.this, 913 ActionEvent.ACTION_PERFORMED, 914 MenuItem.this.getActionCommand(), 915 EventQueue.getMostRecentEventTime(), 916 0)); 917 return true; 918 } else { 919 return false; 920 } 921 } 922 923 /** 924 * Get the value of this object as a Number. 925 * 926 * @return An Integer of 0 if this isn't selected or an Integer of 1 if 927 * this is selected. 928 * @see javax.swing.AbstractButton#isSelected() 929 */ 930 public Number getCurrentAccessibleValue() { 931 return Integer.valueOf(0); 932 } 933 934 /** 935 * Set the value of this object as a Number. 936 * 937 * @return True if the value was set. 938 */ 939 public boolean setCurrentAccessibleValue(Number n) { 940 return false; 941 } 942 943 /** 944 * Get the minimum value of this object as a Number. 945 * 946 * @return An Integer of 0. 947 */ 948 public Number getMinimumAccessibleValue() { 949 return Integer.valueOf(0); 950 } 951 952 /** 953 * Get the maximum value of this object as a Number. 954 * 955 * @return An Integer of 0. 956 */ 957 public Number getMaximumAccessibleValue() { 958 return Integer.valueOf(0); 959 } 960 961 } // class AccessibleAWTMenuItem 962 963 }