001: /*
002: * @(#)Menu.java 1.59 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 java.util.Vector;
030: import java.util.Enumeration;
031: import sun.awt.peer.MenuPeer;
032: import sun.awt.PeerBasedToolkit;
033: import java.awt.event.KeyEvent;
034:
035: /**
036: * A <code>Menu</code> object is a pull-down menu component
037: * that is deployed from a menu bar.
038: * <p>
039: * A menu can optionally be a <i>tear-off</i> menu. A tear-off menu
040: * can be opened and dragged away from its parent menu bar or menu.
041: * It remains on the screen after the mouse button has been released.
042: * The mechanism for tearing off a menu is platform dependent, since
043: * the look and feel of the tear-off menu is determined by its peer.
044: * On platforms that do not support tear-off menus, the tear-off
045: * property is ignored.
046: * <p>
047: * Each item in a menu must belong to the <code>MenuItem</code>
048: * class. It can be an instance of <code>MenuItem</code>, a submenu
049: * (an instance of <code>Menu</code>), or a check box (an instance of
050: * <code>CheckboxMenuItem</code>).
051: *
052: * @version 1.55, 08/19/02
053: * @author Sami Shaio
054: * @see java.awt.MenuItem
055: * @see java.awt.MenuBar
056: * @see java.awt.MenuShortcut
057: * @see java.awt.CheckboxMenuItem
058: * @see java.awt.Frame
059: * @since JDK1.0
060: */
061: public class Menu extends MenuItem implements MenuContainer {
062: /**
063: * A vector of the items that will be part of the Menu.
064: *
065: * @serial
066: * @see countItems()
067: */
068: Vector items = new Vector();
069: /**
070: * This field indicates whether the menu has the
071: * tear of property or not. It will be set to
072: * <code>true</code> if the menu has the tear off
073: * property and it will be set to <code>false></code>
074: * if it does not.
075: * A torn off menu can be deleted by a user when
076: * it is no longer needed.
077: *
078: * @serial
079: * @see isTearOff()
080: */
081: boolean tearOff;
082: /**
083: * This field will be set to <code>true</code>
084: * if the Menu in question is actually a help
085: * menu. Otherwise it will be set to <code>
086: * false</code>.
087: *
088: * @serial
089: */
090: boolean isHelpMenu;
091: private static final String base = "menu";
092: private static int nameCounter = 0;
093: /*
094: * JDK 1.1 serialVersionUID
095: */
096: private static final long serialVersionUID = -8809584163345499784L;
097:
098: /**
099: * Constructs a new menu with an empty label. This menu is not
100: * a tear-off menu.
101: * @since JDK1.1
102: */
103: public Menu() {
104: this ("", false);
105: }
106:
107: /**
108: * Constructs a new menu with the specified label. This menu is not
109: * a tear-off menu.
110: * @param label the menu's label in the menu bar, or in
111: * another menu of which this menu is a submenu.
112: */
113: public Menu(String label) {
114: this (label, false);
115: }
116:
117: /**
118: * Constructs a new menu with the specified label,
119: * indicating whether the menu can be torn off.
120: * <p>
121: * Tear-off functionality may not be supported by all
122: * implementations of AWT. If a particular implementation doesn't
123: * support tear-off menus, this value is silently ignored.
124: * @param label the menu's label in the menu bar, or in
125: * another menu of which this menu is a submenu.
126: * @param tearOff if <code>true</code>, the menu
127: * is a tear-off menu.
128: * @since JDK1.0.
129: */
130: public Menu(String label, boolean tearOff) {
131: super (label);
132: checkPopup();
133: this .tearOff = tearOff;
134: }
135:
136: /**
137: * Construct a name for this MenuComponent. Called by getName() when
138: * the name is null.
139: */
140: String constructComponentName() {
141: return base + nameCounter++;
142: }
143:
144: private void checkPopup() {
145: }
146:
147: private void checkNonCascading(MenuItem mi) {
148: }
149:
150: /**
151: * Creates the menu's peer. The peer allows us to modify the
152: * appearance of the menu without changing its functionality.
153: */
154: public void addNotify() {
155: synchronized (getTreeLock()) {
156: if (peer == null) {
157: peer = ((PeerBasedToolkit) Toolkit.getDefaultToolkit())
158: .createMenu(this );
159: }
160: int nitems = getItemCount();
161: for (int i = 0; i < nitems; i++) {
162: MenuItem mi = getItem(i);
163: mi.parent = this ;
164: mi.addNotify();
165: }
166: }
167: }
168:
169: /**
170: * Removes the menu's peer. The peer allows us to modify the appearance
171: * of the menu without changing its functionality.
172: */
173: public void removeNotify() {
174: synchronized (getTreeLock()) {
175: int nitems = getItemCount();
176: for (int i = 0; i < nitems; i++) {
177: getItem(i).removeNotify();
178: }
179: super .removeNotify();
180: }
181: }
182:
183: /**
184: * Indicates whether this menu is a tear-off menu.
185: * <p>
186: * Tear-off functionality may not be supported by all
187: * implementations of AWT. If a particular implementation doesn't
188: * support tear-off menus, this value is silently ignored.
189: * @return <code>true</code> if this is a tear-off menu;
190: * <code>false</code> otherwise.
191: */
192: public boolean isTearOff() {
193: return tearOff;
194: }
195:
196: /**
197: * Get the number of items in this menu.
198: * @return the number of items in this menu.
199: * @since JDK1.1
200: */
201: public int getItemCount() {
202: return countItems();
203: }
204:
205: /**
206: * @deprecated As of JDK version 1.1,
207: * replaced by <code>getItemCount()</code>.
208: */
209: public int countItems() {
210: return items.size();
211: }
212:
213: /**
214: * Gets the item located at the specified index of this menu.
215: * @param index the position of the item to be returned.
216: * @return the item located at the specified index.
217: */
218: public MenuItem getItem(int index) {
219: return (MenuItem) items.elementAt(index);
220: }
221:
222: /**
223: * Adds the specified menu item to this menu. If the
224: * menu item has been part of another menu, remove it
225: * from that menu.
226: * @param mi the menu item to be added.
227: * @return the menu item added.
228: * @see java.awt.Menu#insert(java.lang.String, int)
229: * @see java.awt.Menu#insert(java.awt.MenuItem, int)
230: */
231: public MenuItem add(MenuItem mi) {
232: checkNonCascading(mi);
233: synchronized (getTreeLock()) {
234: if (mi.parent != null) {
235: mi.parent.remove(mi);
236: }
237: items.addElement(mi);
238: mi.parent = this ;
239: MenuPeer peer = (MenuPeer) this .peer;
240: if (peer != null) {
241: mi.addNotify();
242: peer.addItem(mi);
243: }
244: return mi;
245: }
246: }
247:
248: /**
249: * Adds an item with the specified label to this menu.
250: * @param label the text on the item.
251: * @see java.awt.Menu#insert(java.lang.String, int)
252: * @see java.awt.Menu#insert(java.awt.MenuItem, int)
253: */
254: public void add(String label) {
255: add(new MenuItem(label));
256: }
257:
258: /**
259: * Inserts a menu item into this menu
260: * at the specified position.
261: * @param menuitem the menu item to be inserted.
262: * @param index the position at which the menu
263: * item should be inserted.
264: * @see java.awt.Menu#add(java.lang.String)
265: * @see java.awt.Menu#add(java.awt.MenuItem)
266: * @exception IllegalArgumentException if the value of
267: * <code>index</code> is less than zero.
268: * @since JDK1.1
269: */
270:
271: public void insert(MenuItem menuitem, int index) {
272: synchronized (getTreeLock()) {
273: if (index < 0) {
274: throw new IllegalArgumentException(
275: "index less than zero.");
276: }
277: int nitems = getItemCount();
278: Vector tempItems = new Vector();
279: /* Remove the item at index, nitems-index times
280: storing them in a temporary vector in the
281: order they appear on the menu.
282: */
283: for (int i = index; i < nitems; i++) {
284: tempItems.addElement(getItem(index));
285: remove(index);
286: }
287: add(menuitem);
288: /* Add the removed items back to the menu, they are
289: already in the correct order in the temp vector.
290: */
291: for (int i = 0; i < tempItems.size(); i++) {
292: add((MenuItem) tempItems.elementAt(i));
293: }
294: }
295: }
296:
297: /**
298: * Inserts a menu item with the specified label into this menu
299: * at the specified position.
300: * @param label the text on the item.
301: * @param index the position at which the menu item
302: * should be inserted.
303: * @see java.awt.Menu#add(java.lang.String)
304: * @see java.awt.Menu#add(java.awt.MenuItem)
305: * @since JDK1.1
306: */
307:
308: public void insert(String label, int index) {
309: insert(new MenuItem(label), index);
310: }
311:
312: /**
313: * Adds a separator line, or a hypen, to the menu at the current position.
314: * @see java.awt.Menu#insertSeparator(int)
315: */
316: public void addSeparator() {
317: add("-");
318: }
319:
320: /**
321: * Inserts a separator at the specified position.
322: * @param index the position at which the
323: * menu separator should be inserted.
324: * @exception IllegalArgumentException if the value of
325: * <code>index</code> is less than 0.
326: * @see java.awt.Menu#addSeparator
327: * @since JDK1.1
328: */
329:
330: public void insertSeparator(int index) {
331: synchronized (getTreeLock()) {
332: if (index < 0) {
333: throw new IllegalArgumentException(
334: "index less than zero.");
335: }
336: int nitems = getItemCount();
337: Vector tempItems = new Vector();
338: /* Remove the item at index, nitems-index times
339: storing them in a temporary vector in the
340: order they appear on the menu.
341: */
342: for (int i = index; i < nitems; i++) {
343: tempItems.addElement(getItem(index));
344: remove(index);
345: }
346: addSeparator();
347: /* Add the removed items back to the menu, they are
348: already in the correct order in the temp vector.
349: */
350: for (int i = 0; i < tempItems.size(); i++) {
351: add((MenuItem) tempItems.elementAt(i));
352: }
353: }
354: }
355:
356: /**
357: * Removes the menu item at the specified index from this menu.
358: * @param index the position of the item to be removed.
359: */
360: public void remove(int index) {
361: synchronized (getTreeLock()) {
362: MenuItem mi = getItem(index);
363: items.removeElementAt(index);
364: MenuPeer peer = (MenuPeer) this .peer;
365: if (peer != null) {
366: mi.removeNotify();
367: mi.parent = null;
368: peer.delItem(index);
369: }
370: }
371: }
372:
373: /**
374: * Removes the specified menu item from this menu.
375: * @param item the item to be removed from the menu.
376: * If <code>item</code> is <code>null</code>
377: * or is not in this menu, this method does
378: * nothing.
379: */
380: public void remove(MenuComponent item) {
381: synchronized (getTreeLock()) {
382: int index = items.indexOf(item);
383: if (index >= 0) {
384: remove(index);
385: }
386: }
387: }
388:
389: /**
390: * Removes all items from this menu.
391: * @since JDK1.0.
392: */
393: public void removeAll() {
394: synchronized (getTreeLock()) {
395: int nitems = getItemCount();
396: for (int i = 0; i < nitems; i++) {
397: remove(0);
398: }
399: }
400: }
401:
402: /*
403: * Post an ActionEvent to the target of the MenuPeer
404: * associated with the specified keyboard event (on
405: * keydown). Returns true if there is an associated
406: * keyboard event.
407: */
408: boolean handleShortcut(KeyEvent e) {
409: int nitems = getItemCount();
410: for (int i = 0; i < nitems; i++) {
411: MenuItem mi = getItem(i);
412: if (mi.handleShortcut(e)) {
413: return true;
414: }
415: }
416: return false;
417: }
418:
419: MenuItem getShortcutMenuItem(MenuShortcut s) {
420: int nitems = getItemCount();
421: for (int i = 0; i < nitems; i++) {
422: MenuItem mi = getItem(i).getShortcutMenuItem(s);
423: if (mi != null) {
424: return mi;
425: }
426: }
427: return null;
428: }
429:
430: synchronized Enumeration shortcuts() {
431: Vector shortcuts = new Vector();
432: int nitems = getItemCount();
433: for (int i = 0; i < nitems; i++) {
434: MenuItem mi = getItem(i);
435: if (mi instanceof Menu) {
436: Enumeration e = ((Menu) mi).shortcuts();
437: while (e.hasMoreElements()) {
438: shortcuts.addElement(e.nextElement());
439: }
440: } else {
441: MenuShortcut ms = mi.getShortcut();
442: if (ms != null) {
443: shortcuts.addElement(ms);
444: }
445: }
446: }
447: return shortcuts.elements();
448: }
449:
450: void deleteShortcut(MenuShortcut s) {
451: int nitems = getItemCount();
452: for (int i = 0; i < nitems; i++) {
453: getItem(i).deleteShortcut(s);
454: }
455: }
456:
457: /* Serialization support. A MenuContainer is responsible for
458: * restoring the parent fields of its children.
459: */
460:
461: private int menuSerializedDataVersion = 1;
462:
463: private void writeObject(java.io.ObjectOutputStream s)
464: throws java.lang.ClassNotFoundException,
465: java.io.IOException {
466: s.defaultWriteObject();
467: }
468:
469: private void readObject(java.io.ObjectInputStream s)
470: throws java.lang.ClassNotFoundException,
471: java.io.IOException {
472: checkPopup();
473: s.defaultReadObject();
474: for (int i = 0; i < items.size(); i++) {
475: MenuItem item = (MenuItem) items.elementAt(i);
476: checkNonCascading(item);
477: item.parent = this ;
478: }
479: }
480:
481: /**
482: * Gets the parameter string representing the state of this menu.
483: * This string is useful for debugging.
484: * @since JDK1.0nu.
485: */
486: public String paramString() {
487: String str = ",tearOff=" + tearOff + ",isHelpMenu="
488: + isHelpMenu;
489: return super.paramString() + str;
490: }
491: }
|