KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > widgets > Menu


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.swt.widgets;
12
13  
14 import org.eclipse.swt.internal.*;
15 import org.eclipse.swt.internal.win32.*;
16 import org.eclipse.swt.*;
17 import org.eclipse.swt.graphics.*;
18 import org.eclipse.swt.events.*;
19
20 /**
21  * Instances of this class are user interface objects that contain
22  * menu items.
23  * <dl>
24  * <dt><b>Styles:</b></dt>
25  * <dd>BAR, DROP_DOWN, POP_UP, NO_RADIO_GROUP</dd>
26  * <dd>LEFT_TO_RIGHT, RIGHT_TO_LEFT</dd>
27  * <dt><b>Events:</b></dt>
28  * <dd>Help, Hide, Show </dd>
29  * </dl>
30  * <p>
31  * Note: Only one of BAR, DROP_DOWN and POP_UP may be specified.
32  * Only one of LEFT_TO_RIGHT or RIGHT_TO_LEFT may be specified.
33  * </p><p>
34  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
35  * </p>
36  */

37
38 public class Menu extends Widget {
39     /**
40      * the handle to the OS resource
41      * (Warning: This field is platform dependent)
42      * <p>
43      * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
44      * public API. It is marked public only so that it can be shared
45      * within the packages provided by SWT. It is not available on all
46      * platforms and should never be accessed from application code.
47      * </p>
48      */

49     public int handle;
50     
51     int x, y, hBrush, hwndCB, id0, id1;
52     int foreground = -1, background = -1;
53     Image backgroundImage;
54     boolean hasLocation;
55     MenuItem cascade;
56     Decorations parent;
57     ImageList imageList;
58     
59     /* Resource ID for SHMENUBARINFO */
60     static final int ID_PPC = 100;
61     
62     /* SmartPhone SoftKeyBar resource ids */
63     static final int ID_SPMM = 102;
64     static final int ID_SPBM = 103;
65     static final int ID_SPMB = 104;
66     static final int ID_SPBB = 105;
67     static final int ID_SPSOFTKEY0 = 106;
68     static final int ID_SPSOFTKEY1 = 107;
69
70 /**
71  * Constructs a new instance of this class given its parent,
72  * and sets the style for the instance so that the instance
73  * will be a popup menu on the given parent's shell.
74  *
75  * @param parent a control which will be the parent of the new instance (cannot be null)
76  *
77  * @exception IllegalArgumentException <ul>
78  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
79  * </ul>
80  * @exception SWTException <ul>
81  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
82  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
83  * </ul>
84  *
85  * @see SWT#POP_UP
86  * @see Widget#checkSubclass
87  * @see Widget#getStyle
88  */

89 public Menu (Control parent) {
90     this (checkNull (parent).menuShell (), SWT.POP_UP);
91 }
92
93 /**
94  * Constructs a new instance of this class given its parent
95  * (which must be a <code>Decorations</code>) and a style value
96  * describing its behavior and appearance.
97  * <p>
98  * The style value is either one of the style constants defined in
99  * class <code>SWT</code> which is applicable to instances of this
100  * class, or must be built by <em>bitwise OR</em>'ing together
101  * (that is, using the <code>int</code> "|" operator) two or more
102  * of those <code>SWT</code> style constants. The class description
103  * lists the style constants that are applicable to the class.
104  * Style bits are also inherited from superclasses.
105  * </p>
106  *
107  * @param parent a decorations control which will be the parent of the new instance (cannot be null)
108  * @param style the style of menu to construct
109  *
110  * @exception IllegalArgumentException <ul>
111  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
112  * </ul>
113  * @exception SWTException <ul>
114  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
115  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
116  * </ul>
117  *
118  * @see SWT#BAR
119  * @see SWT#DROP_DOWN
120  * @see SWT#POP_UP
121  * @see Widget#checkSubclass
122  * @see Widget#getStyle
123  */

124 public Menu (Decorations parent, int style) {
125     this (parent, checkStyle (style), 0);
126 }
127
128 /**
129  * Constructs a new instance of this class given its parent
130  * (which must be a <code>Menu</code>) and sets the style
131  * for the instance so that the instance will be a drop-down
132  * menu on the given parent's parent.
133  *
134  * @param parentMenu a menu which will be the parent of the new instance (cannot be null)
135  *
136  * @exception IllegalArgumentException <ul>
137  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
138  * </ul>
139  * @exception SWTException <ul>
140  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
141  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
142  * </ul>
143  *
144  * @see SWT#DROP_DOWN
145  * @see Widget#checkSubclass
146  * @see Widget#getStyle
147  */

148 public Menu (Menu parentMenu) {
149     this (checkNull (parentMenu).parent, SWT.DROP_DOWN);
150 }
151
152 /**
153  * Constructs a new instance of this class given its parent
154  * (which must be a <code>MenuItem</code>) and sets the style
155  * for the instance so that the instance will be a drop-down
156  * menu on the given parent's parent menu.
157  *
158  * @param parentItem a menu item which will be the parent of the new instance (cannot be null)
159  *
160  * @exception IllegalArgumentException <ul>
161  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
162  * </ul>
163  * @exception SWTException <ul>
164  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
165  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
166  * </ul>
167  *
168  * @see SWT#DROP_DOWN
169  * @see Widget#checkSubclass
170  * @see Widget#getStyle
171  */

172 public Menu (MenuItem parentItem) {
173     this (checkNull (parentItem).parent);
174 }
175
176 Menu (Decorations parent, int style, int handle) {
177     super (parent, checkStyle (style));
178     this.parent = parent;
179     this.handle = handle;
180     /*
181     * Bug in IBM JVM 1.3.1. For some reason, when the checkOrientation() is
182     * called from createWidget(), the JVM issues this error:
183     *
184     * JVM Exception 0x2 (subcode 0x0) occurred in thread "main" (TID:0x9F19D8)
185     *
186     * In addition, on Windows XP, a dialog appears with following error message,
187     * indicating that the problem may be in the JIT:
188     *
189     * AppName: java.exe AppVer: 0.0.0.0 ModName: jitc.dll
190     * ModVer: 0.0.0.0 Offset: 000b6912
191     *
192     * The fix is to call checkOrientation() from here.
193     */

194     checkOrientation (parent);
195     createWidget ();
196 }
197
198 void _setVisible (boolean visible) {
199     if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return;
200     int hwndParent = parent.handle;
201     if (visible) {
202         int flags = OS.TPM_LEFTBUTTON;
203         if (OS.GetKeyState (OS.VK_LBUTTON) >= 0) flags |= OS.TPM_RIGHTBUTTON;
204         if ((style & SWT.RIGHT_TO_LEFT) != 0) flags |= OS.TPM_RIGHTALIGN;
205         if ((parent.style & SWT.MIRRORED) != 0) {
206             flags &= ~OS.TPM_RIGHTALIGN;
207             if ((style & SWT.LEFT_TO_RIGHT) != 0) flags |= OS.TPM_RIGHTALIGN;
208         }
209         int nX = x, nY = y;
210         if (!hasLocation) {
211             int pos = OS.GetMessagePos ();
212             nX = (short) (pos & 0xFFFF);
213             nY = (short) (pos >> 16);
214         }
215         /*
216         * Feature in Windows. It is legal use TrackPopupMenu()
217         * to display an empty menu as long as menu items are added
218         * inside of WM_INITPOPUPMENU. If no items are added, then
219         * TrackPopupMenu() fails and does not send an indication
220         * that the menu has been closed. This is not strictly a
221         * bug but leads to unwanted behavior when application code
222         * assumes that every WM_INITPOPUPMENU will eventually result
223         * in a WM_MENUSELECT, wParam=0xFFFF0000, lParam=0 to indicate
224         * that the menu has been closed. The fix is to detect the
225         * case when TrackPopupMenu() fails and the number of items in
226         * the menu is zero and issue a fake WM_MENUSELECT.
227         */

228         boolean success = OS.TrackPopupMenu (handle, flags, nX, nY, 0, hwndParent, null);
229         if (!success && GetMenuItemCount (handle) == 0) {
230             OS.SendMessage (hwndParent, OS.WM_MENUSELECT, 0xFFFF0000, 0);
231         }
232     } else {
233         OS.SendMessage (hwndParent, OS.WM_CANCELMODE, 0, 0);
234     }
235 }
236
237 /**
238  * Adds the listener to the collection of listeners who will
239  * be notified when help events are generated for the control,
240  * by sending it one of the messages defined in the
241  * <code>HelpListener</code> interface.
242  *
243  * @param listener the listener which should be notified
244  *
245  * @exception IllegalArgumentException <ul>
246  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
247  * </ul>
248  * @exception SWTException <ul>
249  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
250  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
251  * </ul>
252  *
253  * @see HelpListener
254  * @see #removeHelpListener
255  */

256 public void addHelpListener (HelpListener listener) {
257     checkWidget ();
258     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
259     TypedListener typedListener = new TypedListener (listener);
260     addListener (SWT.Help, typedListener);
261 }
262
263 /**
264  * Adds the listener to the collection of listeners who will
265  * be notified when menus are hidden or shown, by sending it
266  * one of the messages defined in the <code>MenuListener</code>
267  * interface.
268  *
269  * @param listener the listener which should be notified
270  *
271  * @exception IllegalArgumentException <ul>
272  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
273  * </ul>
274  * @exception SWTException <ul>
275  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
276  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
277  * </ul>
278  *
279  * @see MenuListener
280  * @see #removeMenuListener
281  */

282 public void addMenuListener (MenuListener listener) {
283     checkWidget ();
284     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
285     TypedListener typedListener = new TypedListener (listener);
286     addListener (SWT.Hide,typedListener);
287     addListener (SWT.Show,typedListener);
288 }
289
290 static Control checkNull (Control control) {
291     if (control == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
292     return control;
293 }
294
295 static Menu checkNull (Menu menu) {
296     if (menu == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
297     return menu;
298 }
299
300 static MenuItem checkNull (MenuItem item) {
301     if (item == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
302     return item;
303 }
304
305 static int checkStyle (int style) {
306     return checkBits (style, SWT.POP_UP, SWT.BAR, SWT.DROP_DOWN, 0, 0, 0);
307 }
308
309 void createHandle () {
310     if (handle != 0) return;
311     if ((style & SWT.BAR) != 0) {
312         if (OS.IsPPC) {
313             int hwndShell = parent.handle;
314             SHMENUBARINFO mbi = new SHMENUBARINFO ();
315             mbi.cbSize = SHMENUBARINFO.sizeof;
316             mbi.hwndParent = hwndShell;
317             mbi.dwFlags = OS.SHCMBF_HIDDEN;
318             mbi.nToolBarId = ID_PPC;
319             mbi.hInstRes = OS.GetLibraryHandle ();
320             boolean success = OS.SHCreateMenuBar (mbi);
321             hwndCB = mbi.hwndMB;
322             if (!success) error (SWT.ERROR_NO_HANDLES);
323             /* Remove the item from the resource file */
324             OS.SendMessage (hwndCB, OS.TB_DELETEBUTTON, 0, 0);
325             return;
326         }
327         /*
328         * Note in WinCE SmartPhone. The SoftBar contains only 2 items.
329         * An item can either be a menu or a button.
330         * SWT.BAR: creates a SoftBar with 2 menus
331         * SWT.BAR | SWT.BUTTON1: creates a SoftBar with 1 button
332         * for button1, and a menu for button2
333         * SWT.BAR | SWT.BUTTON1 | SWT.BUTTON2: creates a SoftBar with
334         * 2 buttons
335         */

336         if (OS.IsSP) {
337             /* Determine type of menubar */
338             int nToolBarId;
339             if ((style & SWT.BUTTON1) != 0) {
340                 nToolBarId = ((style & SWT.BUTTON2) != 0) ? ID_SPBB : ID_SPBM;
341             } else {
342                 nToolBarId = ((style & SWT.BUTTON2) != 0) ? ID_SPMB : ID_SPMM;
343             }
344             
345             /* Create SHMENUBAR */
346             SHMENUBARINFO mbi = new SHMENUBARINFO ();
347             mbi.cbSize = SHMENUBARINFO.sizeof;
348             mbi.hwndParent = parent.handle;
349             mbi.dwFlags = OS.SHCMBF_HIDDEN;
350             mbi.nToolBarId = nToolBarId; /* as defined in .rc file */
351             mbi.hInstRes = OS.GetLibraryHandle ();
352             if (!OS.SHCreateMenuBar (mbi)) error (SWT.ERROR_NO_HANDLES);
353             hwndCB = mbi.hwndMB;
354             
355             /*
356             * Feature on WinCE SmartPhone. The SHCMBF_HIDDEN flag causes the
357             * SHMENUBAR to not be drawn. However the keyboard events still go
358             * through it. The workaround is to also hide the SHMENUBAR with
359             * ShowWindow ().
360             */

361             OS.ShowWindow (hwndCB, OS.SW_HIDE);
362             
363             TBBUTTONINFO info = new TBBUTTONINFO ();
364             info.cbSize = TBBUTTONINFO.sizeof;
365             info.dwMask = OS.TBIF_COMMAND;
366             MenuItem item;
367             
368             /* Set first item */
369             if (nToolBarId == ID_SPMM || nToolBarId == ID_SPMB) {
370                 int hMenu = OS.SendMessage (hwndCB, OS.SHCMBM_GETSUBMENU, 0, ID_SPSOFTKEY0);
371                 /* Remove the item from the resource file */
372                 OS.RemoveMenu (hMenu, 0, OS.MF_BYPOSITION);
373                 Menu menu = new Menu (parent, SWT.DROP_DOWN, hMenu);
374                 item = new MenuItem (this, menu, SWT.CASCADE, 0);
375             } else {
376                 item = new MenuItem (this, null, SWT.PUSH, 0);
377             }
378             info.idCommand = id0 = item.id;
379             OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, ID_SPSOFTKEY0, info);
380
381             /* Set second item */
382             if (nToolBarId == ID_SPMM || nToolBarId == ID_SPBM) {
383                 int hMenu = OS.SendMessage (hwndCB, OS.SHCMBM_GETSUBMENU, 0, ID_SPSOFTKEY1);
384                 OS.RemoveMenu (hMenu, 0, OS.MF_BYPOSITION);
385                 Menu menu = new Menu (parent, SWT.DROP_DOWN, hMenu);
386                 item = new MenuItem (this, menu, SWT.CASCADE, 1);
387             } else {
388                 item = new MenuItem (this, null, SWT.PUSH, 1);
389             }
390             info.idCommand = id1 = item.id;
391             OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, ID_SPSOFTKEY1, info);
392
393             /*
394             * Override the Back key. For some reason, the owner of the menubar
395             * must be a Dialog or it won't receive the WM_HOTKEY message. As
396             * a result, Shell on WinCE SP must use the class Dialog.
397             */

398             int dwMask = OS.SHMBOF_NODEFAULT | OS.SHMBOF_NOTIFY;
399             int lParam = dwMask << 16 | dwMask;
400             OS.SendMessage (hwndCB, OS.SHCMBM_OVERRIDEKEY, OS.VK_ESCAPE, lParam);
401             return;
402         }
403         handle = OS.CreateMenu ();
404         if (handle == 0) error (SWT.ERROR_NO_HANDLES);
405         if (OS.IsHPC) {
406             int hwndShell = parent.handle;
407             hwndCB = OS.CommandBar_Create (OS.GetModuleHandle (null), hwndShell, 1);
408             if (hwndCB == 0) error (SWT.ERROR_NO_HANDLES);
409             OS.CommandBar_Show (hwndCB, false);
410             OS.CommandBar_InsertMenubarEx (hwndCB, 0, handle, 0);
411             /*
412             * The command bar hosts the 'close' button when the window does not
413             * have a caption.
414             */

415             if ((parent.style & SWT.CLOSE) != 0 && (parent.style & SWT.TITLE) == 0) {
416                 OS.CommandBar_AddAdornments (hwndCB, 0, 0);
417             }
418         }
419     } else {
420         handle = OS.CreatePopupMenu ();
421         if (handle == 0) error (SWT.ERROR_NO_HANDLES);
422     }
423 }
424
425 void createItem (MenuItem item, int index) {
426     int count = GetMenuItemCount (handle);
427     if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE);
428     display.addMenuItem (item);
429     boolean success = false;
430     if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
431         if (OS.IsSP) return;
432         TBBUTTON lpButton = new TBBUTTON ();
433         lpButton.idCommand = item.id;
434         lpButton.fsStyle = (byte) OS.TBSTYLE_AUTOSIZE;
435         if ((item.style & SWT.CASCADE) != 0) lpButton.fsStyle |= OS.TBSTYLE_DROPDOWN | 0x80;
436         if ((item.style & SWT.SEPARATOR) != 0) lpButton.fsStyle = (byte) OS.BTNS_SEP;
437         lpButton.fsState = (byte) OS.TBSTATE_ENABLED;
438         lpButton.iBitmap = OS.I_IMAGENONE;
439         success = OS.SendMessage (hwndCB, OS.TB_INSERTBUTTON, index, lpButton) != 0;
440     } else {
441         if (OS.IsWinCE) {
442             int uFlags = OS.MF_BYPOSITION;
443             TCHAR lpNewItem = null;
444             if ((item.style & SWT.SEPARATOR) != 0) {
445                 uFlags |= OS.MF_SEPARATOR;
446             } else {
447                 lpNewItem = new TCHAR (0, " ", true);
448             }
449             success = OS.InsertMenu (handle, index, uFlags, item.id, lpNewItem);
450             if (success) {
451                 MENUITEMINFO info = new MENUITEMINFO ();
452                 info.cbSize = MENUITEMINFO.sizeof;
453                 info.fMask = OS.MIIM_DATA;
454                 info.dwItemData = item.id;
455                 success = OS.SetMenuItemInfo (handle, index, true, info);
456             }
457         } else {
458             /*
459             * Bug in Windows. For some reason, when InsertMenuItem()
460             * is used to insert an item without text, it is not possible
461             * to use SetMenuItemInfo() to set the text at a later time.
462             * The fix is to insert the item with some text.
463             *
464             * Feature in Windows. When an empty string is used instead
465             * of a space and InsertMenuItem() is used to set a submenu
466             * before setting text to a non-empty string, the menu item
467             * becomes unexpectedly disabled. The fix is to insert a
468             * space.
469             */

470             int hHeap = OS.GetProcessHeap ();
471             TCHAR buffer = new TCHAR (0, " ", true);
472             int byteCount = buffer.length () * TCHAR.sizeof;
473             int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
474             OS.MoveMemory (pszText, buffer, byteCount);
475             MENUITEMINFO info = new MENUITEMINFO ();
476             info.cbSize = MENUITEMINFO.sizeof;
477             info.fMask = OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_DATA;
478             info.wID = info.dwItemData = item.id;
479             info.fType = item.widgetStyle ();
480             info.dwTypeData = pszText;
481             success = OS.InsertMenuItem (handle, index, true, info);
482             if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
483         }
484     }
485     if (!success) {
486         display.removeMenuItem (item);
487         error (SWT.ERROR_ITEM_NOT_ADDED);
488     }
489     redraw ();
490 }
491     
492 void createWidget () {
493     /*
494     * Bug in IBM JVM 1.3.1. For some reason, when the following code is called
495     * from this method, the JVM issues this error:
496     *
497     * JVM Exception 0x2 (subcode 0x0) occurred in thread "main" (TID:0x9F19D8)
498     *
499     * In addition, on Windows XP, a dialog appears with following error message,
500     * indicating that the problem may be in the JIT:
501     *
502     * AppName: java.exe AppVer: 0.0.0.0 ModName: jitc.dll
503     * ModVer: 0.0.0.0 Offset: 000b6912
504     *
505     * The fix is to move the code to the caller of this method.
506     */

507 // checkOrientation (parent);
508
createHandle ();
509     parent.addMenu (this);
510 }
511
512 int defaultBackground () {
513     return OS.GetSysColor (OS.COLOR_MENU);
514 }
515
516 int defaultForeground () {
517     return OS.GetSysColor (OS.COLOR_MENUTEXT);
518 }
519
520 void destroyAccelerators () {
521     parent.destroyAccelerators ();
522 }
523
524 void destroyItem (MenuItem item) {
525     if (OS.IsWinCE) {
526         if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
527             if (OS.IsSP) {
528                 redraw();
529                 return;
530             }
531             int index = OS.SendMessage (hwndCB, OS.TB_COMMANDTOINDEX, item.id, 0);
532             if (OS.SendMessage (hwndCB, OS.TB_DELETEBUTTON, index, 0) == 0) {
533                 error (SWT.ERROR_ITEM_NOT_REMOVED);
534             }
535             int count = OS.SendMessage (hwndCB, OS.TB_BUTTONCOUNT, 0, 0);
536             if (count == 0) {
537                 if (imageList != null) {
538                     OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0);
539                     display.releaseImageList (imageList);
540                     imageList = null;
541                 }
542             }
543         } else {
544             int index = 0;
545             MENUITEMINFO info = new MENUITEMINFO ();
546             info.cbSize = MENUITEMINFO.sizeof;
547             info.fMask = OS.MIIM_DATA;
548             while (OS.GetMenuItemInfo (handle, index, true, info)) {
549                 if (info.dwItemData == item.id) break;
550                 index++;
551             }
552             if (info.dwItemData != item.id) {
553                 error (SWT.ERROR_ITEM_NOT_REMOVED);
554             }
555             if (!OS.DeleteMenu (handle, index, OS.MF_BYPOSITION)) {
556                 error (SWT.ERROR_ITEM_NOT_REMOVED);
557             }
558         }
559     } else {
560         if (!OS.DeleteMenu (handle, item.id, OS.MF_BYCOMMAND)) {
561             error (SWT.ERROR_ITEM_NOT_REMOVED);
562         }
563     }
564     redraw ();
565 }
566
567 void destroyWidget () {
568     int hMenu = handle, hCB = hwndCB;
569     releaseHandle ();
570     if (OS.IsWinCE && hCB != 0) {
571         OS.CommandBar_Destroy (hCB);
572     } else {
573         if (hMenu != 0) OS.DestroyMenu (hMenu);
574     }
575 }
576
577 void fixMenus (Decorations newParent) {
578     MenuItem [] items = getItems ();
579     for (int i=0; i<items.length; i++) {
580         items [i].fixMenus (newParent);
581     }
582     parent.removeMenu (this);
583     newParent.addMenu (this);
584     this.parent = newParent;
585 }
586
587 /**
588  * Returns the receiver's background color.
589  *
590  * @return the background color
591  *
592  * @exception SWTException <ul>
593  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
594  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
595  * </ul>
596  *
597  * @since 3.3
598  */

