001: /*
002: * @(#)MenuItem.java 1.64 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027: package java.awt;
028:
029: import sun.awt.peer.MenuItemPeer;
030: import sun.awt.PeerBasedToolkit;
031: import java.awt.event.*;
032: import java.io.ObjectOutputStream;
033: import java.io.ObjectInputStream;
034: import java.io.IOException;
035: import java.awt.AWTEventMulticaster;
036: import java.util.EventListener;
037:
038: /**
039: * All items in a menu must belong to the class
040: * <code>MenuItem</code>, or one of its subclasses.
041: * <p>
042: * The default <code>MenuItem</code> object embodies
043: * a simple labeled menu item.
044: * <p>
045: * This picture of a menu bar shows five menu items:
046: * <IMG SRC="images-awt/MenuBar-1.gif"
047: * ALIGN=CENTER HSPACE=10 VSPACE=7>
048: * <br CLEAR=LEFT>
049: * The first two items are simple menu items, labeled
050: * <code>"Basic"</code> and <code>"Simple"</code>.
051: * Following these two items is a separator, which is itself
052: * a menu item, created with the label <code>"-"</code>.
053: * Next is an instance of <code>CheckboxMenuItem</code>
054: * labeled <code>"Check"</code>. The final menu item is a
055: * submenu labeled <code>"More Examples"</code>,
056: * and this submenu is an instance of <code>Menu</code>.
057: * <p>
058: * When a menu item is selected, AWT sends an action event to
059: * the menu item. Since the event is an
060: * instance of <code>ActionEvent</code>, the <code>processEvent</code>
061: * method examines the event and passes it along to
062: * <code>processActionEvent</code>. The latter method redirects the
063: * event to any <code>ActionListener</code> objects that have
064: * registered an interest in action events generated by this
065: * menu item.
066: * <P>
067: * Note that the subclass <code>Menu</code> overrides this behavior and
068: * does not send any event to the frame until one of its subitems is
069: * selected.
070: *
071: * @version 1.50, 08/10/01
072: * @author Sami Shaio
073: */
074: public class MenuItem extends MenuComponent {
075: boolean enabled = true;
076: String label;
077: String actionCommand;
078: // The eventMask is ONLY set by subclasses via enableEvents.
079: // The mask should NOT be set when listeners are registered
080: // so that we can distinguish the difference between when
081: // listeners request events and subclasses request them.
082: long eventMask;
083: transient ActionListener actionListener;
084: private MenuShortcut shortcut = null;
085: private static final String base = "menuitem";
086: private static int nameCounter = 0;
087: /*
088: * JDK 1.1 serialVersionUID
089: */
090: private static final long serialVersionUID = -21757335363267194L;
091:
092: /**
093: * Constructs a new MenuItem with an empty label and no keyboard
094: * shortcut.
095: * @since JDK1.1
096: */
097: public MenuItem() {
098: this ("", null);
099: }
100:
101: /**
102: * Constructs a new MenuItem with the specified label
103: * and no keyboard shortcut. Note that use of "-" in
104: * a label is reserved to indicate a separator between
105: * menu items. By default, all menu items except for
106: * separators are enabled.
107: * @param label the label for this menu item.
108: * @since JDK1.0
109: */
110: public MenuItem(String label) {
111: this (label, null);
112: }
113:
114: /**
115: * Create a menu item with an associated keyboard shortcut.
116: * Note that use of "-" in a label is reserved to indicate
117: * a separator between menu items. By default, all menu
118: * items except for separators are enabled.
119: * @param label the label for this menu item.
120: * @param s the instance of <code>MenuShortcut</code>
121: * associated with this menu item.
122: * @since JDK1.1
123: */
124: public MenuItem(String label, MenuShortcut s) {
125: this .label = label;
126: this .shortcut = s;
127: }
128:
129: /**
130: * Construct a name for this MenuComponent. Called by getName() when
131: * the name is null.
132: */
133: String constructComponentName() {
134: return base + nameCounter++;
135: }
136:
137: /**
138: * Creates the menu item's peer. The peer allows us to modify the
139: * appearance of the menu item without changing its functionality.
140: */
141: public void addNotify() {
142: synchronized (getTreeLock()) {
143: if (peer == null) {
144: peer = ((PeerBasedToolkit) Toolkit.getDefaultToolkit())
145: .createMenuItem(this );
146: }
147: }
148: }
149:
150: /**
151: * Gets the label for this menu item.
152: * @return the label of this menu item, or <code>null</code>
153: if this menu item has no label.
154: * @see java.awt.MenuItem#setLabel
155: * @since JDK1.0
156: */
157: public String getLabel() {
158: return label;
159: }
160:
161: /**
162: * Sets the label for this menu item to the specified label.
163: * @param label the new label, or <code>null</code> for no label.
164: * @see java.awt.MenuItem#getLabel
165: * @since JDK1.0
166: */
167: public synchronized void setLabel(String label) {
168: this .label = label;
169: MenuItemPeer peer = (MenuItemPeer) this .peer;
170: if (peer != null) {
171: peer.setLabel(label);
172: }
173: }
174:
175: /**
176: * Checks whether this menu item is enabled.
177: * @see java.awt.MenuItem#setEnabled
178: * @since JDK1.0
179: */
180: public boolean isEnabled() {
181: return enabled;
182: }
183:
184: /**
185: * Sets whether or not this menu item can be chosen.
186: * @param b if <code>true</code>, enables this menu item;
187: * if <code>false</code>, disables it.
188: * @see java.awt.MenuItem#isEnabled
189: * @since JDK1.1
190: */
191: public synchronized void setEnabled(boolean b) {
192: enable(b);
193: }
194:
195: /**
196: * @deprecated As of JDK version 1.1,
197: * replaced by <code>setEnabled(boolean)</code>.
198: */
199: public synchronized void enable() {
200: enabled = true;
201: MenuItemPeer peer = (MenuItemPeer) this .peer;
202: if (peer != null) {
203: peer.setEnabled(true);
204: }
205: }
206:
207: /**
208: * @deprecated As of JDK version 1.1,
209: * replaced by <code>setEnabled(boolean)</code>.
210: */
211: public void enable(boolean b) {
212: if (b) {
213: enable();
214: } else {
215: disable();
216: }
217: }
218:
219: /**
220: * @deprecated As of JDK version 1.1,
221: * replaced by <code>setEnabled(boolean)</code>.
222: */
223: public synchronized void disable() {
224: enabled = false;
225: MenuItemPeer peer = (MenuItemPeer) this .peer;
226: if (peer != null) {
227: peer.setEnabled(false);
228: }
229: }
230:
231: /**
232: * Get the <code>MenuShortcut</code> object associated with this
233: * menu item,
234: * @return the menu shortcut associated with this menu item,
235: * or <code>null</code> if none has been specified.
236: * @see java.awt.MenuItem#setShortcut
237: * @since JDK1.1
238: */
239: public MenuShortcut getShortcut() {
240: return shortcut;
241: }
242:
243: /**
244: * Set the <code>MenuShortcut</code> object associated with this
245: * menu item. If a menu shortcut is already associated with
246: * this menu item, it is replaced.
247: * @param s the menu shortcut to associate
248: * with this menu item.
249: * @see java.awt.MenuItem#getShortcut
250: * @since JDK1.1
251: */
252: public void setShortcut(MenuShortcut s) {
253: shortcut = s;
254: MenuItemPeer peer = (MenuItemPeer) this .peer;
255: if (peer != null) {
256: peer.setLabel(label);
257: }
258: }
259:
260: /**
261: * Delete any <code>MenuShortcut</code> object associated
262: * with this menu item.
263: * @since JDK1.1
264: */
265: public void deleteShortcut() {
266: shortcut = null;
267: MenuItemPeer peer = (MenuItemPeer) this .peer;
268: if (peer != null) {
269: peer.setLabel(label);
270: }
271: }
272:
273: /*
274: * Delete a matching MenuShortcut associated with this MenuItem.
275: * Used when iterating Menus.
276: */
277: void deleteShortcut(MenuShortcut s) {
278: if (s.equals(shortcut)) {
279: shortcut = null;
280: MenuItemPeer peer = (MenuItemPeer) this .peer;
281: if (peer != null) {
282: peer.setLabel(label);
283: }
284: }
285: }
286:
287: /*
288: * The main goal of this method is to post an appropriate event
289: * to the event queue when menu shortcut is pressed. However,
290: * in subclasses this method may do more than just posting
291: * an event.
292: */
293: void doMenuEvent() {
294: Toolkit.getEventQueue().postEvent(
295: new ActionEvent(this , ActionEvent.ACTION_PERFORMED,
296: getActionCommand()));
297: }
298:
299: /*
300: * Post an ActionEvent to the target (on
301: * keydown). Returns true if there is an associated
302: * shortcut.
303: */
304: boolean handleShortcut(KeyEvent e) {
305: MenuShortcut s = new MenuShortcut(e.getKeyCode(), (e
306: .getModifiers() & InputEvent.SHIFT_MASK) > 0);
307: if (s.equals(shortcut) && enabled) {
308: // MenuShortcut match -- issue an event on keydown.
309: if (e.getID() == KeyEvent.KEY_PRESSED) {
310: doMenuEvent();
311: } else {// silently eat key release.
312: }
313: return true;
314: }
315: return false;
316: }
317:
318: MenuItem getShortcutMenuItem(MenuShortcut s) {
319: return (s.equals(shortcut)) ? this : null;
320: }
321:
322: /**
323: * Enables event delivery to this menu item for events
324: * to be defined by the specified event mask parameter
325: * <p>
326: * Since event types are automatically enabled when a listener for
327: * that type is added to the menu item, this method only needs
328: * to be invoked by subclasses of <code>MenuItem</code> which desire to
329: * have the specified event types delivered to <code>processEvent</code>
330: * regardless of whether a listener is registered.
331: * @param eventsToEnable the event mask defining the event types.
332: * @see java.awt.MenuItem#processEvent
333: * @see java.awt.MenuItem#disableEvents
334: * @see java.awt.Component#enableEvents
335: * @since JDK1.1
336: */
337: protected final void enableEvents(long eventsToEnable) {
338: eventMask |= eventsToEnable;
339: newEventsOnly = true;
340: }
341:
342: /**
343: * Disables event delivery to this menu item for events
344: * defined by the specified event mask parameter.
345: * @param eventsToDisable the event mask defining the event types.
346: * @see java.awt.MenuItem#processEvent
347: * @see java.awt.MenuItem#enableEvents
348: * @see java.awt.Component#disableEvents
349: * @since JDK1.1
350: */
351: protected final void disableEvents(long eventsToDisable) {
352: eventMask &= ~eventsToDisable;
353: }
354:
355: /**
356: * Sets the command name of the action event that is fired
357: * by this menu item.
358: * <p>
359: * By default, the action command is set to the label of
360: * the menu item.
361: * @param command the action command to be set
362: * for this menu item.
363: * @see java.awt.MenuItem#getActionCommand
364: * @since JDK1.1
365: */
366: public void setActionCommand(String command) {
367: actionCommand = command;
368: }
369:
370: /**
371: * Gets the command name of the action event that is fired
372: * by this menu item.
373: * @see java.awt.MenuItem#setActionCommand
374: * @since JDK1.1
375: */
376: public String getActionCommand() {
377: return (actionCommand == null ? label : actionCommand);
378: }
379:
380: /**
381: * Adds the specified action listener to receive action events
382: * from this menu item.
383: * @param l the action listener.
384: * @see java.awt.event.ActionEvent
385: * @see java.awt.event.ActionListener
386: * @see java.awt.MenuItem#removeActionListener
387: * @since JDK1.1
388: */
389: public synchronized void addActionListener(ActionListener l) {
390: actionListener = AWTEventMulticaster.add(actionListener, l);
391: newEventsOnly = true;
392: }
393:
394: /**
395: * Removes the specified action listener so it no longer receives
396: * action events from this menu item.
397: * @param l the action listener.
398: * @see java.awt.event.ActionEvent
399: * @see java.awt.event.ActionListener
400: * @see java.awt.MenuItem#addActionListener
401: * @since JDK1.1
402: */
403: public synchronized void removeActionListener(ActionListener l) {
404: actionListener = AWTEventMulticaster.remove(actionListener, l);
405: }
406:
407: /**
408: * Returns an array of all the action listeners
409: * registered on this menu item.
410: *
411: * @return all of this menu item's <code>ActionListener</code>s
412: * or an empty array if no action
413: * listeners are currently registered
414: *
415: * @see #addActionListener
416: * @see #removeActionListener
417: * @see java.awt.event.ActionEvent
418: * @see java.awt.event.ActionListener
419: * @since 1.4
420: */
421: public synchronized ActionListener[] getActionListeners() {
422: return (ActionListener[]) AWTEventMulticaster.getListeners(
423: (EventListener) actionListener, ActionListener.class);
424: }
425:
426: /**
427: * Processes events on this menu item. If the event is an
428: * instance of <code>ActionEvent</code>, it invokes
429: * <code>processActionEvent</code>, another method
430: * defined by <code>MenuItem</code>.
431: * <p>
432: * Currently, menu items only support action events.
433: * @param e the event.
434: * @see java.awt.MenuItem#processActionEvent
435: * @since JDK1.1
436: */
437: protected void processEvent(AWTEvent e) {
438: if (e instanceof ActionEvent) {
439: processActionEvent((ActionEvent) e);
440: }
441: }
442:
443: // NOTE: remove when filtering is done at lower level
444: boolean eventEnabled(AWTEvent e) {
445: if (e.id == ActionEvent.ACTION_PERFORMED) {
446: if ((eventMask & AWTEvent.ACTION_EVENT_MASK) != 0
447: || actionListener != null) {
448: return true;
449: }
450: return false;
451: }
452: return super .eventEnabled(e);
453: }
454:
455: /**
456: * Processes action events occurring on this menu item,
457: * by dispatching them to any registered
458: * <code>ActionListener</code> objects.
459: * This method is not called unless action events are
460: * enabled for this component. Action events are enabled
461: * when one of the following occurs:
462: * <p><ul>
463: * <li>An <code>ActionListener</code> object is registered
464: * via <code>addActionListener</code>.
465: * <li>Action events are enabled via <code>enableEvents</code>.
466: * </ul>
467: * @param e the action event.
468: * @see java.awt.event.ActionEvent
469: * @see java.awt.event.ActionListener
470: * @see java.awt.MenuItem#enableEvents
471: * @since JDK1.1
472: */
473: protected void processActionEvent(ActionEvent e) {
474: if (actionListener != null) {
475: actionListener.actionPerformed(e);
476: }
477: }
478:
479: /**
480: * Returns the parameter string representing the state of this menu
481: * item. This string is useful for debugging.
482: * @return the parameter string of this menu item.
483: * @since JDK1.0
484: */
485: public String paramString() {
486: String str = ",label=" + label;
487: if (shortcut != null) {
488: str += ",shortcut=" + shortcut;
489: }
490: return super .paramString() + str;
491: }
492:
493: /* Serialization support.
494: */
495:
496: private int menuItemSerializedDataVersion = 1;
497:
498: private void writeObject(ObjectOutputStream s) throws IOException {
499: s.defaultWriteObject();
500: AWTEventMulticaster.save(s, actionListenerK, actionListener);
501: s.writeObject(null);
502: }
503:
504: private void readObject(ObjectInputStream s)
505: throws ClassNotFoundException, IOException {
506: s.defaultReadObject();
507: Object keyOrNull;
508: while (null != (keyOrNull = s.readObject())) {
509: String key = ((String) keyOrNull).intern();
510: if (actionListenerK == key)
511: addActionListener((ActionListener) (s.readObject()));
512: else
513: // skip value for unrecognized key
514: s.readObject();
515: }
516: }
517: }
|