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