599 /*public*/ Color getBackground () {
600     checkWidget ();
601     return Color.win32_new (display, background != -1 ? background : defaultBackground ());
602 }
603
604 /**
605  * Returns the receiver's background image.
606  *
607  * @return the background image
608  *
609  * @exception SWTException <ul>
610  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
611  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
612  * </ul>
613  *
614  * @since 3.3
615  */

616 /*public*/ Image getBackgroundImage () {
617     checkWidget ();
618     return backgroundImage;
619 }
620
621 /**
622  * Returns a rectangle describing the receiver's size and location
623  * relative to its parent (or its display if its parent is null),
624  * unless the receiver is a menu or a shell. In this case, the
625  * location is relative to the display.
626  * <p>
627  * Note that the bounds of a menu or menu item are undefined when
628  * the menu is not visible. This is because most platforms compute
629  * the bounds of a menu dynamically just before it is displayed.
630  * </p>
631  *
632  * @return the receiver's bounding rectangle
633  *
634  * @exception SWTException <ul>
635  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
636  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
637  * </ul>
638  *
639  * @since 3.1
640  */

641 /*public*/ Rectangle getBounds () {
642     checkWidget ();
643     if (OS.IsWinCE) return new Rectangle (0, 0, 0, 0);
644     if ((style & SWT.BAR) != 0) {
645         if (parent.menuBar != this) {
646             return new Rectangle (0, 0, 0, 0);
647         }
648         int hwndShell = parent.handle;
649         MENUBARINFO info = new MENUBARINFO ();
650         info.cbSize = MENUBARINFO.sizeof;
651         if (OS.GetMenuBarInfo (hwndShell, OS.OBJID_MENU, 0, info)) {
652             int width = info.right - info.left;
653             int height = info.bottom - info.top;
654             return new Rectangle (info.left, info.top, width, height);
655         }
656     } else {
657         int count = GetMenuItemCount (handle);
658         if (count != 0) {
659             RECT rect1 = new RECT ();
660             if (OS.GetMenuItemRect (0, handle, 0, rect1)) {
661                 RECT rect2 = new RECT ();
662                 if (OS.GetMenuItemRect (0, handle, count - 1, rect2)) {
663                     int x = rect1.left - 2, y = rect1.top - 2;
664                     int width = (rect2.right - rect2.left) + 4;
665                     int height = (rect2.bottom - rect1.top) + 4;
666                     return new Rectangle (x, y, width, height);
667                 }
668             }
669         }
670     }
671     return new Rectangle (0, 0, 0, 0);
672 }
673
674 /**
675  * Returns the default menu item or null if none has
676  * been previously set.
677  *
678  * @return the default menu item.
679  *
680  * </ul>
681  * @exception SWTException <ul>
682  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
683  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
684  * </ul>
685  */

