]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/menu.cpp
workarounded false memory leak report
[wxWidgets.git] / src / mac / carbon / menu.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: menu.cpp
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
4 // Author: AUTHOR
5 // Modified by:
6 // Created: ??/??/98
7 // RCS-ID: $Id$
8 // Copyright: (c) AUTHOR
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12
13 // ============================================================================
14 // headers & declarations
15 // ============================================================================
16
17 // wxWindows headers
18 // -----------------
19
20 #ifdef __GNUG__
21 #pragma implementation "menu.h"
22 #pragma implementation "menuitem.h"
23 #endif
24
25 #include "wx/menu.h"
26 #include "wx/menuitem.h"
27 #include "wx/log.h"
28 #include "wx/utils.h"
29
30 #include "wx/mac/uma.h"
31
32 // other standard headers
33 // ----------------------
34 #include <string.h>
35
36 #if !USE_SHARED_LIBRARY
37 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
38 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
39 #endif
40
41 // the (popup) menu title has this special id
42 static const int idMenuTitle = -2;
43 static int formerHelpMenuItems = 0 ;
44
45 const short kwxMacMenuBarResource = 1 ;
46 const short kwxMacAppleMenuId = 1 ;
47
48 // ============================================================================
49 // implementation
50 // ============================================================================
51
52
53 // Menus
54
55 // Construct a menu with optional title (then use append)
56
57 short wxMenu::s_macNextMenuId = 2 ;
58
59 void wxMenu::Init()
60 {
61 m_doBreak = FALSE;
62
63 // create the menu
64 Str255 label;
65 wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_title , false );
66 m_macMenuId = s_macNextMenuId++;
67 wxCHECK_RET( s_macNextMenuId < 236 , "menu ids > 235 cannot be used for submenus on mac" );
68 m_hMenu = UMANewMenu(m_macMenuId, label);
69
70 if ( !m_hMenu )
71 {
72 wxLogLastError("CreatePopupMenu");
73 }
74
75 // if we have a title, insert it in the beginning of the menu
76 if ( !!m_title )
77 {
78 Append(idMenuTitle, m_title) ;
79 AppendSeparator() ;
80 }
81 }
82
83 wxMenu::~wxMenu()
84 {
85 if (m_hMenu)
86 UMADisposeMenu(m_hMenu);
87
88 #if wxUSE_ACCEL
89 // delete accels
90 WX_CLEAR_ARRAY(m_accels);
91 #endif // wxUSE_ACCEL
92 }
93
94 void wxMenu::Break()
95 {
96 // not available on the mac platform
97 }
98
99 #if wxUSE_ACCEL
100
101 int wxMenu::FindAccel(int id) const
102 {
103 size_t n, count = m_accels.GetCount();
104 for ( n = 0; n < count; n++ )
105 {
106 if ( m_accels[n]->m_command == id )
107 return n;
108 }
109
110 return wxNOT_FOUND;
111 }
112
113 void wxMenu::UpdateAccel(wxMenuItem *item)
114 {
115 // find the (new) accel for this item
116 wxAcceleratorEntry *accel = wxGetAccelFromString(item->GetText());
117 if ( accel )
118 accel->m_command = item->GetId();
119
120 // find the old one
121 int n = FindAccel(item->GetId());
122 if ( n == wxNOT_FOUND )
123 {
124 // no old, add new if any
125 if ( accel )
126 m_accels.Add(accel);
127 else
128 return; // skipping RebuildAccelTable() below
129 }
130 else
131 {
132 // replace old with new or just remove the old one if no new
133 delete m_accels[n];
134 if ( accel )
135 m_accels[n] = accel;
136 else
137 m_accels.Remove(n);
138 }
139
140 if ( IsAttached() )
141 {
142 m_menuBar->RebuildAccelTable();
143 }
144 }
145
146 #endif // wxUSE_ACCEL
147
148 // function appends a new item or submenu to the menu
149 // append a new item or submenu to the menu
150 bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
151 {
152 wxASSERT_MSG( pItem != NULL, "can't append NULL item to the menu" );
153 #if wxUSE_ACCEL
154 UpdateAccel(pItem);
155 #endif // wxUSE_ACCEL
156
157 if ( pItem->IsSeparator() )
158 {
159 if ( pos == (size_t)-1 )
160 {
161 MacAppendMenu(m_hMenu, "\p-");
162 }
163 else
164 {
165 MacInsertMenuItem(m_hMenu, "\p-" , pos);
166 }
167 }
168 else
169 {
170 wxMenu *pSubMenu = pItem->GetSubMenu() ;
171 if ( pSubMenu != NULL )
172 {
173 Str255 label;
174 wxASSERT_MSG( pSubMenu->m_hMenu != NULL , "invalid submenu added");
175 pSubMenu->m_menuParent = this ;
176 wxMenuItem::MacBuildMenuString( label , NULL , NULL , pItem->GetText() ,false);
177
178 if (wxMenuBar::MacGetInstalledMenuBar() == m_menuBar)
179 {
180 UMAInsertMenu( pSubMenu->m_hMenu , -1 ) ;
181 }
182
183 if ( pos == (size_t)-1 )
184 {
185 UMAAppendSubMenuItem(m_hMenu, label, pSubMenu->m_macMenuId);
186 }
187 else
188 {
189 UMAInsertSubMenuItem(m_hMenu, label , pos, pSubMenu->m_macMenuId);
190 }
191 }
192 else
193 {
194 Str255 label ;
195 UInt8 modifiers ;
196 SInt16 key ;
197 wxMenuItem::MacBuildMenuString( label, &key , &modifiers , pItem->GetText(), pItem->GetId() == wxApp::s_macAboutMenuItemId);
198 if ( label[0] == 0 )
199 {
200 // we cannot add empty menus on mac
201 label[0] = 1 ;
202 label[1] = ' ' ;
203 }
204 if ( pos == (size_t)-1 )
205 {
206 UMAAppendMenuItem(m_hMenu, label,key,modifiers);
207 }
208 else
209 {
210 UMAInsertMenuItem(m_hMenu, label , pos,key,modifiers);
211 }
212 if ( pItem->GetId() == idMenuTitle )
213 {
214 if ( pos == (size_t)-1 )
215 {
216 UMADisableMenuItem( m_hMenu , CountMenuItems( m_hMenu ) ) ;
217 }
218 else
219 {
220 UMADisableMenuItem( m_hMenu , pos + 1 ) ;
221 }
222 }
223 }
224 }
225 // if we're already attached to the menubar, we must update it
226 if ( IsAttached() )
227 {
228 m_menuBar->Refresh();
229 }
230 return TRUE ;
231 }
232
233 bool wxMenu::DoAppend(wxMenuItem *item)
234 {
235 return wxMenuBase::DoAppend(item) && DoInsertOrAppend(item);
236 }
237
238 bool wxMenu::DoInsert(size_t pos, wxMenuItem *item)
239 {
240 return wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos);
241 }
242
243 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
244 {
245 // we need to find the items position in the child list
246 size_t pos;
247 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
248 for ( pos = 0; node; pos++ )
249 {
250 if ( node->GetData() == item )
251 break;
252
253 node = node->GetNext();
254 }
255
256 // DoRemove() (unlike Remove) can only be called for existing item!
257 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
258
259 #if wxUSE_ACCEL
260 // remove the corresponding accel from the accel table
261 int n = FindAccel(item->GetId());
262 if ( n != wxNOT_FOUND )
263 {
264 delete m_accels[n];
265
266 m_accels.Remove(n);
267 }
268 //else: this item doesn't have an accel, nothing to do
269 #endif // wxUSE_ACCEL
270
271 ::DeleteMenuItem( m_hMenu , pos + 1);
272
273 if ( IsAttached() )
274 {
275 // otherwise, the chane won't be visible
276 m_menuBar->Refresh();
277 }
278
279 // and from internal data structures
280 return wxMenuBase::DoRemove(item);
281 }
282
283 // ---------------------------------------------------------------------------
284 // accelerator helpers
285 // ---------------------------------------------------------------------------
286
287 #if wxUSE_ACCEL
288
289 // create the wxAcceleratorEntries for our accels and put them into provided
290 // array - return the number of accels we have
291 size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const
292 {
293 size_t count = GetAccelCount();
294 for ( size_t n = 0; n < count; n++ )
295 {
296 *accels++ = *m_accels[n];
297 }
298
299 return count;
300 }
301
302 #endif // wxUSE_ACCEL
303
304 void wxMenu::SetTitle(const wxString& label)
305 {
306 Str255 title ;
307 m_title = label ;
308 wxMenuItem::MacBuildMenuString( title, NULL , NULL , label , false );
309 UMASetMenuTitle( m_hMenu , title ) ;
310 }
311 bool wxMenu::ProcessCommand(wxCommandEvent & event)
312 {
313 bool processed = FALSE;
314
315 #if WXWIN_COMPATIBILITY
316 // Try a callback
317 if (m_callback)
318 {
319 (void)(*(m_callback))(*this, event);
320 processed = TRUE;
321 }
322 #endif WXWIN_COMPATIBILITY
323
324 // Try the menu's event handler
325 if ( !processed && GetEventHandler())
326 {
327 processed = GetEventHandler()->ProcessEvent(event);
328 }
329
330 // Try the window the menu was popped up from (and up through the
331 // hierarchy)
332 wxWindow *win = GetInvokingWindow();
333 if ( !processed && win )
334 processed = win->GetEventHandler()->ProcessEvent(event);
335
336 return processed;
337 }
338
339
340 // ---------------------------------------------------------------------------
341 // other
342 // ---------------------------------------------------------------------------
343
344 void wxMenu::Attach(wxMenuBar *menubar)
345 {
346 // menu can be in at most one menubar because otherwise they would both
347 // delete the menu pointer
348 wxASSERT_MSG( !m_menuBar, wxT("menu belongs to 2 menubars, expect a crash") );
349
350 m_menuBar = menubar;
351 }
352
353 void wxMenu::Detach()
354 {
355 wxASSERT_MSG( m_menuBar, wxT("can't detach menu if it's not attached") );
356
357 m_menuBar = NULL;
358 }
359
360 wxWindow *wxMenu::GetWindow() const
361 {
362 if ( m_invokingWindow != NULL )
363 return m_invokingWindow;
364 else if ( m_menuBar != NULL)
365 return m_menuBar->GetFrame();
366
367 return NULL;
368 }
369
370 // helper functions returning the mac menu position for a certain item, note that this is
371 // mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0
372
373 int wxMenu::MacGetIndexFromId( int id )
374 {
375 size_t pos;
376 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
377 for ( pos = 0; node; pos++ )
378 {
379 if ( node->GetData()->GetId() == id )
380 break;
381
382 node = node->GetNext();
383 }
384
385 if (!node)
386 return 0;
387
388 return pos + 1 ;
389 }
390
391 int wxMenu::MacGetIndexFromItem( wxMenuItem *pItem )
392 {
393 size_t pos;
394 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
395 for ( pos = 0; node; pos++ )
396 {
397 if ( node->GetData() == pItem )
398 break;
399
400 node = node->GetNext();
401 }
402
403 if (!node)
404 return 0;
405
406 return pos + 1 ;
407 }
408
409 void wxMenu::MacEnableMenu( bool bDoEnable )
410 {
411 if ( bDoEnable )
412 UMAEnableMenuItem( m_hMenu , 0 ) ;
413 else
414 UMADisableMenuItem( m_hMenu , 0 ) ;
415
416 ::DrawMenuBar() ;
417 }
418
419 bool wxMenu::MacMenuSelect( wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum )
420 {
421 int pos;
422 wxNode *node;
423
424 if ( m_macMenuId == macMenuId )
425 {
426 node = GetMenuItems().Nth(macMenuItemNum-1);
427 if (node)
428 {
429 wxMenuItem *pItem = (wxMenuItem*)node->Data();
430
431 if (pItem->IsCheckable())
432 pItem->Check(! pItem->IsChecked());
433
434 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, pItem->GetId());
435 event.m_timeStamp = when;
436 event.SetEventObject(handler);
437 event.SetInt( pItem->GetId() );
438 {
439 bool processed = false ;
440
441 #if WXWIN_COMPATIBILITY
442 // Try a callback
443 if (m_callback)
444 {
445 (void) (*(m_callback)) (*this, event);
446 processed = TRUE;
447 }
448 #endif
449 // Try the menu's event handler
450 if ( !processed && handler)
451 {
452 processed = handler->ProcessEvent(event);
453 }
454
455 // Try the window the menu was popped up from (and up
456 // through the hierarchy)
457 if ( !processed && GetInvokingWindow())
458 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
459 }
460 return true ;
461 }
462 }
463 else if ( macMenuId == kHMHelpMenuID )
464 {
465 int menuItem = formerHelpMenuItems ;
466 for (pos = 0, node = GetMenuItems().First(); node; node = node->Next(), pos++)
467 {
468 wxMenuItem * pItem = (wxMenuItem *) node->Data() ;
469
470 wxMenu *pSubMenu = pItem->GetSubMenu() ;
471 if ( pSubMenu != NULL )
472 {
473 }
474 else
475 {
476 if ( pItem->GetId() != wxApp::s_macAboutMenuItemId )
477 ++menuItem ;
478
479 if ( menuItem == macMenuItemNum )
480 {
481 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, pItem->GetId());
482 event.m_timeStamp = when;
483 event.SetEventObject(handler);
484 event.SetInt( pItem->GetId() );
485 {
486 bool processed = false ;
487 #if WXWIN_COMPATIBILITY
488 // Try a callback
489 if (m_callback)
490 {
491 (void) (*(m_callback)) (*this, event);
492 processed = TRUE;
493 }
494 #endif
495 // Try the menu's event handler
496 if ( !processed && handler)
497 {
498 processed = handler->ProcessEvent(event);
499 }
500
501 // Try the window the menu was popped up from (and up
502 // through the hierarchy)
503 if ( !processed && GetInvokingWindow())
504 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
505 }
506 return true ;
507 }
508 }
509 }
510 }
511
512 for (pos = 0, node = GetMenuItems().First(); node; node = node->Next(), pos++)
513 {
514 wxMenuItem * pItem = (wxMenuItem *) node->Data() ;
515
516 wxMenu *pSubMenu = pItem->GetSubMenu() ;
517 if ( pSubMenu != NULL )
518 {
519 if ( pSubMenu->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
520 return true ;
521 }
522 }
523
524 return false ;
525 }
526
527 // Menu Bar
528
529 /*
530
531 Mac Implementation note :
532
533 The Mac has only one global menubar, so we attempt to install the currently
534 active menubar from a frame, we currently don't take into account mdi-frames
535 which would ask for menu-merging
536
537 Secondly there is no mac api for changing a menubar that is not the current
538 menubar, so we have to wait for preparing the actual menubar until the
539 wxMenubar is to be used
540
541 We can in subsequent versions use MacInstallMenuBar to provide some sort of
542 auto-merge for MDI in case this will be necessary
543
544 */
545
546 wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
547
548 void wxMenuBar::Init()
549 {
550 m_eventHandler = this;
551 m_menuBarFrame = NULL;
552 }
553
554 wxMenuBar::wxMenuBar()
555 {
556 Init();
557 }
558
559 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
560 {
561 Init();
562 }
563
564
565 wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
566 {
567 Init();
568
569 m_titles.Alloc(count);
570
571 for ( int i = 0; i < count; i++ )
572 {
573 m_menus.Append(menus[i]);
574 m_titles.Add(titles[i]);
575
576 menus[i]->Attach(this);
577 }
578 }
579
580 wxMenuBar::~wxMenuBar()
581 {
582 if (s_macInstalledMenuBar == this)
583 {
584 ::ClearMenuBar();
585 s_macInstalledMenuBar = NULL;
586 }
587
588 }
589
590 void wxMenuBar::Refresh()
591 {
592 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
593
594 DrawMenuBar();
595 }
596
597 #if wxUSE_ACCEL
598
599 void wxMenuBar::RebuildAccelTable()
600 {
601 // merge the accelerators of all menus into one accel table
602 size_t nAccelCount = 0;
603 size_t i, count = GetMenuCount();
604 for ( i = 0; i < count; i++ )
605 {
606 nAccelCount += m_menus[i]->GetAccelCount();
607 }
608
609 if ( nAccelCount )
610 {
611 wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
612
613 nAccelCount = 0;
614 for ( i = 0; i < count; i++ )
615 {
616 nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]);
617 }
618
619 m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries);
620
621 delete [] accelEntries;
622 }
623 }
624
625 #endif // wxUSE_ACCEL
626
627
628 void wxMenuBar::MacInstallMenuBar()
629 {
630 Handle menubar = ::GetNewMBar( kwxMacMenuBarResource ) ;
631 wxString message ;
632 wxCHECK_RET( menubar != NULL, "can't read MBAR resource" );
633 ::SetMenuBar( menubar ) ;
634 ::DisposeHandle( menubar ) ;
635
636 MenuHandle menu = ::GetMenuHandle( kwxMacAppleMenuId ) ;
637 ::AppendResMenu(menu, 'DRVR');
638
639 for (int i = 0; i < m_menus.GetCount(); i++)
640 {
641 Str255 label;
642 wxNode *node;
643 wxMenuItem *item;
644 int pos ;
645 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
646
647 #if !TARGET_CARBON
648 /* the help menu does not exist in CARBON anymore */
649 if( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName )
650 {
651 MenuHandle mh = NULL ;
652 if ( HMGetHelpMenuHandle( &mh ) != noErr )
653 {
654 continue ;
655 }
656 if ( formerHelpMenuItems == 0 )
657 {
658 if( mh )
659 formerHelpMenuItems = CountMenuItems( mh ) ;
660 }
661
662 for (pos = 0 , node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
663 {
664 item = (wxMenuItem *)node->Data();
665 subMenu = item->GetSubMenu() ;
666 if (subMenu)
667 {
668 // we don't support hierarchical menus in the help menu yet
669 }
670 else
671 {
672 if ( item->IsSeparator() )
673 {
674 if ( mh )
675 UMAAppendMenuItem(mh, "\p-" );
676 }
677 else
678 {
679 Str255 label ;
680 UInt8 modifiers ;
681 SInt16 key ;
682 wxMenuItem::MacBuildMenuString( label, &key , &modifiers , item->GetText(), item->GetId() != wxApp::s_macAboutMenuItemId); // no shortcut in about menu
683 if ( label[0] == 0 )
684 {
685 // we cannot add empty menus on mac
686 label[0] = 1 ;
687 label[1] = ' ' ;
688 }
689 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
690 {
691 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , label );
692 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 );
693 }
694 else
695 {
696 if ( mh )
697 UMAAppendMenuItem(mh, label , key , modifiers );
698 }
699 }
700 }
701 }
702 }
703 else
704 #endif
705 {
706 wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_titles[i] , false );
707 UMASetMenuTitle( menu->GetHMenu() , label ) ;
708 for (pos = 0, node = menu->GetMenuItems().First(); node; node = node->Next(), pos++)
709 {
710 item = (wxMenuItem *)node->Data();
711 subMenu = item->GetSubMenu() ;
712 if (subMenu)
713 {
714 UMAInsertMenu( subMenu->GetHMenu() , -1 ) ;
715 }
716 }
717 UMAInsertMenu(m_menus[i]->GetHMenu(), 0);
718 }
719 }
720 UMADrawMenuBar() ;
721
722 s_macInstalledMenuBar = this;
723 }
724
725 void wxMenuBar::EnableTop(size_t pos, bool enable)
726 {
727 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
728 m_menus[pos]->MacEnableMenu( enable ) ;
729 Refresh();
730 }
731
732 void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
733 {
734 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
735
736 m_titles[pos] = label;
737
738 if ( !IsAttached() )
739 {
740 return;
741 }
742
743 m_menus[pos]->SetTitle( label ) ;
744 if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ?
745 {
746 ::SetMenuBar( GetMenuBar() ) ;
747 ::InvalMenuBar() ;
748 }
749 }
750
751 wxString wxMenuBar::GetLabelTop(size_t pos) const
752 {
753 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
754 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
755
756 return m_titles[pos];
757 }
758
759 int wxMenuBar::FindMenu(const wxString& title)
760 {
761 wxString menuTitle = wxStripMenuCodes(title);
762
763 size_t count = GetMenuCount();
764 for ( size_t i = 0; i < count; i++ )
765 {
766 wxString title = wxStripMenuCodes(m_titles[i]);
767 if ( menuTitle == title )
768 return i;
769 }
770
771 return wxNOT_FOUND;
772
773 }
774
775
776 // ---------------------------------------------------------------------------
777 // wxMenuBar construction
778 // ---------------------------------------------------------------------------
779
780 // ---------------------------------------------------------------------------
781 // wxMenuBar construction
782 // ---------------------------------------------------------------------------
783
784 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
785 {
786 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
787 if ( !menuOld )
788 return FALSE;
789 m_titles[pos] = title;
790
791 if ( IsAttached() )
792 {
793 if (s_macInstalledMenuBar == this)
794 {
795 UMADeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
796 {
797 Str255 label;
798 wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false );
799 UMASetMenuTitle( menu->GetHMenu() , label ) ;
800 if ( pos == m_menus.GetCount() - 1)
801 {
802 UMAInsertMenu( menu->GetHMenu() , 0 ) ;
803 }
804 else
805 {
806 UMAInsertMenu( menu->GetHMenu() , m_menus[pos+1]->MacGetMenuId() ) ;
807 }
808 }
809 }
810
811
812 #if wxUSE_ACCEL
813 if ( menuOld->HasAccels() || menu->HasAccels() )
814 {
815 // need to rebuild accell table
816 RebuildAccelTable();
817 }
818 #endif // wxUSE_ACCEL
819
820 Refresh();
821 }
822
823 return menuOld;
824 }
825
826 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
827 {
828 if ( !wxMenuBarBase::Insert(pos, menu, title) )
829 return FALSE;
830
831 m_titles.Insert(title, pos);
832
833 menu->Attach(this);
834
835 if ( IsAttached() )
836 {
837 if ( pos == (size_t) -1 )
838 {
839 ::InsertMenu( menu->GetHMenu() , 0 ) ;
840 }
841 else
842 {
843 ::InsertMenu( menu->GetHMenu() , m_menus[pos+1]->MacGetMenuId() ) ;
844 }
845
846 #if wxUSE_ACCEL
847 if ( menu->HasAccels() )
848 {
849 // need to rebuild accell table
850 RebuildAccelTable();
851 }
852 #endif // wxUSE_ACCEL
853
854 Refresh();
855 }
856
857 return TRUE;
858 }
859
860 void wxMenuBar::MacMenuSelect(wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum)
861 {
862 // first scan fast for direct commands, i.e. menus which have these commands directly in their own list
863
864 if ( macMenuId == kwxMacAppleMenuId && macMenuItemNum == 1 )
865 {
866 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, wxApp::s_macAboutMenuItemId );
867 event.m_timeStamp = when;
868 event.SetEventObject(handler);
869 event.SetInt( wxApp::s_macAboutMenuItemId );
870 handler->ProcessEvent(event);
871 }
872 else
873 {
874 for (int i = 0; i < m_menus.GetCount() ; i++)
875 {
876 if ( m_menus[i]->MacGetMenuId() == macMenuId ||
877 ( macMenuId == kHMHelpMenuID && ( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName ) )
878 )
879 {
880 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
881 return ;
882 else
883 {
884 //TODO flag this as an error since it must contain the item
885 return ;
886 }
887 }
888 }
889
890 for (int i = 0; i < m_menus.GetCount(); i++)
891 {
892 if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) )
893 {
894 break ;
895 }
896 }
897 }
898 }
899
900 wxMenu *wxMenuBar::Remove(size_t pos)
901 {
902 wxMenu *menu = wxMenuBarBase::Remove(pos);
903 if ( !menu )
904 return NULL;
905
906 if ( IsAttached() )
907 {
908 if (s_macInstalledMenuBar == this)
909 {
910 ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
911 }
912
913 menu->Detach();
914
915 #if wxUSE_ACCEL
916 if ( menu->HasAccels() )
917 {
918 // need to rebuild accell table
919 RebuildAccelTable();
920 }
921 #endif // wxUSE_ACCEL
922
923 Refresh();
924 }
925
926 m_titles.Remove(pos);
927
928 return menu;
929 }
930
931 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
932 {
933 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
934 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
935
936 if ( !wxMenuBarBase::Append(menu, title) )
937 return FALSE;
938
939 menu->Attach(this);
940
941 m_titles.Add(title);
942
943 if ( IsAttached() )
944 {
945 if (s_macInstalledMenuBar == this)
946 {
947 ::InsertMenu( menu->GetHMenu() , 0 ) ;
948 }
949
950 #if wxUSE_ACCEL
951 if ( menu->HasAccels() )
952 {
953 // need to rebuild accell table
954 RebuildAccelTable();
955 }
956 #endif // wxUSE_ACCEL
957
958 Refresh();
959 }
960
961 return TRUE;
962 }
963
964 void wxMenuBar::Attach(wxFrame *frame)
965 {
966 // wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
967
968 m_menuBarFrame = frame;
969
970 #if wxUSE_ACCEL
971 RebuildAccelTable();
972 #endif // wxUSE_ACCEL
973 }
974 // ---------------------------------------------------------------------------
975 // wxMenuBar searching for menu items
976 // ---------------------------------------------------------------------------
977
978 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
979 int wxMenuBar::FindMenuItem(const wxString& menuString,
980 const wxString& itemString) const
981 {
982 wxString menuLabel = wxStripMenuCodes(menuString);
983 size_t count = GetMenuCount();
984 for ( size_t i = 0; i < count; i++ )
985 {
986 wxString title = wxStripMenuCodes(m_titles[i]);
987 if ( menuString == title )
988 return m_menus[i]->FindItem(itemString);
989 }
990
991 return wxNOT_FOUND;
992 }
993
994 wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
995 {
996 if ( itemMenu )
997 *itemMenu = NULL;
998
999 wxMenuItem *item = NULL;
1000 size_t count = GetMenuCount();
1001 for ( size_t i = 0; !item && (i < count); i++ )
1002 {
1003 item = m_menus[i]->FindItem(id, itemMenu);
1004 }
1005
1006 return item;
1007 }
1008
1009