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