686 public MenuItem getDefaultItem () {
687     checkWidget ();
688     if (OS.IsWinCE) return null;
689     int id = OS.GetMenuDefaultItem (handle, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED);
690     if (id == -1) return null;
691     MENUITEMINFO info = new MENUITEMINFO ();
692     info.cbSize = MENUITEMINFO.sizeof;
693     info.fMask = OS.MIIM_ID;
694     if (OS.GetMenuItemInfo (handle, id, false, info)) {
695         return display.getMenuItem (info.wID);
696     }
697     return null;
698 }
699
700 /**
701  * Returns <code>true</code> if the receiver is enabled, and
702  * <code>false</code> otherwise. A disabled menu is typically
703  * not selectable from the user interface and draws with an
704  * inactive or "grayed" look.
705  *
706  * @return the receiver's enabled state
707  *
708  * @exception SWTException <ul>
709  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
710  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
711  * </ul>
712  *
713  * @see #isEnabled
714  */

715 public boolean getEnabled () {
716     checkWidget ();
717     return (state & DISABLED) == 0;
718 }
719
720 /**
721  * Returns the foreground color that the receiver will use to draw.
722  *
723  * @return the receiver's foreground color
724  *
725  * @exception SWTException <ul>
726  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
727  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
728  * </ul>
729  */

