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 boolean handleShortcut(KeyEvent e) { 439 MenuShortcut s = new MenuShortcut(e.getKeyCode(), 440 (e.getModifiers() & InputEvent.SHIFT_MASK) > 0); 441 MenuShortcut sE = new MenuShortcut(e.getExtendedKeyCode(), 442 (e.getModifiers() & InputEvent.SHIFT_MASK) > 0); 443 // Fix For 6185151: Menu shortcuts of all menuitems within a menu 444 // should be disabled when the menu itself is disabled 445 if ((s.equals(shortcut) || sE.equals(shortcut)) && isItemEnabled()) { 446 // MenuShortcut match -- issue an event on keydown. 447 if (e.getID() == KeyEvent.KEY_PRESSED) { 448 doMenuEvent(e.getWhen(), e.getModifiers()); 449 } else { 450 // silently eat key release. 451 } 452 return true; 453 } 454 return false; 455 } 456 457 MenuItem getShortcutMenuItem(MenuShortcut s) { 458 return (s.equals(shortcut)) ? this : null; 459 } 460 461 /** 462 * Enables event delivery to this menu item for events 463 * to be defined by the specified event mask parameter 464 * <p> 465 * Since event types are automatically enabled when a listener for 466 * that type is added to the menu item, this method only needs 467 * to be invoked by subclasses of {@code MenuItem} which desire to 468 * have the specified event types delivered to {@code processEvent} 469 * regardless of whether a listener is registered. 470 * 471 * @param eventsToEnable the event mask defining the event types 472 * @see java.awt.MenuItem#processEvent 473 * @see java.awt.MenuItem#disableEvents 474 * @see java.awt.Component#enableEvents 475 * @since 1.1 476 */ 477 protected final void enableEvents(long eventsToEnable) { 478 eventMask |= eventsToEnable; 479 newEventsOnly = true; 480 } 481 482 /** 483 * Disables event delivery to this menu item for events 484 * defined by the specified event mask parameter. 485 * 486 * @param eventsToDisable the event mask defining the event types 487 * @see java.awt.MenuItem#processEvent 488 * @see java.awt.MenuItem#enableEvents 489 * @see java.awt.Component#disableEvents 490 * @since 1.1 491 */ 492 protected final void disableEvents(long eventsToDisable) { 493 eventMask &= ~eventsToDisable; 494 } 495 496 /** 497 * Sets the command name of the action event that is fired 498 * by this menu item. 499 * <p> 500 * By default, the action command is set to the label of 501 * the menu item. 502 * @param command the action command to be set 503 * for this menu item. 504 * @see java.awt.MenuItem#getActionCommand 505 * @since 1.1 506 */ 507 public void setActionCommand(String command) { 508 actionCommand = command; 509 } 510 511 /** 512 * Gets the command name of the action event that is fired 513 * by this menu item. 514 * 515 * @return the action command name 516 * @see java.awt.MenuItem#setActionCommand 517 * @since 1.1 518 */ 519 public String getActionCommand() { 520 return getActionCommandImpl(); 521 } 522 523 // This is final so it can be called on the Toolkit thread. 524 final String getActionCommandImpl() { 525 return (actionCommand == null? label : actionCommand); 526 } 527 528 /** 529 * Adds the specified action listener to receive action events 530 * from this menu item. 531 * If l is null, no exception is thrown and no action is performed. 532 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads" 533 * >AWT Threading Issues</a> for details on AWT's threading model. 534 * 535 * @param l the action listener. 536 * @see #removeActionListener 537 * @see #getActionListeners 538 * @see java.awt.event.ActionEvent 539 * @see java.awt.event.ActionListener 540 * @since 1.1 541 */ 542 public synchronized void addActionListener(ActionListener l) { 543 if (l == null) { 544 return; 545 } 546 actionListener = AWTEventMulticaster.add(actionListener, l); 547 newEventsOnly = true; 548 } 549 550 /** 551 * Removes the specified action listener so it no longer receives 552 * action events from this menu item. 553 * If l is null, no exception is thrown and no action is performed. 554 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads" 555 * >AWT Threading Issues</a> for details on AWT's threading model. 556 * 557 * @param l the action listener. 558 * @see #addActionListener 559 * @see #getActionListeners 560 * @see java.awt.event.ActionEvent 561 * @see java.awt.event.ActionListener 562 * @since 1.1 563 */ 564 public synchronized void removeActionListener(ActionListener l) { 565 if (l == null) { 566 return; 567 } 568 actionListener = AWTEventMulticaster.remove(actionListener, l); 569 } 570 571 /** 572 * Returns an array of all the action listeners 573 * registered on this menu item. 574 * 575 * @return all of this menu item's {@code ActionListener}s 576 * or an empty array if no action 577 * listeners are currently registered 578 * 579 * @see #addActionListener 580 * @see #removeActionListener 581 * @see java.awt.event.ActionEvent 582 * @see java.awt.event.ActionListener 583 * @since 1.4 584 */ 585 public synchronized ActionListener[] getActionListeners() { 586 return getListeners(ActionListener.class); 587 } 588 589 /** 590 * Returns an array of all the objects currently registered 591 * as <code><em>Foo</em>Listener</code>s 592 * upon this {@code MenuItem}. 593 * <code><em>Foo</em>Listener</code>s are registered using the 594 * <code>add<em>Foo</em>Listener</code> method. 595 * 596 * <p> 597 * You can specify the {@code listenerType} argument 598 * with a class literal, such as 599 * <code><em>Foo</em>Listener.class</code>. 600 * For example, you can query a 601 * {@code MenuItem m} 602 * for its action listeners with the following code: 603 * 604 * <pre>ActionListener[] als = (ActionListener[])(m.getListeners(ActionListener.class));</pre> 605 * 606 * If no such listeners exist, this method returns an empty array. 607 * 608 * @param <T> the type of the listeners 609 * @param listenerType the type of listeners requested; this parameter 610 * should specify an interface that descends from 611 * {@code java.util.EventListener} 612 * @return an array of all objects registered as 613 * <code><em>Foo</em>Listener</code>s on this menu item, 614 * or an empty array if no such 615 * listeners have been added 616 * @exception ClassCastException if {@code listenerType} 617 * doesn't specify a class or interface that implements 618 * {@code java.util.EventListener} 619 * 620 * @see #getActionListeners 621 * @since 1.3 622 */ 623 public <T extends EventListener> T[] getListeners(Class<T> listenerType) { 624 EventListener l = null; 625 if (listenerType == ActionListener.class) { 626 l = actionListener; 627 } 628 return AWTEventMulticaster.getListeners(l, listenerType); 629 } 630 631 /** 632 * Processes events on this menu item. If the event is an 633 * instance of {@code ActionEvent}, it invokes 634 * {@code processActionEvent}, another method 635 * defined by {@code MenuItem}. 636 * <p> 637 * Currently, menu items only support action events. 638 * <p>Note that if the event parameter is {@code null} 639 * the behavior is unspecified and may result in an 640 * exception. 641 * 642 * @param e the event 643 * @see java.awt.MenuItem#processActionEvent 644 * @since 1.1 645 */ 646 protected void processEvent(AWTEvent e) { 647 if (e instanceof ActionEvent) { 648 processActionEvent((ActionEvent)e); 649 } 650 } 651 652 // REMIND: remove when filtering is done at lower level 653 boolean eventEnabled(AWTEvent e) { 654 if (e.id == ActionEvent.ACTION_PERFORMED) { 655 if ((eventMask & AWTEvent.ACTION_EVENT_MASK) != 0 || 656 actionListener != null) { 657 return true; 658 } 659 return false; 660 } 661 return super.eventEnabled(e); 662 } 663 664 /** 665 * Processes action events occurring on this menu item, 666 * by dispatching them to any registered 667 * {@code ActionListener} objects. 668 * This method is not called unless action events are 669 * enabled for this component. Action events are enabled 670 * when one of the following occurs: 671 * <ul> 672 * <li>An {@code ActionListener} object is registered 673 * via {@code addActionListener}. 674 * <li>Action events are enabled via {@code enableEvents}. 675 * </ul> 676 * <p>Note that if the event parameter is {@code null} 677 * the behavior is unspecified and may result in an 678 * exception. 679 * 680 * @param e the action event 681 * @see java.awt.event.ActionEvent 682 * @see java.awt.event.ActionListener 683 * @see java.awt.MenuItem#enableEvents 684 * @since 1.1 685 */ 686 protected void processActionEvent(ActionEvent e) { 687 ActionListener listener = actionListener; 688 if (listener != null) { 689 listener.actionPerformed(e); 690 } 691 } 692 693 /** 694 * Returns a string representing the state of this {@code MenuItem}. 695 * This method is intended to be used only for debugging purposes, and the 696 * content and format of the returned string may vary between 697 * implementations. The returned string may be empty but may not be 698 * {@code null}. 699 * 700 * @return the parameter string of this menu item 701 */ 702 public String paramString() { 703 String str = ",label=" + label; 704 if (shortcut != null) { 705 str += ",shortcut=" + shortcut; 706 } 707 return super.paramString() + str; 708 } 709 710 711 /* Serialization support. 712 */ 713 714 /** 715 * Menu item serialized data version. 716 * 717 * @serial 718 */ 719 private int menuItemSerializedDataVersion = 1; 720 721 /** 722 * Writes default serializable fields to stream. Writes 723 * a list of serializable {@code ActionListeners} 724 * as optional data. The non-serializable listeners are 725 * detected and no attempt is made to serialize them. 726 * 727 * @param s the {@code ObjectOutputStream} to write 728 * @serialData {@code null} terminated sequence of 0 729 * or more pairs; the pair consists of a {@code String} 730 * and an {@code Object}; the {@code String} 731 * indicates the type of object and is one of the following: 732 * {@code actionListenerK} indicating an 733 * {@code ActionListener} object 734 * 735 * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener) 736 * @see #readObject(ObjectInputStream) 737 */ 738 private void writeObject(ObjectOutputStream s) 739 throws IOException 740 { 741 s.defaultWriteObject(); 742 743 AWTEventMulticaster.save(s, actionListenerK, actionListener); 744 s.writeObject(null); 745 } 746 747 /** 748 * Reads the {@code ObjectInputStream} and if it 749 * isn't {@code null} adds a listener to receive 750 * action events fired by the {@code Menu} Item. 751 * Unrecognized keys or values will be ignored. 752 * 753 * @param s the {@code ObjectInputStream} to read 754 * @exception HeadlessException if 755 * {@code GraphicsEnvironment.isHeadless} returns 756 * {@code true} 757 * @see #removeActionListener(ActionListener) 758 * @see #addActionListener(ActionListener) 759 * @see #writeObject(ObjectOutputStream) 760 */ 761 private void readObject(ObjectInputStream s) 762 throws ClassNotFoundException, IOException, HeadlessException 763 { 764 // HeadlessException will be thrown from MenuComponent's readObject 765 s.defaultReadObject(); 766 767 Object keyOrNull; 768 while(null != (keyOrNull = s.readObject())) { 769 String key = ((String)keyOrNull).intern(); 770 771 if (actionListenerK == key) 772 addActionListener((ActionListener)(s.readObject())); 773 774 else // skip value for unrecognized key 775 s.readObject(); 776 } 777 } 778 779 /** 780 * Initialize JNI field and method IDs 781 */ 782 private static native void initIDs(); 783 784 785 ///////////////// 786 // Accessibility support 787 //////////////// 788 789 /** 790 * Gets the AccessibleContext associated with this MenuItem. 791 * For menu items, the AccessibleContext takes the form of an 792 * AccessibleAWTMenuItem. 793 * A new AccessibleAWTMenuItem instance is created if necessary. 794 * 795 * @return an AccessibleAWTMenuItem that serves as the 796 * AccessibleContext of this MenuItem 797 * @since 1.3 798 */ 799 public AccessibleContext getAccessibleContext() { 800 if (accessibleContext == null) { 801 accessibleContext = new AccessibleAWTMenuItem(); 802 } 803 return accessibleContext; 804 } 805 806 /** 807 * Inner class of MenuItem used to provide default support for 808 * accessibility. This class is not meant to be used directly by 809 * application developers, but is instead meant only to be 810 * subclassed by menu component developers. 811 * <p> 812 * This class implements accessibility support for the 813 * {@code MenuItem} class. It provides an implementation of the 814 * Java Accessibility API appropriate to menu item user-interface elements. 815 * @since 1.3 816 */ 817 protected class AccessibleAWTMenuItem extends AccessibleAWTMenuComponent 818 implements AccessibleAction, AccessibleValue 819 { 820 /* 821 * JDK 1.3 serialVersionUID 822 */ 823 private static final long serialVersionUID = -217847831945965825L; 824 825 /** 826 * Get the accessible name of this object. 827 * 828 * @return the localized name of the object -- can be null if this 829 * object does not have a name 830 */ 831 public String getAccessibleName() { 832 if (accessibleName != null) { 833 return accessibleName; 834 } else { 835 if (getLabel() == null) { 836 return super.getAccessibleName(); 837 } else { 838 return getLabel(); 839 } 840 } 841 } 842 843 /** 844 * Get the role of this object. 845 * 846 * @return an instance of AccessibleRole describing the role of the 847 * object 848 */ 849 public AccessibleRole getAccessibleRole() { 850 return AccessibleRole.MENU_ITEM; 851 } 852 853 /** 854 * Get the AccessibleAction associated with this object. In the 855 * implementation of the Java Accessibility API for this class, 856 * return this object, which is responsible for implementing the 857 * AccessibleAction interface on behalf of itself. 858 * 859 * @return this object 860 */ 861 public AccessibleAction getAccessibleAction() { 862 return this; 863 } 864 865 /** 866 * Get the AccessibleValue associated with this object. In the 867 * implementation of the Java Accessibility API for this class, 868 * return this object, which is responsible for implementing the 869 * AccessibleValue interface on behalf of itself. 870 * 871 * @return this object 872 */ 873 public AccessibleValue getAccessibleValue() { 874 return this; 875 } 876 877 /** 878 * Returns the number of Actions available in this object. The 879 * default behavior of a menu item is to have one action. 880 * 881 * @return 1, the number of Actions in this object 882 */ 883 public int getAccessibleActionCount() { 884 return 1; 885 } 886 887 /** 888 * Return a description of the specified action of the object. 889 * 890 * @param i zero-based index of the actions 891 */ 892 public String getAccessibleActionDescription(int i) { 893 if (i == 0) { 894 // [[[PENDING: WDW -- need to provide a localized string]]] 895 return "click"; 896 } else { 897 return null; 898 } 899 } 900 901 /** 902 * Perform the specified Action on the object 903 * 904 * @param i zero-based index of actions 905 * @return true if the action was performed; otherwise false. 906 */ 907 public boolean doAccessibleAction(int i) { 908 if (i == 0) { 909 // Simulate a button click 910 Toolkit.getEventQueue().postEvent( 911 new ActionEvent(MenuItem.this, 912 ActionEvent.ACTION_PERFORMED, 913 MenuItem.this.getActionCommand(), 914 EventQueue.getMostRecentEventTime(), 915 0)); 916 return true; 917 } else { 918 return false; 919 } 920 } 921 922 /** 923 * Get the value of this object as a Number. 924 * 925 * @return An Integer of 0 if this isn't selected or an Integer of 1 if 926 * this is selected. 927 * @see javax.swing.AbstractButton#isSelected() 928 */ 929 public Number getCurrentAccessibleValue() { 930 return Integer.valueOf(0); 931 } 932 933 /** 934 * Set the value of this object as a Number. 935 * 936 * @return True if the value was set. 937 */ 938 public boolean setCurrentAccessibleValue(Number n) { 939 return false; 940 } 941 942 /** 943 * Get the minimum value of this object as a Number. 944 * 945 * @return An Integer of 0. 946 */ 947 public Number getMinimumAccessibleValue() { 948 return Integer.valueOf(0); 949 } 950 951 /** 952 * Get the maximum value of this object as a Number. 953 * 954 * @return An Integer of 0. 955 */ 956 public Number getMaximumAccessibleValue() { 957 return Integer.valueOf(0); 958 } 959 960 } // class AccessibleAWTMenuItem 961 962 }