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