730 /*public*/ Color getForeground () {
731     checkWidget ();
732     return Color.win32_new (display, foreground != -1 ? foreground : defaultForeground ());
733 }
734
735 /**
736  * Returns the item at the given, zero-relative index in the
737  * receiver. Throws an exception if the index is out of range.
738  *
739  * @param index the index of the item to return
740  * @return the item at the given index
741  *
742  * @exception IllegalArgumentException <ul>
743  * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
744  * </ul>
745  * @exception SWTException <ul>
746  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
747  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
748  * </ul>
749  */

750 public MenuItem getItem (int index) {
751     checkWidget ();
752     int id = 0;
753     if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
754         if (OS.IsPPC) {
755             TBBUTTON lpButton = new TBBUTTON ();
756             int result = OS.SendMessage (hwndCB, OS.TB_GETBUTTON, index, lpButton);
757             if (result == 0) error (SWT.ERROR_CANNOT_GET_ITEM);
758             id = lpButton.idCommand;
759         }
760         if (OS.IsSP) {
761             if (!(0 <= index && index <= 1)) error (SWT.ERROR_CANNOT_GET_ITEM);
762             id = index == 0 ? id0 : id1;
763         }
764     } else {
765         MENUITEMINFO info = new MENUITEMINFO ();
766         info.cbSize = MENUITEMINFO.sizeof;
767         info.fMask = OS.MIIM_DATA;
768         if (!OS.GetMenuItemInfo (handle, index, true, info)) {
769             error (SWT.ERROR_INVALID_RANGE);
770         }
771         id = info.dwItemData;
772     }
773     return display.getMenuItem (id);
774 }
775
776 /**
777  * Returns the number of items contained in the receiver.
778  *
779  * @return the number of items
780  *
781  * @exception SWTException <ul>
782  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
783  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
784  * </ul>
785  */

