]> git.saurik.com Git - wxWidgets.git/blame - src/common/menucmn.cpp
always NUL-terminate log messages, even if they're longer than buffer size
[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
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 {
134 current += wxTolower(label[n]);
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?
154 if ( current[0U] == 'f' && isdigit(current[1U]) &&
155 (current.Len() == 2 ||
156 (current.Len() == 3 && isdigit(current[2U]))) ) {
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;
41b78190 169 else if ( current == wxT("INS") )
1e6feb95 170 keyCode = WXK_INSERT;
41b78190 171 else if ( current == wxT("INSERT") )
1e6feb95 172 keyCode = WXK_INSERT;
41b78190 173 else if ( current == wxT("ENTER") || current == wxT("RETURN") )
2b5f62a0 174 keyCode = WXK_RETURN;
41b78190 175 else if ( current == wxT("PGUP") )
2b5f62a0 176 keyCode = WXK_PRIOR;
41b78190 177 else if ( current == wxT("PGDN") )
2b5f62a0 178 keyCode = WXK_NEXT;
41b78190 179 else if ( current == wxT("LEFT") )
2b5f62a0 180 keyCode = WXK_LEFT;
41b78190 181 else if ( current == wxT("RIGHT") )
2b5f62a0 182 keyCode = WXK_RIGHT;
41b78190 183 else if ( current == wxT("UP") )
2b5f62a0 184 keyCode = WXK_UP;
41b78190 185 else if ( current == wxT("DOWN") )
2b5f62a0 186 keyCode = WXK_DOWN;
41b78190 187 else if ( current == wxT("HOME") )
2b5f62a0 188 keyCode = WXK_HOME;
41b78190 189 else if ( current == wxT("END") )
2b5f62a0 190 keyCode = WXK_END;
41b78190 191 else if ( current == wxT("SPACE") )
2b5f62a0 192 keyCode = WXK_SPACE;
41b78190 193 else if ( current == wxT("TAB") )
2b5f62a0 194 keyCode = WXK_TAB;
73baf01a 195 else if ( current == wxT("ESC") || current == wxT("ESCAPE") )
41b78190 196 keyCode = WXK_ESCAPE;
1e6feb95
VZ
197 else
198 {
199 wxLogDebug(wxT("Unrecognized accel key '%s', accel string ignored."),
200 current.c_str());
201 }
202 }
203 }
204 }
205
206 if ( keyCode ) {
207 // we do have something
208 return new wxAcceleratorEntry(accelFlags, keyCode);
209 }
210 }
211
212 return (wxAcceleratorEntry *)NULL;
213}
214
215wxAcceleratorEntry *wxMenuItemBase::GetAccel() const
216{
217 return wxGetAccelFromString(GetText());
218}
219
717a57c2
VZ
220void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel)
221{
222 wxString text = m_text.BeforeFirst(wxT('\t'));
223 if ( accel )
224 {
225 text += wxT('\t');
226
227 int flags = accel->GetFlags();
228 if ( flags & wxACCEL_ALT )
229 text += wxT("Alt-");
230 if ( flags & wxACCEL_CTRL )
231 text += wxT("Ctrl-");
232 if ( flags & wxACCEL_SHIFT )
233 text += wxT("Shift-");
234
235 int code = accel->GetKeyCode();
236 switch ( code )
237 {
238 case WXK_F1:
239 case WXK_F2:
240 case WXK_F3:
241 case WXK_F4:
242 case WXK_F5:
243 case WXK_F6:
244 case WXK_F7:
245 case WXK_F8:
246 case WXK_F9:
247 case WXK_F10:
248 case WXK_F11:
249 case WXK_F12:
250 text << wxT('F') << code - WXK_F1 + 1;
251 break;
252
253 // if there are any other keys wxGetAccelFromString() may return,
254 // we should process them here
255
256 default:
257 if ( wxIsalnum(code) )
258 {
259 text << (wxChar)code;
260
261 break;
262 }
263
264 wxFAIL_MSG( wxT("unknown keyboard accel") );
265 }
266 }
267
268 SetText(text);
269}
270
271#endif // wxUSE_ACCEL
272
273// ----------------------------------------------------------------------------
274// wxMenu ctor and dtor
275// ----------------------------------------------------------------------------
276
277void wxMenuBase::Init(long style)
278{
279 m_items.DeleteContents(TRUE);
280
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;
9739d9ee
VZ
288
289#if wxUSE_MENU_CALLBACK
5b0d48b3 290 m_callback = (wxFunction) NULL;
9739d9ee 291#endif // wxUSE_MENU_CALLBACK
717a57c2
VZ
292}
293
294wxMenuBase::~wxMenuBase()
295{
a583e623 296 // nothing to do, wxMenuItemList dtor will delete the menu items.
1e6feb95
VZ
297
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
717a57c2
VZ
317bool wxMenuBase::DoAppend(wxMenuItem *item)
318{
319 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Append()") );
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
VZ
327
328 return TRUE;
329}
330
331bool wxMenuBase::Insert(size_t pos, wxMenuItem *item)
332{
333 wxCHECK_MSG( item, FALSE, 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
348bool wxMenuBase::DoInsert(size_t pos, wxMenuItem *item)
349{
350 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Insert()") );
351
352 wxMenuItemList::Node *node = m_items.Item(pos);
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
VZ
361
362 return TRUE;
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{
374 wxMenuItemList::Node *node = m_items.Find(item);
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!)
381 node->SetData((wxMenuItem *)NULL); // to prevent it from deleting the item
382 m_items.DeleteNode(node);
383
384 // item isn't attached to anything any more
1e93ca17 385 item->SetMenu((wxMenu *)NULL);
717a57c2
VZ
386 wxMenu *submenu = item->GetSubMenu();
387 if ( submenu )
388 {
389 submenu->SetParent((wxMenu *)NULL);
390 }
391
392 return item;
393}
394
395bool wxMenuBase::Delete(wxMenuItem *item)
396{
39d03faf 397 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Delete") );
717a57c2
VZ
398
399 return DoDelete(item);
400}
401
402bool wxMenuBase::DoDelete(wxMenuItem *item)
403{
404 wxMenuItem *item2 = DoRemove(item);
405 wxCHECK_MSG( item2, FALSE, wxT("failed to delete menu item") );
406
407 // don't delete the submenu
408 item2->SetSubMenu((wxMenu *)NULL);
409
410 delete item2;
411
412 return TRUE;
413}
414
415bool wxMenuBase::Destroy(wxMenuItem *item)
416{
39d03faf 417 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Destroy") );
717a57c2
VZ
418
419 return DoDestroy(item);
420}
421
422bool wxMenuBase::DoDestroy(wxMenuItem *item)
423{
424 wxMenuItem *item2 = DoRemove(item);
425 wxCHECK_MSG( item2, FALSE, wxT("failed to delete menu item") );
426
427 delete item2;
428
429 return TRUE;
430}
431
432// ----------------------------------------------------------------------------
433// wxMenu searching for items
434// ----------------------------------------------------------------------------
435
436// Finds the item id matching the given string, -1 if not found.
437int wxMenuBase::FindItem(const wxString& text) const
438{
3b59cdbf 439 wxString label = wxMenuItem::GetLabelFromText(text);
717a57c2
VZ
440 for ( wxMenuItemList::Node *node = m_items.GetFirst();
441 node;
442 node = node->GetNext() )
443 {
444 wxMenuItem *item = node->GetData();
445 if ( item->IsSubMenu() )
446 {
447 int rc = item->GetSubMenu()->FindItem(label);
448 if ( rc != wxNOT_FOUND )
449 return rc;
450 }
adb21613
VZ
451
452 // we execute this code for submenus as well to alllow finding them by
453 // name just like the ordinary items
454 if ( !item->IsSeparator() )
717a57c2
VZ
455 {
456 if ( item->GetLabel() == label )
457 return item->GetId();
458 }
459 }
460
461 return wxNOT_FOUND;
462}
463
464// recursive search for item by id
465wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const
466{
467 if ( itemMenu )
468 *itemMenu = NULL;
469
470 wxMenuItem *item = NULL;
471 for ( wxMenuItemList::Node *node = m_items.GetFirst();
472 node && !item;
473 node = node->GetNext() )
474 {
475 item = node->GetData();
476
477 if ( item->GetId() == itemId )
478 {
479 if ( itemMenu )
480 *itemMenu = (wxMenu *)this;
481 }
482 else if ( item->IsSubMenu() )
483 {
484 item = item->GetSubMenu()->FindItem(itemId, itemMenu);
485 }
486 else
487 {
488 // don't exit the loop
489 item = NULL;
490 }
491 }
492
493 return item;
494}
495
496// non recursive search
497wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const
498{
499 wxMenuItem *item = (wxMenuItem *)NULL;
500 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
501
502 size_t pos;
503 for ( pos = 0; node; pos++ )
504 {
1dddf838
VZ
505 if ( node->GetData()->GetId() == id )
506 {
507 item = node->GetData();
508
717a57c2 509 break;
1dddf838 510 }
717a57c2
VZ
511
512 node = node->GetNext();
513 }
514
515 if ( ppos )
516 {
1987af7e 517 *ppos = item ? pos : (size_t)wxNOT_FOUND;
717a57c2
VZ
518 }
519
520 return item;
521}
522
523// ----------------------------------------------------------------------------
1e6feb95 524// wxMenu helpers used by derived classes
717a57c2
VZ
525// ----------------------------------------------------------------------------
526
527// Update a menu and all submenus recursively. source is the object that has
528// the update event handlers defined for it. If NULL, the menu or associated
529// window will be used.
530void wxMenuBase::UpdateUI(wxEvtHandler* source)
531{
532 if ( !source && GetInvokingWindow() )
533 source = GetInvokingWindow()->GetEventHandler();
534 if ( !source )
535 source = GetEventHandler();
536 if ( !source )
537 source = this;
538
539 wxMenuItemList::Node* node = GetMenuItems().GetFirst();
540 while ( node )
541 {
542 wxMenuItem* item = node->GetData();
543 if ( !item->IsSeparator() )
544 {
545 wxWindowID id = item->GetId();
546 wxUpdateUIEvent event(id);
547 event.SetEventObject( source );
548
549 if ( source->ProcessEvent(event) )
550 {
551 // if anything changed, update the chanegd attribute
552 if (event.GetSetText())
553 SetLabel(id, event.GetText());
554 if (event.GetSetChecked())
555 Check(id, event.GetChecked());
556 if (event.GetSetEnabled())
557 Enable(id, event.GetEnabled());
558 }
559
560 // recurse to the submenus
561 if ( item->GetSubMenu() )
562 item->GetSubMenu()->UpdateUI(source);
563 }
564 //else: item is a separator (which don't process update UI events)
565
566 node = node->GetNext();
567 }
568}
569
1e6feb95
VZ
570bool wxMenuBase::SendEvent(int id, int checked)
571{
572 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id);
573 event.SetEventObject(this);
574 event.SetInt(checked);
575
576 bool processed = FALSE;
577
578#if wxUSE_MENU_CALLBACK
579 // Try a callback
580 if (m_callback)
581 {
582 (void)(*(m_callback))(*this, event);
583 processed = TRUE;
584 }
585#endif // wxUSE_MENU_CALLBACK
586
587 // Try the menu's event handler
588 if ( !processed )
589 {
590 wxEvtHandler *handler = GetEventHandler();
591 if ( handler )
592 processed = handler->ProcessEvent(event);
593 }
594
595 // Try the window the menu was popped up from (and up through the
596 // hierarchy)
597 if ( !processed )
598 {
599 const wxMenuBase *menu = this;
600 while ( menu )
601 {
602 wxWindow *win = menu->GetInvokingWindow();
603 if ( win )
604 {
605 processed = win->GetEventHandler()->ProcessEvent(event);
606 break;
607 }
608
609 menu = menu->GetParent();
610 }
611 }
612
613 return processed;
614}
615
616// ----------------------------------------------------------------------------
617// wxMenu attaching/detaching to/from menu bar
618// ----------------------------------------------------------------------------
619
620void wxMenuBase::Attach(wxMenuBarBase *menubar)
621{
622 // use Detach() instead!
623 wxASSERT_MSG( menubar, _T("menu can't be attached to NULL menubar") );
624
625 // use IsAttached() to prevent this from happening
626 wxASSERT_MSG( !m_menuBar, _T("attaching menu twice?") );
627
628 m_menuBar = (wxMenuBar *)menubar;
629}
630
631void wxMenuBase::Detach()
632{
633 // use IsAttached() to prevent this from happening
634 wxASSERT_MSG( m_menuBar, _T("detaching unattached menu?") );
635
636 m_menuBar = NULL;
637}
638
717a57c2
VZ
639// ----------------------------------------------------------------------------
640// wxMenu functions forwarded to wxMenuItem
641// ----------------------------------------------------------------------------
642
643void wxMenuBase::Enable( int id, bool enable )
644{
645 wxMenuItem *item = FindItem(id);
646
647 wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") );
648
649 item->Enable(enable);
650}
651
652bool wxMenuBase::IsEnabled( int id ) const
653{
654 wxMenuItem *item = FindItem(id);
655
656 wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsEnabled: no such item") );
657
658 return item->IsEnabled();
659}
660
661void wxMenuBase::Check( int id, bool enable )
662{
663 wxMenuItem *item = FindItem(id);
664
665 wxCHECK_RET( item, wxT("wxMenu::Check: no such item") );
666
667 item->Check(enable);
668}
669
670bool wxMenuBase::IsChecked( int id ) const
671{
672 wxMenuItem *item = FindItem(id);
673
674 wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsChecked: no such item") );
675
676 return item->IsChecked();
677}
678
679void wxMenuBase::SetLabel( int id, const wxString &label )
680{
681 wxMenuItem *item = FindItem(id);
682
683 wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") );
684
685 item->SetText(label);
686}
687
688wxString wxMenuBase::GetLabel( int id ) const
689{
690 wxMenuItem *item = FindItem(id);
691
692 wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetLabel: no such item") );
693
694 return item->GetText();
695}
696
697void wxMenuBase::SetHelpString( int id, const wxString& helpString )
698{
699 wxMenuItem *item = FindItem(id);
700
701 wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") );
702
703 item->SetHelp( helpString );
704}
705
706wxString wxMenuBase::GetHelpString( int id ) const
707{
708 wxMenuItem *item = FindItem(id);
709
710 wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetHelpString: no such item") );
711
712 return item->GetHelp();
713}
714
715// ----------------------------------------------------------------------------
716// wxMenuBarBase ctor and dtor
3dfac970
VZ
717// ----------------------------------------------------------------------------
718
719wxMenuBarBase::wxMenuBarBase()
720{
721 // we own the menus when we get them
722 m_menus.DeleteContents(TRUE);
1e6feb95
VZ
723
724 // not attached yet
725 m_menuBarFrame = NULL;
3dfac970
VZ
726}
727
728wxMenuBarBase::~wxMenuBarBase()
729{
730 // nothing to do, the list will delete the menus because of the call to
731 // DeleteContents() above
732}
733
734// ----------------------------------------------------------------------------
735// wxMenuBar item access: the base class versions manage m_menus list, the
736// derived class should reflect the changes in the real menubar
737// ----------------------------------------------------------------------------
738
739wxMenu *wxMenuBarBase::GetMenu(size_t pos) const
740{
741 wxMenuList::Node *node = m_menus.Item(pos);
742 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") );
743
744 return node->GetData();
745}
746
747bool wxMenuBarBase::Append(wxMenu *menu, const wxString& WXUNUSED(title))
748{
749 wxCHECK_MSG( menu, FALSE, wxT("can't append NULL menu") );
750
751 m_menus.Append(menu);
1e6feb95 752 menu->Attach(this);
3dfac970
VZ
753
754 return TRUE;
755}
756
757bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu,
32db328c 758 const wxString& title)
3dfac970 759{
32db328c
VZ
760 if ( pos == m_menus.GetCount() )
761 {
186baeb2 762 return wxMenuBarBase::Append(menu, title);
32db328c 763 }
1e6feb95 764 else // not at the end
32db328c
VZ
765 {
766 wxCHECK_MSG( menu, FALSE, wxT("can't insert NULL menu") );
3dfac970 767
32db328c
VZ
768 wxMenuList::Node *node = m_menus.Item(pos);
769 wxCHECK_MSG( node, FALSE, wxT("bad index in wxMenuBar::Insert()") );
3dfac970 770
32db328c 771 m_menus.Insert(node, menu);
1e6feb95 772 menu->Attach(this);
3dfac970 773
32db328c
VZ
774 return TRUE;
775 }
3dfac970
VZ
776}
777
778wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu,
779 const wxString& WXUNUSED(title))
780{
781 wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") );
782
783 wxMenuList::Node *node = m_menus.Item(pos);
784 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") );
785
786 wxMenu *menuOld = node->GetData();
787 node->SetData(menu);
788
1e6feb95
VZ
789 menu->Attach(this);
790 menuOld->Detach();
791
3dfac970
VZ
792 return menuOld;
793}
794
795wxMenu *wxMenuBarBase::Remove(size_t pos)
796{
797 wxMenuList::Node *node = m_menus.Item(pos);
798 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") );
799
800 node = m_menus.DetachNode(node);
801 wxCHECK( node, NULL ); // unexpected
802 wxMenu *menu = node->GetData();
1e6feb95 803 menu->Detach();
3dfac970
VZ
804
805 delete node;
806
807 return menu;
808}
809
270e8b6a 810int wxMenuBarBase::FindMenu(const wxString& title) const
52130557
VZ
811{
812 wxString label = wxMenuItem::GetLabelFromText(title);
813
814 size_t count = GetMenuCount();
815 for ( size_t i = 0; i < count; i++ )
816 {
817 wxString title2 = GetLabelTop(i);
818 if ( (title2 == title) ||
819 (wxMenuItem::GetLabelFromText(title2) == label) )
820 {
821 // found
2b5f62a0 822 return (int)i;
52130557
VZ
823 }
824 }
825
826 return wxNOT_FOUND;
827
828}
829
1e6feb95
VZ
830// ----------------------------------------------------------------------------
831// wxMenuBar attaching/detaching to/from the frame
832// ----------------------------------------------------------------------------
833
834void wxMenuBarBase::Attach(wxFrame *frame)
835{
836 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
837
838 m_menuBarFrame = frame;
839}
840
841void wxMenuBarBase::Detach()
842{
843 wxASSERT_MSG( IsAttached(), wxT("detaching unattached menubar") );
844
845 m_menuBarFrame = NULL;
846}
847
848// ----------------------------------------------------------------------------
849// wxMenuBar searching for items
850// ----------------------------------------------------------------------------
851
852wxMenuItem *wxMenuBarBase::FindItem(int id, wxMenu **menu) const
853{
854 if ( menu )
855 *menu = NULL;
856
857 wxMenuItem *item = NULL;
858 size_t count = GetMenuCount();
859 for ( size_t i = 0; !item && (i < count); i++ )
860 {
861 item = m_menus[i]->FindItem(id, menu);
862 }
863
864 return item;
865}
866
867int wxMenuBarBase::FindMenuItem(const wxString& menu, const wxString& item) const
868{
869 wxString label = wxMenuItem::GetLabelFromText(menu);
870
871 int i = 0;
872 wxMenuList::Node *node;
873 for ( node = m_menus.GetFirst(); node; node = node->GetNext(), i++ )
874 {
875 if ( label == wxMenuItem::GetLabelFromText(GetLabelTop(i)) )
876 return node->GetData()->FindItem(item);
877 }
878
879 return wxNOT_FOUND;
880}
881
3dfac970
VZ
882// ---------------------------------------------------------------------------
883// wxMenuBar functions forwarded to wxMenuItem
884// ---------------------------------------------------------------------------
885
886void wxMenuBarBase::Enable(int id, bool enable)
887{
888 wxMenuItem *item = FindItem(id);
889
890 wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") );
891
892 item->Enable(enable);
893}
894
895void wxMenuBarBase::Check(int id, bool check)
896{
897 wxMenuItem *item = FindItem(id);
898
899 wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") );
900 wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") );
901
902 item->Check(check);
903}
904
905bool wxMenuBarBase::IsChecked(int id) const
906{
907 wxMenuItem *item = FindItem(id);
908
909 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsChecked(): no such item") );
910
911 return item->IsChecked();
912}
913
914bool wxMenuBarBase::IsEnabled(int id) const
915{
916 wxMenuItem *item = FindItem(id);
917
918 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsEnabled(): no such item") );
919
920 return item->IsEnabled();
921}
922
923void wxMenuBarBase::SetLabel(int id, const wxString& label)
924{
925 wxMenuItem *item = FindItem(id);
926
927 wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") );
928
929 item->SetText(label);
930}
931
932wxString wxMenuBarBase::GetLabel(int id) const
933{
934 wxMenuItem *item = FindItem(id);
935
936 wxCHECK_MSG( item, wxEmptyString,
937 wxT("wxMenuBar::GetLabel(): no such item") );
938
939 return item->GetText();
940}
941
942void wxMenuBarBase::SetHelpString(int id, const wxString& helpString)
943{
944 wxMenuItem *item = FindItem(id);
945
946 wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") );
947
948 item->SetHelp(helpString);
949}
950
951wxString wxMenuBarBase::GetHelpString(int id) const
952{
953 wxMenuItem *item = FindItem(id);
954
955 wxCHECK_MSG( item, wxEmptyString,
956 wxT("wxMenuBar::GetHelpString(): no such item") );
957
958 return item->GetHelp();
959}
960
1e6feb95 961#endif // wxUSE_MENUS