]> git.saurik.com Git - wxWidgets.git/blob - src/osx/menu_osx.cpp
Use the correct accelerator for the "Preferences" Apple menu item.
[wxWidgets.git] / src / osx / menu_osx.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/menu_osx.cpp
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // headers & declarations
14 // ============================================================================
15
16 // wxWidgets headers
17 // -----------------
18
19 #include "wx/wxprec.h"
20
21 #if wxUSE_MENUS
22
23 #include "wx/menu.h"
24
25 #ifndef WX_PRECOMP
26 #include "wx/log.h"
27 #include "wx/app.h"
28 #include "wx/utils.h"
29 #include "wx/frame.h"
30 #include "wx/dialog.h"
31 #include "wx/menuitem.h"
32 #endif
33
34 #include "wx/osx/private.h"
35
36 // other standard headers
37 // ----------------------
38 #include <string.h>
39
40 IMPLEMENT_ABSTRACT_CLASS( wxMenuImpl , wxObject )
41
42 wxMenuImpl::~wxMenuImpl()
43 {
44 }
45
46 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
47 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
48
49 // the (popup) menu title has this special id
50 static const int idMenuTitle = -3;
51
52 // ============================================================================
53 // implementation
54 // ============================================================================
55
56 // Menus
57
58 // Construct a menu with optional title (then use append)
59
60 static
61 wxMenu *
62 _wxMenuAt(const wxMenuList &menuList, size_t pos)
63 {
64 wxMenuList::compatibility_iterator menuIter = menuList.GetFirst();
65
66 while (pos-- > 0)
67 menuIter = menuIter->GetNext();
68
69 return menuIter->GetData() ;
70 }
71
72 void wxMenu::Init()
73 {
74 m_doBreak = false;
75 m_startRadioGroup = -1;
76 m_allowRearrange = true;
77 m_noEventsMode = false;
78
79 m_peer = wxMenuImpl::Create( this, wxStripMenuCodes(m_title) );
80
81
82 // if we have a title, insert it in the beginning of the menu
83 if ( !m_title.empty() )
84 {
85 Append(idMenuTitle, m_title) ;
86 AppendSeparator() ;
87 }
88 }
89
90 wxMenu::~wxMenu()
91 {
92 delete m_peer;
93 }
94
95 WXHMENU wxMenu::GetHMenu() const
96 {
97 if ( m_peer )
98 return m_peer->GetHMenu();
99 return NULL;
100 }
101
102 void wxMenu::Break()
103 {
104 // not available on the mac platform
105 }
106
107 void wxMenu::Attach(wxMenuBarBase *menubar)
108 {
109 wxMenuBase::Attach(menubar);
110
111 EndRadioGroup();
112 }
113
114 void wxMenu::SetAllowRearrange( bool allow )
115 {
116 m_allowRearrange = allow;
117 }
118
119 void wxMenu::SetNoEventsMode( bool noEvents )
120 {
121 m_noEventsMode = noEvents;
122 }
123
124 // function appends a new item or submenu to the menu
125 // append a new item or submenu to the menu
126 bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
127 {
128 wxASSERT_MSG( pItem != NULL, wxT("can't append NULL item to the menu") );
129 m_peer->InsertOrAppend( pItem, pos );
130
131 if ( pItem->IsSeparator() )
132 {
133 // nothing to do here
134 }
135 else
136 {
137 wxMenu *pSubMenu = pItem->GetSubMenu() ;
138 if ( pSubMenu != NULL )
139 {
140 wxASSERT_MSG( pSubMenu->GetHMenu() != NULL , wxT("invalid submenu added"));
141 pSubMenu->m_menuParent = this ;
142
143 pSubMenu->DoRearrange();
144 }
145 else
146 {
147 if ( pItem->GetId() == idMenuTitle )
148 pItem->GetMenu()->Enable( idMenuTitle, false );
149 }
150 }
151
152 // if we're already attached to the menubar, we must update it
153 if ( IsAttached() && GetMenuBar()->IsAttached() )
154 GetMenuBar()->Refresh();
155
156 return true ;
157 }
158
159 void wxMenu::EndRadioGroup()
160 {
161 // we're not inside a radio group any longer
162 m_startRadioGroup = -1;
163 }
164
165 wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
166 {
167 wxCHECK_MSG( item, NULL, wxT("NULL item in wxMenu::DoAppend") );
168
169 bool check = false;
170
171 if ( item->GetKind() == wxITEM_RADIO )
172 {
173 int count = GetMenuItemCount();
174
175 if ( m_startRadioGroup == -1 )
176 {
177 // start a new radio group
178 m_startRadioGroup = count;
179
180 // for now it has just one element
181 item->SetAsRadioGroupStart();
182 item->SetRadioGroupEnd(m_startRadioGroup);
183
184 // ensure that we have a checked item in the radio group
185 check = true;
186 }
187 else // extend the current radio group
188 {
189 // we need to update its end item
190 item->SetRadioGroupStart(m_startRadioGroup);
191 wxMenuItemList::compatibility_iterator node = GetMenuItems().Item(m_startRadioGroup);
192
193 if ( node )
194 {
195 node->GetData()->SetRadioGroupEnd(count);
196 }
197 else
198 {
199 wxFAIL_MSG( wxT("where is the radio group start item?") );
200 }
201 }
202 }
203 else // not a radio item
204 {
205 EndRadioGroup();
206 }
207
208 if ( !wxMenuBase::DoAppend(item) || !DoInsertOrAppend(item) )
209 return NULL;
210
211 if ( check )
212 // check the item initially
213 item->Check(true);
214
215 return item;
216 }
217
218 wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
219 {
220 if (wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos))
221 return item;
222
223 return NULL;
224 }
225
226 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
227 {
228 /*
229 // we need to find the items position in the child list
230 size_t pos;
231 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
232
233 for ( pos = 0; node; pos++ )
234 {
235 if ( node->GetData() == item )
236 break;
237
238 node = node->GetNext();
239 }
240
241 // DoRemove() (unlike Remove) can only be called for existing item!
242 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
243
244 wxOSXMenuRemoveItem(m_hMenu , pos );
245 */
246 m_peer->Remove( item );
247 // and from internal data structures
248 return wxMenuBase::DoRemove(item);
249 }
250
251 void wxMenu::SetTitle(const wxString& label)
252 {
253 m_title = label ;
254 m_peer->SetTitle( wxStripMenuCodes( label ) );
255 }
256
257 bool wxMenu::ProcessCommand(wxCommandEvent & event)
258 {
259 bool processed = false;
260
261 // Try the menu's event handler
262 if ( /* !processed && */ GetEventHandler())
263 processed = GetEventHandler()->SafelyProcessEvent(event);
264
265 // Try the window the menu was popped up from
266 // (and up through the hierarchy)
267 wxWindow *win = GetWindow();
268 if ( !processed && win )
269 processed = win->HandleWindowEvent(event);
270
271 return processed;
272 }
273
274 // ---------------------------------------------------------------------------
275 // other
276 // ---------------------------------------------------------------------------
277
278 // MacOS needs to know about submenus somewhere within this menu
279 // before it can be displayed, also hide special menu items
280 // like preferences that are handled by the OS
281 void wxMenu::DoRearrange()
282 {
283 if ( !AllowRearrange() )
284 return;
285
286 wxMenuItem* previousItem = NULL ;
287 size_t pos ;
288 wxMenuItemList::compatibility_iterator node;
289 wxMenuItem *item;
290
291 for (pos = 0, node = GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
292 {
293 item = (wxMenuItem *)node->GetData();
294 wxMenu* subMenu = item->GetSubMenu() ;
295 if (subMenu)
296 {
297 // already done
298 }
299 else // normal item
300 {
301 // what we do here is to hide the special items which are
302 // shown in the application menu anyhow -- it doesn't make
303 // sense to show them in their normal place as well
304 if ( item->GetId() == wxApp::s_macAboutMenuItemId ||
305 item->GetId() == wxApp::s_macPreferencesMenuItemId ||
306 item->GetId() == wxApp::s_macExitMenuItemId )
307
308 {
309 item->GetPeer()->Hide( true );
310
311 // also check for a separator which was used just to
312 // separate this item from the others, so don't leave
313 // separator at the menu start or end nor 2 consecutive
314 // separators
315 wxMenuItemList::compatibility_iterator nextNode = node->GetNext();
316 wxMenuItem *next = nextNode ? nextNode->GetData() : NULL;
317
318 wxMenuItem *sepToHide = 0;
319 if ( !previousItem && next && next->IsSeparator() )
320 {
321 // next (i.e. second as we must be first) item is
322 // the separator to hide
323 wxASSERT_MSG( pos == 0, wxT("should be the menu start") );
324 sepToHide = next;
325 }
326 else if ( GetMenuItems().GetCount() == pos + 1 &&
327 previousItem != NULL &&
328 previousItem->IsSeparator() )
329 {
330 // prev item is a trailing separator we want to hide
331 sepToHide = previousItem;
332 }
333 else if ( previousItem && previousItem->IsSeparator() &&
334 next && next->IsSeparator() )
335 {
336 // two consecutive separators, this is one too many
337 sepToHide = next;
338 }
339
340 if ( sepToHide )
341 {
342 // hide the separator as well
343 sepToHide->GetPeer()->Hide( true );
344 }
345 }
346 }
347
348 previousItem = item ;
349 }
350 }
351
352
353 bool wxMenu::HandleCommandUpdateStatus( wxMenuItem* item, wxWindow* senderWindow )
354 {
355 int id = item ? item->GetId() : 0;
356 wxUpdateUIEvent event(id);
357 event.SetEventObject( this );
358
359 bool processed = false;
360
361 // Try the menu's event handler
362 {
363 wxEvtHandler *handler = GetEventHandler();
364 if ( handler )
365 processed = handler->ProcessEvent(event);
366 }
367
368 // Try the window the menu was popped up from
369 // (and up through the hierarchy)
370 if ( !processed )
371 {
372 wxWindow *win = GetWindow();
373 if ( win )
374 processed = win->HandleWindowEvent(event);
375 }
376
377 if ( !processed && senderWindow != NULL)
378 {
379 processed = senderWindow->HandleWindowEvent(event);
380 }
381
382 if ( processed )
383 {
384 // if anything changed, update the changed attribute
385 if (event.GetSetText())
386 SetLabel(id, event.GetText());
387 if (event.GetSetChecked())
388 Check(id, event.GetChecked());
389 if (event.GetSetEnabled())
390 Enable(id, event.GetEnabled());
391 }
392 else
393 {
394 #if wxOSX_USE_CARBON
395 // these two items are also managed by the Carbon Menu Manager, therefore we must
396 // always reset them ourselves
397 UInt32 cmd = 0;
398
399 if ( id == wxApp::s_macExitMenuItemId )
400 {
401 cmd = kHICommandQuit;
402 }
403 else if (id == wxApp::s_macPreferencesMenuItemId )
404 {
405 cmd = kHICommandPreferences;
406 }
407
408 if ( cmd != 0 )
409 {
410 if ( !item->IsEnabled() || wxDialog::OSXHasModalDialogsOpen() )
411 DisableMenuCommand( NULL , cmd ) ;
412 else
413 EnableMenuCommand( NULL , cmd ) ;
414
415 }
416 #endif
417 }
418
419 return processed;
420 }
421
422 bool wxMenu::HandleCommandProcess( wxMenuItem* item, wxWindow* senderWindow )
423 {
424 int id = item ? item->GetId() : 0;
425 bool processed = false;
426 if (item->IsCheckable())
427 item->Check( !item->IsChecked() ) ;
428
429 if ( SendEvent( id , item->IsCheckable() ? item->IsChecked() : -1 ) )
430 processed = true ;
431 else
432 {
433 if ( senderWindow != NULL )
434 {
435 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED , id);
436 event.SetEventObject(senderWindow);
437 event.SetInt(item->IsCheckable() ? item->IsChecked() : -1);
438
439 if ( senderWindow->HandleWindowEvent(event) )
440 processed = true ;
441 }
442 }
443 return processed;
444 }
445
446 void wxMenu::HandleMenuItemHighlighted( wxMenuItem* item )
447 {
448 int id = item ? item->GetId() : 0;
449 wxMenuEvent wxevent(wxEVT_MENU_HIGHLIGHT, id, this);
450 DoHandleMenuEvent( wxevent );
451 }
452
453 void wxMenu::HandleMenuOpened()
454 {
455 wxMenuEvent wxevent(wxEVT_MENU_OPEN, 0, this);
456 DoHandleMenuEvent( wxevent );
457 }
458
459 void wxMenu::HandleMenuClosed()
460 {
461 wxMenuEvent wxevent(wxEVT_MENU_CLOSE, 0, this);
462 DoHandleMenuEvent( wxevent );
463 }
464
465 bool wxMenu::DoHandleMenuEvent(wxEvent& wxevent)
466 {
467 wxevent.SetEventObject(this);
468 wxEvtHandler* handler = GetEventHandler();
469 if (handler && handler->ProcessEvent(wxevent))
470 {
471 return true;
472 }
473 else
474 {
475 wxWindow *win = GetWindow();
476 if (win)
477 {
478 if ( win->HandleWindowEvent(wxevent) )
479 return true;
480 }
481 }
482 return false;
483 }
484
485 // Menu Bar
486
487 /*
488
489 Mac Implementation note :
490
491 The Mac has only one global menubar, so we attempt to install the currently
492 active menubar from a frame, we currently don't take into account mdi-frames
493 which would ask for menu-merging
494
495 Secondly there is no mac api for changing a menubar that is not the current
496 menubar, so we have to wait for preparing the actual menubar until the
497 wxMenubar is to be used
498
499 We can in subsequent versions use MacInstallMenuBar to provide some sort of
500 auto-merge for MDI in case this will be necessary
501
502 */
503
504 wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
505 wxMenuBar* wxMenuBar::s_macCommonMenuBar = NULL ;
506 bool wxMenuBar::s_macAutoWindowMenu = true ;
507 WXHMENU wxMenuBar::s_macWindowMenuHandle = NULL ;
508
509 void wxMenuBar::Init()
510 {
511 m_eventHandler = this;
512 m_menuBarFrame = NULL;
513 m_rootMenu = new wxMenu();
514 m_rootMenu->Attach(this);
515
516 m_appleMenu = new wxMenu();
517 m_appleMenu->SetAllowRearrange(false);
518
519 // Create standard items unless the application explicitly disabled this by
520 // setting the corresponding ids to wxID_NONE: although this is not
521 // recommended, sometimes these items really don't make sense.
522 if ( wxApp::s_macAboutMenuItemId != wxID_NONE )
523 {
524 wxString aboutLabel("About");
525 if ( wxTheApp )
526 aboutLabel << ' ' << wxTheApp->GetAppDisplayName();
527 else
528 aboutLabel << "...";
529 m_appleMenu->Append( wxApp::s_macAboutMenuItemId, aboutLabel);
530 m_appleMenu->AppendSeparator();
531 }
532
533 #if !wxOSX_USE_CARBON
534 if ( wxApp::s_macPreferencesMenuItemId != wxID_NONE )
535 {
536 m_appleMenu->Append( wxApp::s_macPreferencesMenuItemId,
537 "Preferences...\tCtrl+," );
538 m_appleMenu->AppendSeparator();
539 }
540
541 // Do always add "Quit" item unconditionally however, it can't be disabled.
542 m_appleMenu->Append( wxApp::s_macExitMenuItemId, "Quit\tCtrl+Q" );
543 #endif // !wxOSX_USE_CARBON
544
545 m_rootMenu->AppendSubMenu(m_appleMenu, "\x14") ;
546 }
547
548 wxMenuBar::wxMenuBar()
549 {
550 Init();
551 }
552
553 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
554 {
555 Init();
556 }
557
558 wxMenuBar::wxMenuBar(size_t count, wxMenu *menus[], const wxString titles[], long WXUNUSED(style))
559 {
560 Init();
561
562 m_titles.Alloc(count);
563
564 for ( size_t i = 0; i < count; i++ )
565 {
566 m_menus.Append(menus[i]);
567 m_titles.Add(titles[i]);
568
569 menus[i]->Attach(this);
570 Append( menus[i], titles[i] );
571 }
572 }
573
574 wxMenuBar::~wxMenuBar()
575 {
576 if (s_macCommonMenuBar == this)
577 s_macCommonMenuBar = NULL;
578
579 if (s_macInstalledMenuBar == this)
580 {
581 s_macInstalledMenuBar = NULL;
582 }
583 }
584
585 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
586 {
587 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
588 }
589
590 void wxMenuBar::MacInstallMenuBar()
591 {
592 if ( s_macInstalledMenuBar == this )
593 return ;
594
595 m_rootMenu->GetPeer()->MakeRoot();
596
597 #if 0
598
599 MenuBarHandle menubar = NULL ;
600
601 menubar = NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
602
603 ::SetMenuBar( menubar ) ;
604 DisposeMenuBar( menubar ) ;
605 MenuHandle appleMenu = NULL ;
606
607 verify_noerr( CreateNewMenu( kwxMacAppleMenuId , 0 , &appleMenu ) ) ;
608 verify_noerr( SetMenuTitleWithCFString( appleMenu , CFSTR( "\x14" ) ) );
609
610 // Add About/Preferences separator only on OS X
611 // KH/RN: Separator is always present on 10.3 but not on 10.2
612 // However, the change from 10.2 to 10.3 suggests it is preferred
613 InsertMenuItemTextWithCFString( appleMenu,
614 CFSTR(""), 0, kMenuItemAttrSeparator, 0);
615 InsertMenuItemTextWithCFString( appleMenu,
616 CFSTR("About..."), 0, 0, 0);
617 MacInsertMenu( appleMenu , 0 ) ;
618
619 // if we have a mac help menu, clean it up before adding new items
620 MenuHandle helpMenuHandle ;
621 MenuItemIndex firstUserHelpMenuItem ;
622
623 if ( UMAGetHelpMenuDontCreate( &helpMenuHandle , &firstUserHelpMenuItem) == noErr )
624 {
625 for ( int i = CountMenuItems( helpMenuHandle ) ; i >= firstUserHelpMenuItem ; --i )
626 DeleteMenuItem( helpMenuHandle , i ) ;
627 }
628 else
629 {
630 helpMenuHandle = NULL ;
631 }
632
633 if ( wxApp::s_macPreferencesMenuItemId)
634 {
635 wxMenuItem *item = FindItem( wxApp::s_macPreferencesMenuItemId , NULL ) ;
636 if ( item == NULL || !(item->IsEnabled()) )
637 DisableMenuCommand( NULL , kHICommandPreferences ) ;
638 else
639 EnableMenuCommand( NULL , kHICommandPreferences ) ;
640 }
641
642 // Unlike preferences which may or may not exist, the Quit item should be always
643 // enabled unless it is added by the application and then disabled, otherwise
644 // a program would be required to add an item with wxID_EXIT in order to get the
645 // Quit menu item to be enabled, which seems a bit burdensome.
646 if ( wxApp::s_macExitMenuItemId)
647 {
648 wxMenuItem *item = FindItem( wxApp::s_macExitMenuItemId , NULL ) ;
649 if ( item != NULL && !(item->IsEnabled()) )
650 DisableMenuCommand( NULL , kHICommandQuit ) ;
651 else
652 EnableMenuCommand( NULL , kHICommandQuit ) ;
653 }
654
655 wxString strippedHelpMenuTitle = wxStripMenuCodes( wxApp::s_macHelpMenuTitleName ) ;
656 wxString strippedTranslatedHelpMenuTitle = wxStripMenuCodes( wxString( _("&Help") ) ) ;
657 wxMenuList::compatibility_iterator menuIter = m_menus.GetFirst();
658 for (size_t i = 0; i < m_menus.GetCount(); i++, menuIter = menuIter->GetNext())
659 {
660 wxMenuItemList::compatibility_iterator node;
661 wxMenuItem *item;
662 wxMenu* menu = menuIter->GetData() , *subMenu = NULL ;
663 wxString strippedMenuTitle = wxStripMenuCodes(m_titles[i]);
664
665 if ( strippedMenuTitle == wxT("?") || strippedMenuTitle == strippedHelpMenuTitle || strippedMenuTitle == strippedTranslatedHelpMenuTitle )
666 {
667 for (node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext())
668 {
669 item = (wxMenuItem *)node->GetData();
670 subMenu = item->GetSubMenu() ;
671 if (subMenu)
672 {
673 UMAAppendMenuItem(mh, wxStripMenuCodes(item->GetText()) , wxFont::GetDefaultEncoding() );
674 MenuItemIndex position = CountMenuItems(mh);
675 ::SetMenuItemHierarchicalMenu(mh, position, MAC_WXHMENU(subMenu->GetHMenu()));
676 }
677 else
678 {
679 if ( item->GetId() != wxApp::s_macAboutMenuItemId )
680 {
681 // we have found a user help menu and an item other than the about item,
682 // so we can create the mac help menu now, if we haven't created it yet
683 if ( helpMenuHandle == NULL )
684 {
685 if ( UMAGetHelpMenu( &helpMenuHandle , &firstUserHelpMenuItem) != noErr )
686 {
687 helpMenuHandle = NULL ;
688 break ;
689 }
690 }
691 }
692
693 if ( item->IsSeparator() )
694 {
695 if ( helpMenuHandle )
696 AppendMenuItemTextWithCFString( helpMenuHandle,
697 CFSTR(""), kMenuItemAttrSeparator, 0,NULL);
698 }
699 else
700 {
701 wxAcceleratorEntry*
702 entry = wxAcceleratorEntry::Create( item->GetItemLabel() ) ;
703
704 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
705 {
706 // this will be taken care of below
707 }
708 else
709 {
710 if ( helpMenuHandle )
711 {
712 UMAAppendMenuItem(helpMenuHandle, wxStripMenuCodes(item->GetItemLabel()) , wxFont::GetDefaultEncoding(), entry);
713 SetMenuItemCommandID( helpMenuHandle , CountMenuItems(helpMenuHandle) , wxIdToMacCommand ( item->GetId() ) ) ;
714 SetMenuItemRefCon( helpMenuHandle , CountMenuItems(helpMenuHandle) , (URefCon) item ) ;
715 }
716 }
717
718 delete entry ;
719 }
720 }
721 }
722 }
723
724 else if ( ( m_titles[i] == wxT("Window") || m_titles[i] == wxT("&Window") )
725 && GetAutoWindowMenu() )
726 {
727 if ( MacGetWindowMenuHMenu() == NULL )
728 {
729 CreateStandardWindowMenu( 0 , (MenuHandle*) &s_macWindowMenuHandle ) ;
730 }
731
732 MenuRef wm = (MenuRef)MacGetWindowMenuHMenu();
733 if ( wm == NULL )
734 break;
735
736 // get the insertion point in the standard menu
737 MenuItemIndex winListStart;
738 GetIndMenuItemWithCommandID(wm,
739 kHICommandWindowListSeparator, 1, NULL, &winListStart);
740
741 // add a separator so that the standard items and the custom items
742 // aren't mixed together, but only if this is the first run
743 OSStatus err = GetIndMenuItemWithCommandID(wm,
744 'WXWM', 1, NULL, NULL);
745
746 if ( err == menuItemNotFoundErr )
747 {
748 InsertMenuItemTextWithCFString( wm,
749 CFSTR(""), winListStart-1, kMenuItemAttrSeparator, 'WXWM');
750 }
751
752 wxInsertMenuItemsInMenu(menu, wm, winListStart);
753 }
754 else
755 {
756 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , m_titles[i], GetFont().GetEncoding() ) ;
757 menu->MacBeforeDisplay(false) ;
758
759 ::InsertMenu(MAC_WXHMENU(_wxMenuAt(m_menus, i)->GetHMenu()), 0);
760 }
761 }
762
763 // take care of the about menu item wherever it is
764 {
765 wxMenu* aboutMenu ;
766 wxMenuItem *aboutMenuItem = FindItem(wxApp::s_macAboutMenuItemId , &aboutMenu) ;
767 if ( aboutMenuItem )
768 {
769 wxAcceleratorEntry*
770 entry = wxAcceleratorEntry::Create( aboutMenuItem->GetItemLabel() ) ;
771 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , wxStripMenuCodes ( aboutMenuItem->GetItemLabel() ) , wxFont::GetDefaultEncoding() );
772 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 , true );
773 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId ) , 1 , kHICommandAbout ) ;
774 SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId ) , 1 , (URefCon)aboutMenuItem ) ;
775 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId ) , 1 , entry ) ;
776 delete entry;
777 }
778 }
779
780 if ( GetAutoWindowMenu() )
781 {
782 if ( MacGetWindowMenuHMenu() == NULL )
783 CreateStandardWindowMenu( 0 , (MenuHandle*) &s_macWindowMenuHandle ) ;
784
785 InsertMenu( (MenuHandle) MacGetWindowMenuHMenu() , 0 ) ;
786 }
787
788 ::DrawMenuBar() ;
789 #endif
790
791 s_macInstalledMenuBar = this;
792 }
793
794 void wxMenuBar::EnableTop(size_t pos, bool enable)
795 {
796 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
797
798 m_rootMenu->FindItemByPosition( pos )->Enable(enable);
799
800 Refresh();
801 }
802
803 bool wxMenuBar::Enable(bool enable)
804 {
805 wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
806
807 size_t i;
808 for (i = 0; i < GetMenuCount(); i++)
809 EnableTop(i, enable);
810
811 return true;
812 }
813
814 void wxMenuBar::SetMenuLabel(size_t pos, const wxString& label)
815 {
816 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
817
818 m_titles[pos] = label;
819
820 if ( !IsAttached() )
821 return;
822
823 _wxMenuAt(m_menus, pos)->SetTitle( label ) ;
824 }
825
826 wxString wxMenuBar::GetMenuLabel(size_t pos) const
827 {
828 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
829 wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
830
831 return m_titles[pos];
832 }
833
834 int wxMenuBar::FindMenu(const wxString& title)
835 {
836 wxString menuTitle = wxStripMenuCodes(title);
837
838 size_t count = GetMenuCount();
839 for ( size_t i = 0; i < count; i++ )
840 {
841 wxString title = wxStripMenuCodes(m_titles[i]);
842 if ( menuTitle == title )
843 return i;
844 }
845
846 return wxNOT_FOUND;
847 }
848
849 // ---------------------------------------------------------------------------
850 // wxMenuBar construction
851 // ---------------------------------------------------------------------------
852
853 const int firstMenuPos = 1; // to account for the 0th application menu on mac
854
855 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
856 {
857 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
858 if ( !menuOld )
859 return NULL;
860
861 m_titles[pos] = title;
862
863 wxMenuItem* item = m_rootMenu->FindItemByPosition(pos+firstMenuPos);
864 m_rootMenu->Remove(item);
865 m_rootMenu->Insert( pos+firstMenuPos, wxMenuItem::New( m_rootMenu, wxID_ANY, title, "", wxITEM_NORMAL, menu ) );
866
867 return menuOld;
868 }
869
870 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
871 {
872 if ( !wxMenuBarBase::Insert(pos, menu, title) )
873 return false;
874
875 m_titles.Insert(title, pos);
876
877 m_rootMenu->Insert( pos+firstMenuPos, wxMenuItem::New( m_rootMenu, wxID_ANY, title, "", wxITEM_NORMAL, menu ) );
878
879 return true;
880 }
881
882 wxMenu *wxMenuBar::Remove(size_t pos)
883 {
884 wxMenu *menu = wxMenuBarBase::Remove(pos);
885 if ( !menu )
886 return NULL;
887
888 wxMenuItem* item = m_rootMenu->FindItemByPosition(pos+firstMenuPos);
889 m_rootMenu->Remove(item);
890
891 m_titles.RemoveAt(pos);
892
893 return menu;
894 }
895
896 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
897 {
898 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
899 wxCHECK_MSG( submenu, false, wxT("can't append invalid menu to menubar") );
900
901 if ( !wxMenuBarBase::Append(menu, title) )
902 return false;
903
904 m_titles.Add(title);
905
906 m_rootMenu->AppendSubMenu(menu, title);
907
908 return true;
909 }
910
911 void wxMenuBar::Detach()
912 {
913 wxMenuBarBase::Detach() ;
914 }
915
916 void wxMenuBar::Attach(wxFrame *frame)
917 {
918 wxMenuBarBase::Attach( frame ) ;
919 }
920
921 // ---------------------------------------------------------------------------
922 // wxMenuBar searching for menu items
923 // ---------------------------------------------------------------------------
924
925 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
926 int wxMenuBar::FindMenuItem(const wxString& menuString,
927 const wxString& itemString) const
928 {
929 wxString menuLabel = wxStripMenuCodes(menuString);
930 size_t count = GetMenuCount();
931 for ( size_t i = 0; i < count; i++ )
932 {
933 wxString title = wxStripMenuCodes(m_titles[i]);
934 if ( menuLabel == title )
935 return _wxMenuAt(m_menus, i)->FindItem(itemString);
936 }
937
938 return wxNOT_FOUND;
939 }
940
941 wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
942 {
943 if ( itemMenu )
944 *itemMenu = NULL;
945
946 wxMenuItem *item = NULL;
947 size_t count = GetMenuCount();
948 for ( size_t i = 0; !item && (i < count); i++ )
949 item = _wxMenuAt(m_menus, i)->FindItem(id, itemMenu);
950
951 return item;
952 }
953
954 #endif