786 public int getItemCount () {
787     checkWidget ();
788     return GetMenuItemCount (handle);
789 }
790
791 /**
792  * Returns a (possibly empty) array of <code>MenuItem</code>s which
793  * are the items in the receiver.
794  * <p>
795  * Note: This is not the actual structure used by the receiver
796  * to maintain its list of items, so modifying the array will
797  * not affect the receiver.
798  * </p>
799  *
800  * @return the items in the receiver
801  *
802  * @exception SWTException <ul>
803  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
804  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
805  * </ul>
806  */

807 public MenuItem [] getItems () {
808     checkWidget ();
809     if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
810         if (OS.IsSP) {
811             MenuItem [] result = new MenuItem [2];
812             result[0] = display.getMenuItem (id0);
813             result[1] = display.getMenuItem (id1);
814             return result;
815         }
816         int count = OS.SendMessage (hwndCB, OS.TB_BUTTONCOUNT, 0, 0);
817         TBBUTTON lpButton = new TBBUTTON ();
818         MenuItem [] result = new MenuItem [count];
819         for (int i=0; i<count; i++) {
820             OS.SendMessage (hwndCB, OS.TB_GETBUTTON, i, lpButton);
821             result [i] = display.getMenuItem (lpButton.idCommand);
822         }
823         return result;
824     }
825     int index = 0, count = 0;
826     int length = OS.IsWinCE ? 4 : OS.GetMenuItemCount (handle);
827     MenuItem [] items = new MenuItem [length];
828     MENUITEMINFO info = new MENUITEMINFO ();
829     info.cbSize = MENUITEMINFO.sizeof;
830     info.fMask = OS.MIIM_DATA;
831     while (OS.GetMenuItemInfo (handle, index, true, info)) {
832         if (count == items.length) {
833             MenuItem [] newItems = new MenuItem [count + 4];
834             System.arraycopy (items, 0, newItems, 0, count);
835             items = newItems;
836         }
837         MenuItem item = display.getMenuItem (info.dwItemData);
838         if (item != null) items [count++] = item;
839         index++;
840     }
841     if (count == items.length) return items;
842     MenuItem [] result = new MenuItem [count];
843     System.arraycopy (items, 0, result, 0, count);
844     return result;
845 }
846
847 int GetMenuItemCount (int handle) {
848     if (OS.IsWinCE) {
849         if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
850             return OS.IsSP ? 2 : OS.SendMessage (hwndCB, OS.TB_BUTTONCOUNT, 0, 0);
851         }
852         int count = 0;
853         MENUITEMINFO info = new MENUITEMINFO ();
854         info.cbSize = MENUITEMINFO.sizeof;
855         while (OS.GetMenuItemInfo (handle, count, true, info)) count++;
856         return count;
857     }
858     return OS.GetMenuItemCount (handle);
859 }
860
861 String JavaDoc getNameText () {
862     String JavaDoc result = "";
863     MenuItem [] items = getItems ();
864     int length = items.length;
865     if (length > 0) {
866         for (int i=0; i<length-1; i++) {
867             result = result + items [i].getNameText() + ", ";
868         }
869         result = result + items [length-1].getNameText ();
870     }
871     return result;
872 }
873
874 /**
875  * Returns the receiver's parent, which must be a <code>Decorations</code>.
876  *
877  * @return the receiver's parent
878  *
879  * @exception SWTException <ul>
880  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
881  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
882  * </ul>
883  */

884 public Decorations getParent () {
885     checkWidget ();
886     return parent;
887 }
888
889 /**
890  * Returns the receiver's parent item, which must be a
891  * <code>MenuItem</code> or null when the receiver is a
892  * root.
893  *
894  * @return the receiver's parent item
895  *
896  * @exception SWTException <ul>
897  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
898  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
899  * </ul>
900  */

901 public MenuItem getParentItem () {
902     checkWidget ();
903     return cascade;
904 }
905
906 /**
907  * Returns the receiver's parent item, which must be a
908  * <code>Menu</code> or null when the receiver is a
909  * root.
910  *
911  * @return the receiver's parent item
912  *
913  * @exception SWTException <ul>
914  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
915  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
916  * </ul>
917  */

