]> git.saurik.com Git - wxWidgets.git/blame - src/common/menucmn.cpp
assert is raised when using the thread sample (which works) so the test is
[wxWidgets.git] / src / common / menucmn.cpp
CommitLineData
3dfac970
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: common/menucmn.cpp
3// Purpose: wxMenu and wxMenuBar methods common to all ports
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 26.10.99
7// RCS-ID: $Id$
8// Copyright: (c) wxWindows team
55d99c7a 9// Licence: wxWindows licence
3dfac970
VZ
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation "menubase.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
1e6feb95
VZ
31#if wxUSE_MENUS
32
33#include <ctype.h>
34
3dfac970 35#ifndef WX_PRECOMP
1e6feb95
VZ
36 #include "wx/intl.h"
37 #include "wx/log.h"
3dfac970
VZ
38 #include "wx/menu.h"
39#endif
40
41// ----------------------------------------------------------------------------
42// template lists
43// ----------------------------------------------------------------------------
44
45#include "wx/listimpl.cpp"
717a57c2 46
3dfac970 47WX_DEFINE_LIST(wxMenuList);
717a57c2 48WX_DEFINE_LIST(wxMenuItemList);
3dfac970
VZ
49
50// ============================================================================
51// implementation
52// ============================================================================
53
54// ----------------------------------------------------------------------------
717a57c2
VZ
55// wxMenuItem
56// ----------------------------------------------------------------------------
57
d65c269b
VZ
58wxMenuItemBase::wxMenuItemBase(wxMenu *parentMenu,
59 int id,
60 const wxString& text,
61 const wxString& help,
62 wxItemKind kind,
63 wxMenu *subMenu)
64 : m_text(text),
65 m_help(help)
66{
67 wxASSERT_MSG( parentMenu != NULL, wxT("menuitem should have a menu") );
68
69 m_parentMenu = parentMenu;
70 m_subMenu = subMenu;
71 m_isEnabled = TRUE;
72 m_isChecked = FALSE;
73 m_id = id;
74 m_kind = kind;
75}
76
717a57c2
VZ
77wxMenuItemBase::~wxMenuItemBase()
78{
1e6feb95 79 delete m_subMenu;
717a57c2
VZ
80}
81
82#if wxUSE_ACCEL
83
1e6feb95
VZ
84// return wxAcceleratorEntry for the given menu string or NULL if none
85// specified
86wxAcceleratorEntry *wxGetAccelFromString(const wxString& label)
87{
88 // check for accelerators: they are given after '\t'
89 int posTab = label.Find(wxT('\t'));
90 if ( posTab != wxNOT_FOUND ) {
91 // parse the accelerator string
92 int keyCode = 0;
93 int accelFlags = wxACCEL_NORMAL;
94 wxString current;
95 for ( size_t n = (size_t)posTab + 1; n < label.Len(); n++ ) {
96 if ( (label[n] == '+') || (label[n] == '-') ) {
97 if ( current == _("ctrl") )
98 accelFlags |= wxACCEL_CTRL;
99 else if ( current == _("alt") )
100 accelFlags |= wxACCEL_ALT;
101 else if ( current == _("shift") )
102 accelFlags |= wxACCEL_SHIFT;
103 else {
a070d8ce
VZ
104 // we may have "Ctrl-+", for example, but we still want to
105 // catch typos like "Crtl-A" so only give the warning if we
106 // have something before the current '+' or '-', else take
107 // it as a literal symbol
108 if ( current.empty() )
109 {
110 current += label[n];
111
112 // skip clearing it below
113 continue;
114 }
115 else
116 {
117 wxLogDebug(wxT("Unknown accel modifier: '%s'"),
118 current.c_str());
119 }
1e6feb95
VZ
120 }
121
a070d8ce 122 current.clear();
1e6feb95
VZ
123 }
124 else {
125 current += wxTolower(label[n]);
126 }
127 }
128
129 if ( current.IsEmpty() ) {
130 wxLogDebug(wxT("No accel key found, accel string ignored."));
131 }
132 else {
133 if ( current.Len() == 1 ) {
134 // it's a letter
c921fd59
GD
135 keyCode = current[0U];
136
137 // Only call wxToupper if control, alt, or shift is held down,
138 // otherwise lower case accelerators won't work.
139 if (accelFlags != wxACCEL_NORMAL) {
140 keyCode = wxToupper(keyCode);
141 }
1e6feb95
VZ
142 }
143 else {
144 // is it a function key?
145 if ( current[0U] == 'f' && isdigit(current[1U]) &&
146 (current.Len() == 2 ||
147 (current.Len() == 3 && isdigit(current[2U]))) ) {
148 int n;
149 wxSscanf(current.c_str() + 1, wxT("%d"), &n);
150
151 keyCode = WXK_F1 + n - 1;
152 }
153 else {
154 // several special cases
155 current.MakeUpper();
41b78190 156 if ( current == wxT("DEL") )
1e6feb95 157 keyCode = WXK_DELETE;
41b78190 158 else if ( current == wxT("DELETE") )
1e6feb95 159 keyCode = WXK_DELETE;
41b78190 160 else if ( current == wxT("INS") )
1e6feb95 161 keyCode = WXK_INSERT;
41b78190 162 else if ( current == wxT("INSERT") )
1e6feb95 163 keyCode = WXK_INSERT;
41b78190 164 else if ( current == wxT("ENTER") || current == wxT("RETURN") )
2b5f62a0 165 keyCode = WXK_RETURN;
41b78190 166 else if ( current == wxT("PGUP") )
2b5f62a0 167 keyCode = WXK_PRIOR;
41b78190 168 else if ( current == wxT("PGDN") )
2b5f62a0 169 keyCode = WXK_NEXT;
41b78190 170 else if ( current == wxT("LEFT") )
2b5f62a0 171 keyCode = WXK_LEFT;
41b78190 172 else if ( current == wxT("RIGHT") )
2b5f62a0 173 keyCode = WXK_RIGHT;
41b78190 174 else if ( current == wxT("UP") )
2b5f62a0 175 keyCode = WXK_UP;
41b78190 176 else if ( current == wxT("DOWN") )
2b5f62a0 177 keyCode = WXK_DOWN;
41b78190 178 else if ( current == wxT("HOME") )
2b5f62a0 179 keyCode = WXK_HOME;
41b78190 180 else if ( current == wxT("END") )
2b5f62a0 181 keyCode = WXK_END;
41b78190 182 else if ( current == wxT("SPACE") )
2b5f62a0 183 keyCode = WXK_SPACE;
41b78190 184 else if ( current == wxT("TAB") )
2b5f62a0 185 keyCode = WXK_TAB;
73baf01a 186 else if ( current == wxT("ESC") || current == wxT("ESCAPE") )
41b78190 187 keyCode = WXK_ESCAPE;
1e6feb95
VZ
188 else
189 {
190 wxLogDebug(wxT("Unrecognized accel key '%s', accel string ignored."),
191 current.c_str());
192 }
193 }
194 }
195 }
196
197 if ( keyCode ) {
198 // we do have something
199 return new wxAcceleratorEntry(accelFlags, keyCode);
200 }
201 }
202
203 return (wxAcceleratorEntry *)NULL;
204}
205
206wxAcceleratorEntry *wxMenuItemBase::GetAccel() const
207{
208 return wxGetAccelFromString(GetText());
209}
210
717a57c2
VZ
211void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel)
212{
213 wxString text = m_text.BeforeFirst(wxT('\t'));
214 if ( accel )
215 {
216 text += wxT('\t');
217
218 int flags = accel->GetFlags();
219 if ( flags & wxACCEL_ALT )
220 text += wxT("Alt-");
221 if ( flags & wxACCEL_CTRL )
222 text += wxT("Ctrl-");
223 if ( flags & wxACCEL_SHIFT )
224 text += wxT("Shift-");
225
226 int code = accel->GetKeyCode();
227 switch ( code )
228 {
229 case WXK_F1:
230 case WXK_F2:
231 case WXK_F3:
232 case WXK_F4:
233 case WXK_F5:
234 case WXK_F6:
235 case WXK_F7:
236 case WXK_F8:
237 case WXK_F9:
238 case WXK_F10:
239 case WXK_F11:
240 case WXK_F12:
241 text << wxT('F') << code - WXK_F1 + 1;
242 break;
243
244 // if there are any other keys wxGetAccelFromString() may return,
245 // we should process them here
246
247 default:
248 if ( wxIsalnum(code) )
249 {
250 text << (wxChar)code;
251
252 break;
253 }
254
255 wxFAIL_MSG( wxT("unknown keyboard accel") );
256 }
257 }
258
259 SetText(text);
260}
261
262#endif // wxUSE_ACCEL
263
264// ----------------------------------------------------------------------------
265// wxMenu ctor and dtor
266// ----------------------------------------------------------------------------
267
268void wxMenuBase::Init(long style)
269{
270 m_items.DeleteContents(TRUE);
271
272 m_menuBar = (wxMenuBar *)NULL;
273 m_menuParent = (wxMenu *)NULL;
274
275 m_invokingWindow = (wxWindow *)NULL;
276 m_style = style;
277 m_clientData = (void *)NULL;
278 m_eventHandler = this;
9739d9ee
VZ
279
280#if wxUSE_MENU_CALLBACK
5b0d48b3 281 m_callback = (wxFunction) NULL;
9739d9ee 282#endif // wxUSE_MENU_CALLBACK
717a57c2
VZ
283}
284
285wxMenuBase::~wxMenuBase()
286{
a583e623 287 // nothing to do, wxMenuItemList dtor will delete the menu items.
1e6feb95
VZ
288
289 // Actually, in GTK, the submenus have to get deleted first.
717a57c2
VZ
290}
291
292// ----------------------------------------------------------------------------
293// wxMenu item adding/removing
294// ----------------------------------------------------------------------------
295
1e6feb95
VZ
296void wxMenuBase::AddSubMenu(wxMenu *submenu)
297{
298 wxCHECK_RET( submenu, _T("can't add a NULL submenu") );
299
300 if ( m_menuBar )
301 {
302 submenu->Attach(m_menuBar);
303 }
304
305 submenu->SetParent((wxMenu *)this);
306}
307
717a57c2
VZ
308bool wxMenuBase::DoAppend(wxMenuItem *item)
309{
310 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Append()") );
311
312 m_items.Append(item);
1e6feb95
VZ
313 if ( item->IsSubMenu() )
314 {
315 AddSubMenu(item->GetSubMenu());
316 }
717a57c2
VZ
317
318 return TRUE;
319}
320
321bool wxMenuBase::Insert(size_t pos, wxMenuItem *item)
322{
323 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Insert") );
717a57c2 324
32db328c
VZ
325 if ( pos == GetMenuItemCount() )
326 {
327 return DoAppend(item);
328 }
329 else
330 {
331 wxCHECK_MSG( pos < GetMenuItemCount(), FALSE,
332 wxT("invalid index in wxMenu::Insert") );
333
334 return DoInsert(pos, item);
335 }
717a57c2
VZ
336}
337
338bool wxMenuBase::DoInsert(size_t pos, wxMenuItem *item)
339{
340 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Insert()") );
341
342 wxMenuItemList::Node *node = m_items.Item(pos);
343 wxCHECK_MSG( node, FALSE, wxT("invalid index in wxMenu::Insert()") );
344
345 m_items.Insert(node, item);
1e6feb95
VZ
346 if ( item->IsSubMenu() )
347 {
348 AddSubMenu(item->GetSubMenu());
349 }
717a57c2
VZ
350
351 return TRUE;
352}
353
354wxMenuItem *wxMenuBase::Remove(wxMenuItem *item)
355{
356 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Remove") );
357
358 return DoRemove(item);
359}
360
361wxMenuItem *wxMenuBase::DoRemove(wxMenuItem *item)
362{
363 wxMenuItemList::Node *node = m_items.Find(item);
364
365 // if we get here, the item is valid or one of Remove() functions is broken
366 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
367
368 // we detach the item, but we do delete the list node (i.e. don't call
369 // DetachNode() here!)
370 node->SetData((wxMenuItem *)NULL); // to prevent it from deleting the item
371 m_items.DeleteNode(node);
372
373 // item isn't attached to anything any more
374 wxMenu *submenu = item->GetSubMenu();
375 if ( submenu )
376 {
377 submenu->SetParent((wxMenu *)NULL);
378 }
379
380 return item;
381}
382
383bool wxMenuBase::Delete(wxMenuItem *item)
384{
39d03faf 385 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Delete") );
717a57c2
VZ
386
387 return DoDelete(item);
388}
389
390bool wxMenuBase::DoDelete(wxMenuItem *item)
391{
392 wxMenuItem *item2 = DoRemove(item);
393 wxCHECK_MSG( item2, FALSE, wxT("failed to delete menu item") );
394
395 // don't delete the submenu
396 item2->SetSubMenu((wxMenu *)NULL);
397
398 delete item2;
399
400 return TRUE;
401}
402
403bool wxMenuBase::Destroy(wxMenuItem *item)
404{
39d03faf 405 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Destroy") );
717a57c2
VZ
406
407 return DoDestroy(item);
408}
409
410bool wxMenuBase::DoDestroy(wxMenuItem *item)
411{
412 wxMenuItem *item2 = DoRemove(item);
413 wxCHECK_MSG( item2, FALSE, wxT("failed to delete menu item") );
414
415 delete item2;
416
417 return TRUE;
418}
419
420// ----------------------------------------------------------------------------
421// wxMenu searching for items
422// ----------------------------------------------------------------------------
423
424// Finds the item id matching the given string, -1 if not found.
425int wxMenuBase::FindItem(const wxString& text) const
426{
3b59cdbf 427 wxString label = wxMenuItem::GetLabelFromText(text);
717a57c2
VZ
428 for ( wxMenuItemList::Node *node = m_items.GetFirst();
429 node;
430 node = node->GetNext() )
431 {
432 wxMenuItem *item = node->GetData();
433 if ( item->IsSubMenu() )
434 {
435 int rc = item->GetSubMenu()->FindItem(label);
436 if ( rc != wxNOT_FOUND )
437 return rc;
438 }
adb21613
VZ
439
440 // we execute this code for submenus as well to alllow finding them by
441 // name just like the ordinary items
442 if ( !item->IsSeparator() )
717a57c2
VZ
443 {
444 if ( item->GetLabel() == label )
445 return item->GetId();
446 }
447 }
448
449 return wxNOT_FOUND;
450}
451
452// recursive search for item by id
453wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const
454{
455 if ( itemMenu )
456 *itemMenu = NULL;
457
458 wxMenuItem *item = NULL;
459 for ( wxMenuItemList::Node *node = m_items.GetFirst();
460 node && !item;
461 node = node->GetNext() )
462 {
463 item = node->GetData();
464
465 if ( item->GetId() == itemId )
466 {
467 if ( itemMenu )
468 *itemMenu = (wxMenu *)this;
469 }
470 else if ( item->IsSubMenu() )
471 {
472 item = item->GetSubMenu()->FindItem(itemId, itemMenu);
473 }
474 else
475 {
476 // don't exit the loop
477 item = NULL;
478 }
479 }
480
481 return item;
482}
483
484// non recursive search
485wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const
486{
487 wxMenuItem *item = (wxMenuItem *)NULL;
488 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
489
490 size_t pos;
491 for ( pos = 0; node; pos++ )
492 {
1dddf838
VZ
493 if ( node->GetData()->GetId() == id )
494 {
495 item = node->GetData();
496
717a57c2 497 break;
1dddf838 498 }
717a57c2
VZ
499
500 node = node->GetNext();
501 }
502
503 if ( ppos )
504 {
1987af7e 505 *ppos = item ? pos : (size_t)wxNOT_FOUND;
717a57c2
VZ
506 }
507
508 return item;
509}
510
511// ----------------------------------------------------------------------------
1e6feb95 512// wxMenu helpers used by derived classes
717a57c2
VZ
513// ----------------------------------------------------------------------------
514
515// Update a menu and all submenus recursively. source is the object that has
516// the update event handlers defined for it. If NULL, the menu or associated
517// window will be used.
518void wxMenuBase::UpdateUI(wxEvtHandler* source)
519{
520 if ( !source && GetInvokingWindow() )
521 source = GetInvokingWindow()->GetEventHandler();
522 if ( !source )
523 source = GetEventHandler();
524 if ( !source )
525 source = this;
526
527 wxMenuItemList::Node* node = GetMenuItems().GetFirst();
528 while ( node )
529 {
530 wxMenuItem* item = node->GetData();
531 if ( !item->IsSeparator() )
532 {
533 wxWindowID id = item->GetId();
534 wxUpdateUIEvent event(id);
535 event.SetEventObject( source );
536
537 if ( source->ProcessEvent(event) )
538 {
539 // if anything changed, update the chanegd attribute
540 if (event.GetSetText())
541 SetLabel(id, event.GetText());
542 if (event.GetSetChecked())
543 Check(id, event.GetChecked());
544 if (event.GetSetEnabled())
545 Enable(id, event.GetEnabled());
546 }
547
548 // recurse to the submenus
549 if ( item->GetSubMenu() )
550 item->GetSubMenu()->UpdateUI(source);
551 }
552 //else: item is a separator (which don't process update UI events)
553
554 node = node->GetNext();
555 }
556}
557
1e6feb95
VZ
558bool wxMenuBase::SendEvent(int id, int checked)
559{
560 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id);
561 event.SetEventObject(this);
562 event.SetInt(checked);
563
564 bool processed = FALSE;
565
566#if wxUSE_MENU_CALLBACK
567 // Try a callback
568 if (m_callback)
569 {
570 (void)(*(m_callback))(*this, event);
571 processed = TRUE;
572 }
573#endif // wxUSE_MENU_CALLBACK
574
575 // Try the menu's event handler
576 if ( !processed )
577 {
578 wxEvtHandler *handler = GetEventHandler();
579 if ( handler )
580 processed = handler->ProcessEvent(event);
581 }
582
583 // Try the window the menu was popped up from (and up through the
584 // hierarchy)
585 if ( !processed )
586 {
587 const wxMenuBase *menu = this;
588 while ( menu )
589 {
590 wxWindow *win = menu->GetInvokingWindow();
591 if ( win )
592 {
593 processed = win->GetEventHandler()->ProcessEvent(event);
594 break;
595 }
596
597 menu = menu->GetParent();
598 }
599 }
600
601 return processed;
602}
603
604// ----------------------------------------------------------------------------
605// wxMenu attaching/detaching to/from menu bar
606// ----------------------------------------------------------------------------
607
608void wxMenuBase::Attach(wxMenuBarBase *menubar)
609{
610 // use Detach() instead!
611 wxASSERT_MSG( menubar, _T("menu can't be attached to NULL menubar") );
612
613 // use IsAttached() to prevent this from happening
614 wxASSERT_MSG( !m_menuBar, _T("attaching menu twice?") );
615
616 m_menuBar = (wxMenuBar *)menubar;
617}
618
619void wxMenuBase::Detach()
620{
621 // use IsAttached() to prevent this from happening
622 wxASSERT_MSG( m_menuBar, _T("detaching unattached menu?") );
623
624 m_menuBar = NULL;
625}
626
717a57c2
VZ
627// ----------------------------------------------------------------------------
628// wxMenu functions forwarded to wxMenuItem
629// ----------------------------------------------------------------------------
630
631void wxMenuBase::Enable( int id, bool enable )
632{
633 wxMenuItem *item = FindItem(id);
634
635 wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") );
636
637 item->Enable(enable);
638}
639
640bool wxMenuBase::IsEnabled( int id ) const
641{
642 wxMenuItem *item = FindItem(id);
643
644 wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsEnabled: no such item") );
645
646 return item->IsEnabled();
647}
648
649void wxMenuBase::Check( int id, bool enable )
650{
651 wxMenuItem *item = FindItem(id);
652
653 wxCHECK_RET( item, wxT("wxMenu::Check: no such item") );
654
655 item->Check(enable);
656}
657
658bool wxMenuBase::IsChecked( int id ) const
659{
660 wxMenuItem *item = FindItem(id);
661
662 wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsChecked: no such item") );
663
664 return item->IsChecked();
665}
666
667void wxMenuBase::SetLabel( int id, const wxString &label )
668{
669 wxMenuItem *item = FindItem(id);
670
671 wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") );
672
673 item->SetText(label);
674}
675
676wxString wxMenuBase::GetLabel( int id ) const
677{
678 wxMenuItem *item = FindItem(id);
679
680 wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetLabel: no such item") );
681
682 return item->GetText();
683}
684
685void wxMenuBase::SetHelpString( int id, const wxString& helpString )
686{
687 wxMenuItem *item = FindItem(id);
688
689 wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") );
690
691 item->SetHelp( helpString );
692}
693
694wxString wxMenuBase::GetHelpString( int id ) const
695{
696 wxMenuItem *item = FindItem(id);
697
698 wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetHelpString: no such item") );
699
700 return item->GetHelp();
701}
702
703// ----------------------------------------------------------------------------
704// wxMenuBarBase ctor and dtor
3dfac970
VZ
705// ----------------------------------------------------------------------------
706
707wxMenuBarBase::wxMenuBarBase()
708{
709 // we own the menus when we get them
710 m_menus.DeleteContents(TRUE);
1e6feb95
VZ
711
712 // not attached yet
713 m_menuBarFrame = NULL;
3dfac970
VZ
714}
715
716wxMenuBarBase::~wxMenuBarBase()
717{
718 // nothing to do, the list will delete the menus because of the call to
719 // DeleteContents() above
720}
721
722// ----------------------------------------------------------------------------
723// wxMenuBar item access: the base class versions manage m_menus list, the
724// derived class should reflect the changes in the real menubar
725// ----------------------------------------------------------------------------
726
727wxMenu *wxMenuBarBase::GetMenu(size_t pos) const
728{
729 wxMenuList::Node *node = m_menus.Item(pos);
730 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") );
731
732 return node->GetData();
733}
734
735bool wxMenuBarBase::Append(wxMenu *menu, const wxString& WXUNUSED(title))
736{
737 wxCHECK_MSG( menu, FALSE, wxT("can't append NULL menu") );
738
739 m_menus.Append(menu);
1e6feb95 740 menu->Attach(this);
3dfac970
VZ
741
742 return TRUE;
743}
744
745bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu,
32db328c 746 const wxString& title)
3dfac970 747{
32db328c
VZ
748 if ( pos == m_menus.GetCount() )
749 {
186baeb2 750 return wxMenuBarBase::Append(menu, title);
32db328c 751 }
1e6feb95 752 else // not at the end
32db328c
VZ
753 {
754 wxCHECK_MSG( menu, FALSE, wxT("can't insert NULL menu") );
3dfac970 755
32db328c
VZ
756 wxMenuList::Node *node = m_menus.Item(pos);
757 wxCHECK_MSG( node, FALSE, wxT("bad index in wxMenuBar::Insert()") );
3dfac970 758
32db328c 759 m_menus.Insert(node, menu);
1e6feb95 760 menu->Attach(this);
3dfac970 761
32db328c
VZ
762 return TRUE;
763 }
3dfac970
VZ
764}
765
766wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu,
767 const wxString& WXUNUSED(title))
768{
769 wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") );
770
771 wxMenuList::Node *node = m_menus.Item(pos);
772 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") );
773
774 wxMenu *menuOld = node->GetData();
775 node->SetData(menu);
776
1e6feb95
VZ
777 menu->Attach(this);
778 menuOld->Detach();
779
3dfac970
VZ
780 return menuOld;
781}
782
783wxMenu *wxMenuBarBase::Remove(size_t pos)
784{
785 wxMenuList::Node *node = m_menus.Item(pos);
786 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") );
787
788 node = m_menus.DetachNode(node);
789 wxCHECK( node, NULL ); // unexpected
790 wxMenu *menu = node->GetData();
1e6feb95 791 menu->Detach();
3dfac970
VZ
792
793 delete node;
794
795 return menu;
796}
797
270e8b6a 798int wxMenuBarBase::FindMenu(const wxString& title) const
52130557
VZ
799{
800 wxString label = wxMenuItem::GetLabelFromText(title);
801
802 size_t count = GetMenuCount();
803 for ( size_t i = 0; i < count; i++ )
804 {
805 wxString title2 = GetLabelTop(i);
806 if ( (title2 == title) ||
807 (wxMenuItem::GetLabelFromText(title2) == label) )
808 {
809 // found
2b5f62a0 810 return (int)i;
52130557
VZ
811 }
812 }
813
814 return wxNOT_FOUND;
815
816}
817
1e6feb95
VZ
818// ----------------------------------------------------------------------------
819// wxMenuBar attaching/detaching to/from the frame
820// ----------------------------------------------------------------------------
821
822void wxMenuBarBase::Attach(wxFrame *frame)
823{
824 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
825
826 m_menuBarFrame = frame;
827}
828
829void wxMenuBarBase::Detach()
830{
831 wxASSERT_MSG( IsAttached(), wxT("detaching unattached menubar") );
832
833 m_menuBarFrame = NULL;
834}
835
836// ----------------------------------------------------------------------------
837// wxMenuBar searching for items
838// ----------------------------------------------------------------------------
839
840wxMenuItem *wxMenuBarBase::FindItem(int id, wxMenu **menu) const
841{
842 if ( menu )
843 *menu = NULL;
844
845 wxMenuItem *item = NULL;
846 size_t count = GetMenuCount();
847 for ( size_t i = 0; !item && (i < count); i++ )
848 {
849 item = m_menus[i]->FindItem(id, menu);
850 }
851
852 return item;
853}
854
855int wxMenuBarBase::FindMenuItem(const wxString& menu, const wxString& item) const
856{
857 wxString label = wxMenuItem::GetLabelFromText(menu);
858
859 int i = 0;
860 wxMenuList::Node *node;
861 for ( node = m_menus.GetFirst(); node; node = node->GetNext(), i++ )
862 {
863 if ( label == wxMenuItem::GetLabelFromText(GetLabelTop(i)) )
864 return node->GetData()->FindItem(item);
865 }
866
867 return wxNOT_FOUND;
868}
869
3dfac970
VZ
870// ---------------------------------------------------------------------------
871// wxMenuBar functions forwarded to wxMenuItem
872// ---------------------------------------------------------------------------
873
874void wxMenuBarBase::Enable(int id, bool enable)
875{
876 wxMenuItem *item = FindItem(id);
877
878 wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") );
879
880 item->Enable(enable);
881}
882
883void wxMenuBarBase::Check(int id, bool check)
884{
885 wxMenuItem *item = FindItem(id);
886
887 wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") );
888 wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") );
889
890 item->Check(check);
891}
892
893bool wxMenuBarBase::IsChecked(int id) const
894{
895 wxMenuItem *item = FindItem(id);
896
897 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsChecked(): no such item") );
898
899 return item->IsChecked();
900}
901
902bool wxMenuBarBase::IsEnabled(int id) const
903{
904 wxMenuItem *item = FindItem(id);
905
906 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsEnabled(): no such item") );
907
908 return item->IsEnabled();
909}
910
911void wxMenuBarBase::SetLabel(int id, const wxString& label)
912{
913 wxMenuItem *item = FindItem(id);
914
915 wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") );
916
917 item->SetText(label);
918}
919
920wxString wxMenuBarBase::GetLabel(int id) const
921{
922 wxMenuItem *item = FindItem(id);
923
924 wxCHECK_MSG( item, wxEmptyString,
925 wxT("wxMenuBar::GetLabel(): no such item") );
926
927 return item->GetText();
928}
929
930void wxMenuBarBase::SetHelpString(int id, const wxString& helpString)
931{
932 wxMenuItem *item = FindItem(id);
933
934 wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") );
935
936 item->SetHelp(helpString);
937}
938
939wxString wxMenuBarBase::GetHelpString(int id) const
940{
941 wxMenuItem *item = FindItem(id);
942
943 wxCHECK_MSG( item, wxEmptyString,
944 wxT("wxMenuBar::GetHelpString(): no such item") );
945
946 return item->GetHelp();
947}
948
1e6feb95 949#endif // wxUSE_MENUS