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