918 public Menu getParentMenu () {
919     checkWidget ();
920     if (cascade != null) return cascade.parent;
921     return null;
922 }
923
924 /**
925  * Returns the receiver's shell. For all controls other than
926  * shells, this simply returns the control's nearest ancestor
927  * shell. Shells return themselves, even if they are children
928  * of other shells.
929  *
930  * @return the receiver's shell
931  *
932  * @exception SWTException <ul>
933  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
934  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
935  * </ul>
936  *
937  * @see #getParent
938  */

939 public Shell getShell () {
940     checkWidget ();
941     return parent.getShell ();
942 }
943
944 /**
945  * Returns <code>true</code> if the receiver is visible, and
946  * <code>false</code> otherwise.
947  * <p>
948  * If one of the receiver's ancestors is not visible or some
949  * other condition makes the receiver not visible, this method
950  * may still indicate that it is considered visible even though
951  * it may not actually be showing.
952  * </p>
953  *
954  * @return the receiver's visibility state
955  *
956  * @exception SWTException <ul>
957  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
958  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
959  * </ul>
960  */

961 public boolean getVisible () {
962     checkWidget ();
963     if ((style & SWT.BAR) != 0) {
964         return this == parent.menuShell ().menuBar;
965     }
966     if ((style & SWT.POP_UP) != 0) {
967         Menu [] popups = display.popups;
968         if (popups == null) return false;
969         for (int i=0; i<popups.length; i++) {
970             if (popups [i] == this) return true;
971         }
972     }
973     Shell shell = getShell ();
974     Menu menu = shell.activeMenu;
975     while (menu != null && menu != this) {
976         menu = menu.getParentMenu ();
977     }
978     return this == menu;
979 }
980
981 int imageIndex (Image image) {
982     if (hwndCB == 0 || image == null) return OS.I_IMAGENONE;
983     if (imageList == null) {
984         Rectangle bounds = image.getBounds ();
985         imageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, bounds.width, bounds.height);
986         int index = imageList.add (image);
987         int hImageList = imageList.getHandle ();
988         OS.SendMessage (hwndCB, OS.TB_SETIMAGELIST, 0, hImageList);
989         return index;
990     }
991     int index = imageList.indexOf (image);
992     if (index == -1) {
993         index = imageList.add (image);
994     } else {
995         imageList.put (index, image);
996     }
997     return index;
998 }
999
1000/**
1001 * Searches the receiver's list starting at the first item
1002 * (index 0) until an item is found that is equal to the
1003 * argument, and returns the index of that item. If no item
1004 * is found, returns -1.
1005 *
1006 * @param item the search item
1007 * @return the index of the item
1008 *
1009 * @exception IllegalArgumentException <ul>
1010 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
1011 * </ul>
1012 * @exception SWTException <ul>
1013 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1014 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1015 * </ul>
1016 */

1017public int indexOf (MenuItem item) {
1018    checkWidget ();
1019    if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
1020    if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
1021    if (item.parent != this) return -1;
1022    if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
1023        if (OS.IsPPC) {
1024            return OS.SendMessage (hwndCB, OS.TB_COMMANDTOINDEX, item.id, 0);
1025        }
1026        if (OS.IsSP) {
1027            if (item.id == id0) return 0;
1028            if (item.id == id1) return 1;
1029            return -1;
1030        }
1031    }
1032    int index = 0;
1033    MENUITEMINFO info = new MENUITEMINFO ();
1034    info.cbSize = MENUITEMINFO.sizeof;
1035    info.fMask = OS.MIIM_DATA;
1036    while (OS.GetMenuItemInfo (handle, index, true, info)) {
1037        if (info.dwItemData == item.id) return index;
1038        index++;
1039    }
1040    return -1;
1041}
1042
1043/**
1044 * Returns <code>true</code> if the receiver is enabled and all
1045 * of the receiver's ancestors are enabled, and <code>false</code>
1046 * otherwise. A disabled menu is typically not selectable from the
1047 * user interface and draws with an inactive or "grayed" look.
1048 *
1049 * @return the receiver's enabled state
1050 *
1051 * @exception SWTException <ul>
1052 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1053 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1054 * </ul>
1055 *
1056 * @see #getEnabled
1057 */

1058public boolean isEnabled () {
1059    checkWidget ();
1060    Menu parentMenu = getParentMenu ();
1061    if (parentMenu == null) {
1062        return getEnabled () && parent.isEnabled ();
1063    }
1064    return getEnabled () && parentMenu.isEnabled ();
1065}
1066
1067/**
1068 * Returns <code>true</code> if the receiver is visible and all
1069 * of the receiver's ancestors are visible and <code>false</code>
1070 * otherwise.
1071 *
1072 * @return the receiver's visibility state
1073 *
1074 * @exception SWTException <ul>
1075 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1076 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1077 * </ul>
1078 *
1079 * @see #getVisible
1080 */

1081public boolean isVisible () {
1082    checkWidget ();
1083    return getVisible ();
1084}
1085
1086void redraw () {
1087    if (!isVisible ()) return;
1088    if ((style & SWT.BAR) != 0) {
1089        display.addBar (this);
1090    } else {
1091        update ();
1092    }
1093}
1094
1095void releaseHandle () {
1096    super.releaseHandle ();
1097    handle = hwndCB = 0;
1098}
1099
1100void releaseChildren (boolean destroy) {
1101    MenuItem [] items = getItems ();
1102    for (int i=0; i<items.length; i++) {
1103        MenuItem item = items [i];
1104        if (item != null && !item.isDisposed ()) {
1105            if (OS.IsPPC && hwndCB != 0) {
1106                item.dispose ();
1107            } else {
1108                item.release (false);
1109            }
1110        }
1111    }
1112    super.releaseChildren (destroy);
1113}
1114
1115void releaseParent () {
1116    super.releaseParent ();
1117    if (cascade != null) cascade.releaseMenu ();
1118    if ((style & SWT.BAR) != 0) {
1119        display.removeBar (this);
1120        if (this == parent.menuBar) {
1121            parent.setMenuBar (null);
1122        }
1123    } else {
1124        if ((style & SWT.POP_UP) != 0) {
1125            display.removePopup (this);
1126        }
1127    }
1128}
1129
1130void releaseWidget () {
1131    super.releaseWidget ();
1132    backgroundImage = null;
1133    if (hBrush == 0) OS.DeleteObject (hBrush);
1134    hBrush = 0;
1135    if (OS.IsPPC && hwndCB != 0) {
1136        if (imageList != null) {
1137            OS.SendMessage (hwndCB, OS.TB_SETIMAGELIST, 0, 0);
1138            display.releaseToolImageList (imageList);
1139            imageList = null;
1140        }
1141    }
1142    if (parent != null) parent.removeMenu (this);
1143    parent = null;
1144    cascade = null;
1145}
1146
1147/**
1148 * Removes the listener from the collection of listeners who will
1149 * be notified when the help events are generated for the control.
1150 *
1151 * @param listener the listener which should no longer be notified
1152 *
1153 * @exception IllegalArgumentException <ul>
1154 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1155 * </ul>
1156 * @exception SWTException <ul>
1157 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1158 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1159 * </ul>
1160 *
1161 * @see HelpListener
1162 * @see #addHelpListener
1163 */

