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 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;
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 1.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 1.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 = getComponentFactory().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 1.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 1.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 *
268 * @return {@code true} if the item is enabled;
269 * otherwise {@code false}
270 * @see java.awt.MenuItem#setEnabled
271 * @since 1.0
272 */
273 public boolean isEnabled() {
274 return enabled;
275 }
276
277 /**
278 * Sets whether or not this menu item can be chosen.
279 * @param b if <code>true</code>, enables this menu item;
280 * if <code>false</code>, disables it.
281 * @see java.awt.MenuItem#isEnabled
282 * @since 1.1
283 */
284 public synchronized void setEnabled(boolean b) {
285 enable(b);
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 enable() {
294 enabled = true;
295 MenuItemPeer peer = (MenuItemPeer)this.peer;
296 if (peer != null) {
297 peer.setEnabled(true);
298 }
299 }
300
301 /**
302 * Sets whether or not this menu item can be chosen.
303 *
304 * @param b if {@code true}, enables this menu item;
305 * otherwise disables
306 * @deprecated As of JDK version 1.1,
307 * replaced by <code>setEnabled(boolean)</code>.
308 */
309 @Deprecated
310 public void enable(boolean b) {
311 if (b) {
312 enable();
313 } else {
314 disable();
315 }
316 }
317
318 /**
319 * @deprecated As of JDK version 1.1,
320 * replaced by <code>setEnabled(boolean)</code>.
321 */
322 @Deprecated
323 public synchronized void disable() {
324 enabled = false;
325 MenuItemPeer peer = (MenuItemPeer)this.peer;
326 if (peer != null) {
327 peer.setEnabled(false);
328 }
329 }
330
331 /**
332 * Get the <code>MenuShortcut</code> object associated with this
333 * menu item,
334 * @return the menu shortcut associated with this menu item,
335 * or <code>null</code> if none has been specified.
336 * @see java.awt.MenuItem#setShortcut
337 * @since 1.1
338 */
339 public MenuShortcut getShortcut() {
340 return shortcut;
341 }
342
343 /**
344 * Set the <code>MenuShortcut</code> object associated with this
345 * menu item. If a menu shortcut is already associated with
346 * this menu item, it is replaced.
347 * @param s the menu shortcut to associate
348 * with this menu item.
349 * @see java.awt.MenuItem#getShortcut
350 * @since 1.1
351 */
352 public void setShortcut(MenuShortcut s) {
353 shortcut = s;
354 MenuItemPeer peer = (MenuItemPeer)this.peer;
355 if (peer != null) {
356 peer.setLabel(label);
357 }
358 }
359
360 /**
361 * Delete any <code>MenuShortcut</code> object associated
362 * with this menu item.
363 * @since 1.1
364 */
365 public void deleteShortcut() {
366 shortcut = null;
367 MenuItemPeer peer = (MenuItemPeer)this.peer;
368 if (peer != null) {
369 peer.setLabel(label);
370 }
371 }
372
373 /*
374 * Delete a matching MenuShortcut associated with this MenuItem.
375 * Used when iterating Menus.
376 */
377 void deleteShortcut(MenuShortcut s) {
378 if (s.equals(shortcut)) {
379 shortcut = null;
380 MenuItemPeer peer = (MenuItemPeer)this.peer;
381 if (peer != null) {
437 if (e.getID() == KeyEvent.KEY_PRESSED) {
438 doMenuEvent(e.getWhen(), e.getModifiers());
439 } else {
440 // silently eat key release.
441 }
442 return true;
443 }
444 return false;
445 }
446
447 MenuItem getShortcutMenuItem(MenuShortcut s) {
448 return (s.equals(shortcut)) ? this : null;
449 }
450
451 /**
452 * Enables event delivery to this menu item for events
453 * to be defined by the specified event mask parameter
454 * <p>
455 * Since event types are automatically enabled when a listener for
456 * that type is added to the menu item, this method only needs
457 * to be invoked by subclasses of <code>MenuItem</code> which desire to
458 * have the specified event types delivered to <code>processEvent</code>
459 * regardless of whether a listener is registered.
460 *
461 * @param eventsToEnable the event mask defining the event types
462 * @see java.awt.MenuItem#processEvent
463 * @see java.awt.MenuItem#disableEvents
464 * @see java.awt.Component#enableEvents
465 * @since 1.1
466 */
467 protected final void enableEvents(long eventsToEnable) {
468 eventMask |= eventsToEnable;
469 newEventsOnly = true;
470 }
471
472 /**
473 * Disables event delivery to this menu item for events
474 * defined by the specified event mask parameter.
475 *
476 * @param eventsToDisable the event mask defining the event types
477 * @see java.awt.MenuItem#processEvent
478 * @see java.awt.MenuItem#enableEvents
545 * >AWT Threading Issues</a> for details on AWT's threading model.
546 *
547 * @param l the action listener.
548 * @see #addActionListener
549 * @see #getActionListeners
550 * @see java.awt.event.ActionEvent
551 * @see java.awt.event.ActionListener
552 * @since 1.1
553 */
554 public synchronized void removeActionListener(ActionListener l) {
555 if (l == null) {
556 return;
557 }
558 actionListener = AWTEventMulticaster.remove(actionListener, l);
559 }
560
561 /**
562 * Returns an array of all the action listeners
563 * registered on this menu item.
564 *
565 * @return all of this menu item's <code>ActionListener</code>s
566 * or an empty array if no action
567 * listeners are currently registered
568 *
569 * @see #addActionListener
570 * @see #removeActionListener
571 * @see java.awt.event.ActionEvent
572 * @see java.awt.event.ActionListener
573 * @since 1.4
574 */
575 public synchronized ActionListener[] getActionListeners() {
576 return getListeners(ActionListener.class);
577 }
578
579 /**
580 * Returns an array of all the objects currently registered
581 * as <code><em>Foo</em>Listener</code>s
582 * upon this <code>MenuItem</code>.
583 * <code><em>Foo</em>Listener</code>s are registered using the
584 * <code>add<em>Foo</em>Listener</code> method.
585 *
586 * <p>
587 * You can specify the <code>listenerType</code> argument
588 * with a class literal, such as
589 * <code><em>Foo</em>Listener.class</code>.
590 * For example, you can query a
591 * <code>MenuItem</code> <code>m</code>
592 * for its action listeners with the following code:
593 *
594 * <pre>ActionListener[] als = (ActionListener[])(m.getListeners(ActionListener.class));</pre>
595 *
596 * If no such listeners exist, this method returns an empty array.
597 *
598 * @param <T> the type of the listeners
599 * @param listenerType the type of listeners requested; this parameter
600 * should specify an interface that descends from
601 * <code>java.util.EventListener</code>
602 * @return an array of all objects registered as
603 * <code><em>Foo</em>Listener</code>s on this menu item,
604 * or an empty array if no such
605 * listeners have been added
606 * @exception ClassCastException if <code>listenerType</code>
607 * doesn't specify a class or interface that implements
608 * <code>java.util.EventListener</code>
609 *
610 * @see #getActionListeners
611 * @since 1.3
612 */
613 public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
614 EventListener l = null;
615 if (listenerType == ActionListener.class) {
616 l = actionListener;
617 }
618 return AWTEventMulticaster.getListeners(l, listenerType);
619 }
620
621 /**
622 * Processes events on this menu item. If the event is an
623 * instance of <code>ActionEvent</code>, it invokes
624 * <code>processActionEvent</code>, another method
625 * defined by <code>MenuItem</code>.
626 * <p>
627 * Currently, menu items only support action events.
628 * <p>Note that if the event parameter is <code>null</code>
629 * the behavior is unspecified and may result in an
630 * exception.
631 *
632 * @param e the event
633 * @see java.awt.MenuItem#processActionEvent
634 * @since 1.1
635 */
636 protected void processEvent(AWTEvent e) {
637 if (e instanceof ActionEvent) {
638 processActionEvent((ActionEvent)e);
639 }
640 }
641
642 // REMIND: remove when filtering is done at lower level
643 boolean eventEnabled(AWTEvent e) {
644 if (e.id == ActionEvent.ACTION_PERFORMED) {
645 if ((eventMask & AWTEvent.ACTION_EVENT_MASK) != 0 ||
646 actionListener != null) {
647 return true;
648 }
649 return false;
650 }
651 return super.eventEnabled(e);
652 }
653
654 /**
655 * Processes action events occurring on this menu item,
656 * by dispatching them to any registered
657 * <code>ActionListener</code> objects.
658 * This method is not called unless action events are
659 * enabled for this component. Action events are enabled
660 * when one of the following occurs:
661 * <ul>
662 * <li>An <code>ActionListener</code> object is registered
663 * via <code>addActionListener</code>.
664 * <li>Action events are enabled via <code>enableEvents</code>.
665 * </ul>
666 * <p>Note that if the event parameter is <code>null</code>
667 * the behavior is unspecified and may result in an
668 * exception.
669 *
670 * @param e the action event
671 * @see java.awt.event.ActionEvent
672 * @see java.awt.event.ActionListener
673 * @see java.awt.MenuItem#enableEvents
674 * @since 1.1
675 */
676 protected void processActionEvent(ActionEvent e) {
677 ActionListener listener = actionListener;
678 if (listener != null) {
679 listener.actionPerformed(e);
680 }
681 }
682
683 /**
684 * Returns a string representing the state of this <code>MenuItem</code>.
685 * This method is intended to be used only for debugging purposes, and the
686 * content and format of the returned string may vary between
687 * implementations. The returned string may be empty but may not be
688 * <code>null</code>.
689 *
690 * @return the parameter string of this menu item
691 */
692 public String paramString() {
693 String str = ",label=" + label;
694 if (shortcut != null) {
695 str += ",shortcut=" + shortcut;
696 }
697 return super.paramString() + str;
698 }
699
700
701 /* Serialization support.
702 */
703
704 /**
705 * Menu item serialized data version.
706 *
707 * @serial
708 */
709 private int menuItemSerializedDataVersion = 1;
710
711 /**
712 * Writes default serializable fields to stream. Writes
713 * a list of serializable <code>ActionListeners</code>
714 * as optional data. The non-serializable listeners are
715 * detected and no attempt is made to serialize them.
716 *
717 * @param s the <code>ObjectOutputStream</code> to write
718 * @serialData <code>null</code> terminated sequence of 0
719 * or more pairs; the pair consists of a <code>String</code>
720 * and an <code>Object</code>; the <code>String</code>
721 * indicates the type of object and is one of the following:
722 * <code>actionListenerK</code> indicating an
723 * <code>ActionListener</code> object
724 *
725 * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
726 * @see #readObject(ObjectInputStream)
727 */
728 private void writeObject(ObjectOutputStream s)
729 throws IOException
730 {
731 s.defaultWriteObject();
732
733 AWTEventMulticaster.save(s, actionListenerK, actionListener);
734 s.writeObject(null);
735 }
736
737 /**
738 * Reads the <code>ObjectInputStream</code> and if it
739 * isn't <code>null</code> adds a listener to receive
740 * action events fired by the <code>Menu</code> Item.
741 * Unrecognized keys or values will be ignored.
742 *
743 * @param s the <code>ObjectInputStream</code> to read
744 * @exception HeadlessException if
745 * <code>GraphicsEnvironment.isHeadless</code> returns
746 * <code>true</code>
747 * @see #removeActionListener(ActionListener)
748 * @see #addActionListener(ActionListener)
749 * @see #writeObject(ObjectOutputStream)
750 */
751 private void readObject(ObjectInputStream s)
752 throws ClassNotFoundException, IOException, HeadlessException
753 {
754 // HeadlessException will be thrown from MenuComponent's readObject
755 s.defaultReadObject();
756
757 Object keyOrNull;
758 while(null != (keyOrNull = s.readObject())) {
759 String key = ((String)keyOrNull).intern();
760
761 if (actionListenerK == key)
762 addActionListener((ActionListener)(s.readObject()));
763
764 else // skip value for unrecognized key
765 s.readObject();
766 }
783 * A new AccessibleAWTMenuItem instance is created if necessary.
784 *
785 * @return an AccessibleAWTMenuItem that serves as the
786 * AccessibleContext of this MenuItem
787 * @since 1.3
788 */
789 public AccessibleContext getAccessibleContext() {
790 if (accessibleContext == null) {
791 accessibleContext = new AccessibleAWTMenuItem();
792 }
793 return accessibleContext;
794 }
795
796 /**
797 * Inner class of MenuItem used to provide default support for
798 * accessibility. This class is not meant to be used directly by
799 * application developers, but is instead meant only to be
800 * subclassed by menu component developers.
801 * <p>
802 * This class implements accessibility support for the
803 * <code>MenuItem</code> class. It provides an implementation of the
804 * Java Accessibility API appropriate to menu item user-interface elements.
805 * @since 1.3
806 */
807 protected class AccessibleAWTMenuItem extends AccessibleAWTMenuComponent
808 implements AccessibleAction, AccessibleValue
809 {
810 /*
811 * JDK 1.3 serialVersionUID
812 */
813 private static final long serialVersionUID = -217847831945965825L;
814
815 /**
816 * Get the accessible name of this object.
817 *
818 * @return the localized name of the object -- can be null if this
819 * object does not have a name
820 */
821 public String getAccessibleName() {
822 if (accessibleName != null) {
823 return accessibleName;
|
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}, or one of its subclasses.
39 * <p>
40 * The default {@code MenuItem} 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"} and {@code "Simple"}.
49 * Following these two items is a separator, which is itself
50 * a menu item, created with the label {@code "-"}.
51 * Next is an instance of {@code CheckboxMenuItem}
52 * labeled {@code "Check"}. The final menu item is a
53 * submenu labeled <code>"More Examples"</code>,
54 * and this submenu is an instance of {@code Menu}.
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}, the {@code processEvent}
59 * method examines the event and passes it along to
60 * {@code processActionEvent}. The latter method redirects the
61 * event to any {@code ActionListener} 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} 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} will
107 * be set to true. Else {@code enabled} 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} 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}
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;
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 1.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}
208 * associated with this menu item.
209 * @exception HeadlessException if GraphicsEnvironment.isHeadless()
210 * returns true.
211 * @see java.awt.GraphicsEnvironment#isHeadless
212 * @since 1.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 = getComponentFactory().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}
243 if this menu item has no label.
244 * @see java.awt.MenuItem#setLabel
245 * @since 1.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} for no label.
254 * @see java.awt.MenuItem#getLabel
255 * @since 1.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 *
268 * @return {@code true} if the item is enabled;
269 * otherwise {@code false}
270 * @see java.awt.MenuItem#setEnabled
271 * @since 1.0
272 */
273 public boolean isEnabled() {
274 return enabled;
275 }
276
277 /**
278 * Sets whether or not this menu item can be chosen.
279 * @param b if {@code true}, enables this menu item;
280 * if {@code false}, disables it.
281 * @see java.awt.MenuItem#isEnabled
282 * @since 1.1
283 */
284 public synchronized void setEnabled(boolean b) {
285 enable(b);
286 }
287
288 /**
289 * @deprecated As of JDK version 1.1,
290 * replaced by {@code setEnabled(boolean)}.
291 */
292 @Deprecated
293 public synchronized void enable() {
294 enabled = true;
295 MenuItemPeer peer = (MenuItemPeer)this.peer;
296 if (peer != null) {
297 peer.setEnabled(true);
298 }
299 }
300
301 /**
302 * Sets whether or not this menu item can be chosen.
303 *
304 * @param b if {@code true}, enables this menu item;
305 * otherwise disables
306 * @deprecated As of JDK version 1.1,
307 * replaced by {@code setEnabled(boolean)}.
308 */
309 @Deprecated
310 public void enable(boolean b) {
311 if (b) {
312 enable();
313 } else {
314 disable();
315 }
316 }
317
318 /**
319 * @deprecated As of JDK version 1.1,
320 * replaced by {@code setEnabled(boolean)}.
321 */
322 @Deprecated
323 public synchronized void disable() {
324 enabled = false;
325 MenuItemPeer peer = (MenuItemPeer)this.peer;
326 if (peer != null) {
327 peer.setEnabled(false);
328 }
329 }
330
331 /**
332 * Get the {@code MenuShortcut} object associated with this
333 * menu item,
334 * @return the menu shortcut associated with this menu item,
335 * or {@code null} if none has been specified.
336 * @see java.awt.MenuItem#setShortcut
337 * @since 1.1
338 */
339 public MenuShortcut getShortcut() {
340 return shortcut;
341 }
342
343 /**
344 * Set the {@code MenuShortcut} object associated with this
345 * menu item. If a menu shortcut is already associated with
346 * this menu item, it is replaced.
347 * @param s the menu shortcut to associate
348 * with this menu item.
349 * @see java.awt.MenuItem#getShortcut
350 * @since 1.1
351 */
352 public void setShortcut(MenuShortcut s) {
353 shortcut = s;
354 MenuItemPeer peer = (MenuItemPeer)this.peer;
355 if (peer != null) {
356 peer.setLabel(label);
357 }
358 }
359
360 /**
361 * Delete any {@code MenuShortcut} object associated
362 * with this menu item.
363 * @since 1.1
364 */
365 public void deleteShortcut() {
366 shortcut = null;
367 MenuItemPeer peer = (MenuItemPeer)this.peer;
368 if (peer != null) {
369 peer.setLabel(label);
370 }
371 }
372
373 /*
374 * Delete a matching MenuShortcut associated with this MenuItem.
375 * Used when iterating Menus.
376 */
377 void deleteShortcut(MenuShortcut s) {
378 if (s.equals(shortcut)) {
379 shortcut = null;
380 MenuItemPeer peer = (MenuItemPeer)this.peer;
381 if (peer != null) {
437 if (e.getID() == KeyEvent.KEY_PRESSED) {
438 doMenuEvent(e.getWhen(), e.getModifiers());
439 } else {
440 // silently eat key release.
441 }
442 return true;
443 }
444 return false;
445 }
446
447 MenuItem getShortcutMenuItem(MenuShortcut s) {
448 return (s.equals(shortcut)) ? this : null;
449 }
450
451 /**
452 * Enables event delivery to this menu item for events
453 * to be defined by the specified event mask parameter
454 * <p>
455 * Since event types are automatically enabled when a listener for
456 * that type is added to the menu item, this method only needs
457 * to be invoked by subclasses of {@code MenuItem} which desire to
458 * have the specified event types delivered to {@code processEvent}
459 * regardless of whether a listener is registered.
460 *
461 * @param eventsToEnable the event mask defining the event types
462 * @see java.awt.MenuItem#processEvent
463 * @see java.awt.MenuItem#disableEvents
464 * @see java.awt.Component#enableEvents
465 * @since 1.1
466 */
467 protected final void enableEvents(long eventsToEnable) {
468 eventMask |= eventsToEnable;
469 newEventsOnly = true;
470 }
471
472 /**
473 * Disables event delivery to this menu item for events
474 * defined by the specified event mask parameter.
475 *
476 * @param eventsToDisable the event mask defining the event types
477 * @see java.awt.MenuItem#processEvent
478 * @see java.awt.MenuItem#enableEvents
545 * >AWT Threading Issues</a> for details on AWT's threading model.
546 *
547 * @param l the action listener.
548 * @see #addActionListener
549 * @see #getActionListeners
550 * @see java.awt.event.ActionEvent
551 * @see java.awt.event.ActionListener
552 * @since 1.1
553 */
554 public synchronized void removeActionListener(ActionListener l) {
555 if (l == null) {
556 return;
557 }
558 actionListener = AWTEventMulticaster.remove(actionListener, l);
559 }
560
561 /**
562 * Returns an array of all the action listeners
563 * registered on this menu item.
564 *
565 * @return all of this menu item's {@code ActionListener}s
566 * or an empty array if no action
567 * listeners are currently registered
568 *
569 * @see #addActionListener
570 * @see #removeActionListener
571 * @see java.awt.event.ActionEvent
572 * @see java.awt.event.ActionListener
573 * @since 1.4
574 */
575 public synchronized ActionListener[] getActionListeners() {
576 return getListeners(ActionListener.class);
577 }
578
579 /**
580 * Returns an array of all the objects currently registered
581 * as <code><em>Foo</em>Listener</code>s
582 * upon this {@code MenuItem}.
583 * <code><em>Foo</em>Listener</code>s are registered using the
584 * <code>add<em>Foo</em>Listener</code> method.
585 *
586 * <p>
587 * You can specify the {@code listenerType} argument
588 * with a class literal, such as
589 * <code><em>Foo</em>Listener.class</code>.
590 * For example, you can query a
591 * {@code MenuItem m}
592 * for its action listeners with the following code:
593 *
594 * <pre>ActionListener[] als = (ActionListener[])(m.getListeners(ActionListener.class));</pre>
595 *
596 * If no such listeners exist, this method returns an empty array.
597 *
598 * @param <T> the type of the listeners
599 * @param listenerType the type of listeners requested; this parameter
600 * should specify an interface that descends from
601 * {@code java.util.EventListener}
602 * @return an array of all objects registered as
603 * <code><em>Foo</em>Listener</code>s on this menu item,
604 * or an empty array if no such
605 * listeners have been added
606 * @exception ClassCastException if {@code listenerType}
607 * doesn't specify a class or interface that implements
608 * {@code java.util.EventListener}
609 *
610 * @see #getActionListeners
611 * @since 1.3
612 */
613 public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
614 EventListener l = null;
615 if (listenerType == ActionListener.class) {
616 l = actionListener;
617 }
618 return AWTEventMulticaster.getListeners(l, listenerType);
619 }
620
621 /**
622 * Processes events on this menu item. If the event is an
623 * instance of {@code ActionEvent}, it invokes
624 * {@code processActionEvent}, another method
625 * defined by {@code MenuItem}.
626 * <p>
627 * Currently, menu items only support action events.
628 * <p>Note that if the event parameter is {@code null}
629 * the behavior is unspecified and may result in an
630 * exception.
631 *
632 * @param e the event
633 * @see java.awt.MenuItem#processActionEvent
634 * @since 1.1
635 */
636 protected void processEvent(AWTEvent e) {
637 if (e instanceof ActionEvent) {
638 processActionEvent((ActionEvent)e);
639 }
640 }
641
642 // REMIND: remove when filtering is done at lower level
643 boolean eventEnabled(AWTEvent e) {
644 if (e.id == ActionEvent.ACTION_PERFORMED) {
645 if ((eventMask & AWTEvent.ACTION_EVENT_MASK) != 0 ||
646 actionListener != null) {
647 return true;
648 }
649 return false;
650 }
651 return super.eventEnabled(e);
652 }
653
654 /**
655 * Processes action events occurring on this menu item,
656 * by dispatching them to any registered
657 * {@code ActionListener} objects.
658 * This method is not called unless action events are
659 * enabled for this component. Action events are enabled
660 * when one of the following occurs:
661 * <ul>
662 * <li>An {@code ActionListener} object is registered
663 * via {@code addActionListener}.
664 * <li>Action events are enabled via {@code enableEvents}.
665 * </ul>
666 * <p>Note that if the event parameter is {@code null}
667 * the behavior is unspecified and may result in an
668 * exception.
669 *
670 * @param e the action event
671 * @see java.awt.event.ActionEvent
672 * @see java.awt.event.ActionListener
673 * @see java.awt.MenuItem#enableEvents
674 * @since 1.1
675 */
676 protected void processActionEvent(ActionEvent e) {
677 ActionListener listener = actionListener;
678 if (listener != null) {
679 listener.actionPerformed(e);
680 }
681 }
682
683 /**
684 * Returns a string representing the state of this {@code MenuItem}.
685 * This method is intended to be used only for debugging purposes, and the
686 * content and format of the returned string may vary between
687 * implementations. The returned string may be empty but may not be
688 * {@code null}.
689 *
690 * @return the parameter string of this menu item
691 */
692 public String paramString() {
693 String str = ",label=" + label;
694 if (shortcut != null) {
695 str += ",shortcut=" + shortcut;
696 }
697 return super.paramString() + str;
698 }
699
700
701 /* Serialization support.
702 */
703
704 /**
705 * Menu item serialized data version.
706 *
707 * @serial
708 */
709 private int menuItemSerializedDataVersion = 1;
710
711 /**
712 * Writes default serializable fields to stream. Writes
713 * a list of serializable {@code ActionListeners}
714 * as optional data. The non-serializable listeners are
715 * detected and no attempt is made to serialize them.
716 *
717 * @param s the {@code ObjectOutputStream} to write
718 * @serialData {@code null} terminated sequence of 0
719 * or more pairs; the pair consists of a {@code String}
720 * and an {@code Object}; the {@code String}
721 * indicates the type of object and is one of the following:
722 * {@code actionListenerK} indicating an
723 * {@code ActionListener} object
724 *
725 * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
726 * @see #readObject(ObjectInputStream)
727 */
728 private void writeObject(ObjectOutputStream s)
729 throws IOException
730 {
731 s.defaultWriteObject();
732
733 AWTEventMulticaster.save(s, actionListenerK, actionListener);
734 s.writeObject(null);
735 }
736
737 /**
738 * Reads the {@code ObjectInputStream} and if it
739 * isn't {@code null} adds a listener to receive
740 * action events fired by the {@code Menu} Item.
741 * Unrecognized keys or values will be ignored.
742 *
743 * @param s the {@code ObjectInputStream} to read
744 * @exception HeadlessException if
745 * {@code GraphicsEnvironment.isHeadless} returns
746 * {@code true}
747 * @see #removeActionListener(ActionListener)
748 * @see #addActionListener(ActionListener)
749 * @see #writeObject(ObjectOutputStream)
750 */
751 private void readObject(ObjectInputStream s)
752 throws ClassNotFoundException, IOException, HeadlessException
753 {
754 // HeadlessException will be thrown from MenuComponent's readObject
755 s.defaultReadObject();
756
757 Object keyOrNull;
758 while(null != (keyOrNull = s.readObject())) {
759 String key = ((String)keyOrNull).intern();
760
761 if (actionListenerK == key)
762 addActionListener((ActionListener)(s.readObject()));
763
764 else // skip value for unrecognized key
765 s.readObject();
766 }
783 * A new AccessibleAWTMenuItem instance is created if necessary.
784 *
785 * @return an AccessibleAWTMenuItem that serves as the
786 * AccessibleContext of this MenuItem
787 * @since 1.3
788 */
789 public AccessibleContext getAccessibleContext() {
790 if (accessibleContext == null) {
791 accessibleContext = new AccessibleAWTMenuItem();
792 }
793 return accessibleContext;
794 }
795
796 /**
797 * Inner class of MenuItem used to provide default support for
798 * accessibility. This class is not meant to be used directly by
799 * application developers, but is instead meant only to be
800 * subclassed by menu component developers.
801 * <p>
802 * This class implements accessibility support for the
803 * {@code MenuItem} class. It provides an implementation of the
804 * Java Accessibility API appropriate to menu item user-interface elements.
805 * @since 1.3
806 */
807 protected class AccessibleAWTMenuItem extends AccessibleAWTMenuComponent
808 implements AccessibleAction, AccessibleValue
809 {
810 /*
811 * JDK 1.3 serialVersionUID
812 */
813 private static final long serialVersionUID = -217847831945965825L;
814
815 /**
816 * Get the accessible name of this object.
817 *
818 * @return the localized name of the object -- can be null if this
819 * object does not have a name
820 */
821 public String getAccessibleName() {
822 if (accessibleName != null) {
823 return accessibleName;
|