1164public void removeHelpListener (HelpListener listener) {
1165    checkWidget ();
1166    if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
1167    if (eventTable == null) return;
1168    eventTable.unhook (SWT.Help, listener);
1169}
1170
1171/**
1172 * Removes the listener from the collection of listeners who will
1173 * be notified when the menu events are generated for the control.
1174 *
1175 * @param listener the listener which should no longer be notified
1176 *
1177 * @exception IllegalArgumentException <ul>
1178 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1179 * </ul>
1180 * @exception SWTException <ul>
1181 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1182 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1183 * </ul>
1184 *
1185 * @see MenuListener
1186 * @see #addMenuListener
1187 */

1188public void removeMenuListener (MenuListener listener) {
1189    checkWidget ();
1190    if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
1191    if (eventTable == null) return;
1192    eventTable.unhook (SWT.Hide, listener);
1193    eventTable.unhook (SWT.Show, listener);
1194}
1195
1196/**
1197 * Sets the receiver's background color to the color specified
1198 * by the argument, or to the default system color for the control
1199 * if the argument is null.
1200 *
1201 * @param color the new color (or null)
1202 *
1203 * @exception IllegalArgumentException <ul>
1204 * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1205 * </ul>
1206 * @exception SWTException <ul>
1207 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1208 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1209 * </ul>
1210 *
1211 * @since 3.3
1212 */

1213/*public*/ void setBackground (Color color) {
1214    checkWidget ();
1215    int pixel = -1;
1216    if (color != null) {
1217        if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1218        pixel = color.handle;
1219    }
1220    if (pixel == background) return;
1221    background = pixel;
1222    updateBackground ();
1223}
1224
1225/**
1226 * Sets the receiver's background image to the image specified
1227 * by the argument, or to the default system color for the control
1228 * if the argument is null. The background image is tiled to fill
1229 * the available space.
1230 *
1231 * @param image the new image (or null)
1232 *
1233 * @exception IllegalArgumentException <ul>
1234 * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1235 * <li>ERROR_INVALID_ARGUMENT - if the argument is not a bitmap</li>
1236 * </ul>
1237 * @exception SWTException <ul>
1238 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1239 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1240 * </ul>
1241 *
1242 * @since 3.3
1243 */

1244/*public*/ void setBackgroundImage (Image image) {
1245    checkWidget ();
1246    if (image != null) {
1247        if (image.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
1248        if (image.type != SWT.BITMAP) error (SWT.ERROR_INVALID_ARGUMENT);
1249    }
1250    if (backgroundImage == image) return;
1251    backgroundImage = image;
1252    updateBackground ();
1253}
1254
1255/**
1256 * Sets the receiver's foreground color to the color specified
1257 * by the argument, or to the default system color for the control
1258 * if the argument is null.
1259 *
1260 * @param color the new color (or null)
1261 *
1262 * @exception IllegalArgumentException <ul>
1263 * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1264 * </ul>
1265 * @exception SWTException <ul>
1266 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1267 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1268 * </ul>
1269 *
1270 * @since 3.3
1271 */

1272/*public*/ void setForeground (Color color) {
1273    checkWidget ();
1274    int pixel = -1;
1275    if (color != null) {
1276        if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1277        pixel = color.handle;
1278    }
1279    if (pixel == foreground) return;
1280    foreground = pixel;
1281    updateForeground ();
1282}
1283
1284/**
1285 * Sets the default menu item to the argument or removes
1286 * the default emphasis when the argument is <code>null</code>.
1287 *
1288 * @param item the default menu item or null
1289 *
1290 * @exception IllegalArgumentException <ul>
1291 * <li>ERROR_INVALID_ARGUMENT - if the menu item has been disposed</li>
1292 * </ul>
1293 * @exception SWTException <ul>
1294 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1295 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1296 * </ul>
1297 */

1298public void setDefaultItem (MenuItem item) {
1299    checkWidget ();
1300    int newID = -1;
1301    if (item != null) {
1302        if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
1303        if (item.parent != this) return;
1304        newID = item.id;
1305    }
1306    if (OS.IsWinCE) return;
1307    int oldID = OS.GetMenuDefaultItem (handle, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED);
1308    if (newID == oldID) return;
1309    OS.SetMenuDefaultItem (handle, newID, OS.MF_BYCOMMAND);
1310    redraw ();
1311}
1312
1313/**
1314 * Enables the receiver if the argument is <code>true</code>,
1315 * and disables it otherwise. A disabled menu is typically
1316 * not selectable from the user interface and draws with an
1317 * inactive or "grayed" look.
1318 *
1319 * @param enabled the new enabled state
1320 *
1321 * @exception SWTException <ul>
1322 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1323 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1324 * </ul>
1325 */

1326public void setEnabled (boolean enabled) {
1327    checkWidget ();
1328    state &= ~DISABLED;
1329    if (!enabled) state |= DISABLED;
1330}
1331
1332/**
1333 * Sets the location of the receiver, which must be a popup,
1334 * to the point specified by the arguments which are relative
1335 * to the display.
1336 * <p>
1337 * Note that this is different from most widgets where the
1338 * location of the widget is relative to the parent.
1339 * </p><p>
1340 * Note that the platform window manager ultimately has control
1341 * over the location of popup menus.
1342 * </p>
1343 *
1344 * @param x the new x coordinate for the receiver
1345 * @param y the new y coordinate for the receiver
1346 *
1347 * @exception SWTException <ul>
1348 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1349 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1350 * </ul>
1351 */

1352public void setLocation (int x, int y) {
1353    checkWidget ();
1354    if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return;
1355    this.x = x;
1356    this.y = y;
1357    hasLocation = true;
1358}
1359
1360/**
1361 * Sets the location of the receiver, which must be a popup,
1362 * to the point specified by the argument which is relative
1363 * to the display.
1364 * <p>
1365 * Note that this is different from most widgets where the
1366 * location of the widget is relative to the parent.
1367 * </p><p>
1368 * Note that the platform window manager ultimately has control
1369 * over the location of popup menus.
1370 * </p>
1371 *
1372 * @param location the new location for the receiver
1373 *
1374 * @exception IllegalArgumentException <ul>
1375 * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
1376 * </ul>
1377 * @exception SWTException <ul>
1378 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1379 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1380 * </ul>
1381 *
1382 * @since 2.1
1383 */

1384public void setLocation (Point location) {
1385    checkWidget ();
1386    if (location == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
1387    setLocation (location.x, location.y);
1388}
1389
1390/**
1391 * Marks the receiver as visible if the argument is <code>true</code>,
1392 * and marks it invisible otherwise.
1393 * <p>
1394 * If one of the receiver's ancestors is not visible or some
1395 * other condition makes the receiver not visible, marking
1396 * it visible may not actually cause it to be displayed.
1397 * </p>
1398 *
1399 * @param visible the new visibility state
1400 *
1401 * @exception SWTException <ul>
1402 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1403 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1404 * </ul>
1405 */

1406public void setVisible (boolean visible) {
1407    checkWidget ();
1408    if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return;
1409    if (visible) {
1410        display.addPopup (this);
1411    } else {
1412        display.removePopup (this);
1413        _setVisible (false);
1414    }
1415}
1416
1417void update () {
1418    if (OS.IsPPC || OS.IsSP) return;
1419    if (OS.IsHPC) {
1420        /*
1421        * Each time a menu has been modified, the command menu bar
1422        * must be redrawn or it won't update properly. For example,
1423        * a submenu will not drop down.
1424        */

1425        Menu menuBar = parent.menuBar;
1426        if (menuBar != null) {
1427            Menu menu = this;
1428            while (menu != null && menu != menuBar) {
1429                menu = menu.getParentMenu ();
1430            }
1431            if (menu == menuBar) {
1432                OS.CommandBar_DrawMenuBar (menuBar.hwndCB, 0);
1433                OS.CommandBar_Show (menuBar.hwndCB, true);
1434            }
1435        }
1436        return;
1437    }
1438    if (OS.IsWinCE) return;
1439    if ((style & SWT.BAR) != 0) {
1440        if (this == parent.menuBar) OS.DrawMenuBar (parent.handle);
1441        return;
1442    }
1443    if (OS.WIN32_VERSION < OS.VERSION (4, 10)) {
1444        return;
1445    }
1446    boolean hasCheck = false, hasImage = false;
1447    MenuItem [] items = getItems ();
1448    for (int i=0; i<items.length; i++) {
1449        MenuItem item = items [i];
1450        if (item.image != null) {
1451            if ((hasImage = true) && hasCheck) break;
1452        }
1453        if ((item.style & (SWT.CHECK | SWT.RADIO)) != 0) {
1454            if ((hasCheck = true) && hasImage) break;
1455        }
1456    }
1457    
1458    /*
1459    * Bug in Windows. If a menu contains items that have
1460    * images and can be checked, Windows does not include
1461    * the width of the image and the width of the check when
1462    * computing the width of the menu. When the longest item
1463    * does not have an image, the label and the accelerator
1464    * text can overlap. The fix is to use SetMenuItemInfo()
1465    * to indicate that all items have a bitmap and then include
1466    * the width of the widest bitmap in WM_MEASURECHILD.
1467    *
1468    * NOTE: This work around causes problems on Windows 98.
1469    * Under certain circumstances that have yet to be isolated,
1470    * some menus can become huge and blank. For now, do not
1471    * run the code on Windows 98.
1472    *
1473    * NOTE: This work around doesn't run on Vista because
1474    * WM_MEASURECHILD and WM_DRAWITEM cause Vista to lose
1475    * the menu theme.
1476    */

1477    if (!OS.IsWin95) {
1478        if (OS.WIN32_VERSION < OS.VERSION (6, 0)) {
1479            MENUITEMINFO info = new MENUITEMINFO ();
1480            info.cbSize = MENUITEMINFO.sizeof;
1481            info.fMask = OS.MIIM_BITMAP;
1482            for (int i=0; i<items.length; i++) {
1483                MenuItem item = items [i];
1484                if ((style & SWT.SEPARATOR) == 0) {
1485                    if (item.image == null || foreground != -1) {
1486                        info.hbmpItem = hasImage || foreground != -1 ? OS.HBMMENU_CALLBACK : 0;
1487                        OS.SetMenuItemInfo (handle, item.id, false, info);
1488                    }
1489                }
1490            }
1491        }
1492    }
1493
1494    /* Update the menu to hide or show the space for bitmaps */
1495    MENUINFO lpcmi = new MENUINFO ();
1496    lpcmi.cbSize = MENUINFO.sizeof;
1497    lpcmi.fMask = OS.MIM_STYLE;
1498    OS.GetMenuInfo (handle, lpcmi);
1499    if (hasImage && !hasCheck) {
1500        lpcmi.dwStyle |= OS.MNS_CHECKORBMP;
1501    } else {
1502        lpcmi.dwStyle &= ~OS.MNS_CHECKORBMP;
1503    }
1504    OS.SetMenuInfo (handle, lpcmi);
1505}
1506
1507void updateBackground () {
1508    if (hBrush == 0) OS.DeleteObject (hBrush);
1509    hBrush = 0;
1510    if (backgroundImage != null) {
1511        hBrush = OS.CreatePatternBrush (backgroundImage.handle);
1512    } else {
1513        if (background != -1) hBrush = OS.CreateSolidBrush (background);
1514    }
1515    MENUINFO lpcmi = new MENUINFO ();
1516    lpcmi.cbSize = MENUINFO.sizeof;
1517    lpcmi.fMask = OS.MIM_BACKGROUND;
1518    lpcmi.hbrBack = hBrush;
1519    OS.SetMenuInfo (handle, lpcmi);
1520}
1521
1522void updateForeground () {
1523    if (OS.WIN32_VERSION < OS.VERSION (4, 10)) return;
1524    MENUITEMINFO info = new MENUITEMINFO ();
1525    info.cbSize = MENUITEMINFO.sizeof;
1526    int index = 0;
1527    while (OS.GetMenuItemInfo (handle, index, true, info)) {
1528        info.fMask = OS.MIIM_BITMAP;
1529        info.hbmpItem = OS.HBMMENU_CALLBACK;
1530        OS.SetMenuItemInfo (handle, index, true, info);
1531        index++;
1532    }
1533    redraw ();
1534}
1535}
1536
Popular Tags