avoid type conflict with univ wxMenuInfo
[wxWidgets.git] / src / common / menucmn.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/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) wxWidgets team
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_MENUS
28
29 #ifndef WX_PRECOMP
30 #include "wx/intl.h"
31 #include "wx/log.h"
32 #include "wx/menu.h"
33 #include "wx/frame.h"
34 #endif
35
36 #include "wx/stockitem.h"
37
38 // ----------------------------------------------------------------------------
39 // template lists
40 // ----------------------------------------------------------------------------
41
42 #include "wx/listimpl.cpp"
43
44 WX_DEFINE_LIST(wxMenuList)
45 WX_DEFINE_LIST(wxMenuItemList)
46
47 // ============================================================================
48 // implementation
49 // ============================================================================
50
51 // ----------------------------------------------------------------------------
52 // XTI for wxMenu(Bar)
53 // ----------------------------------------------------------------------------
54
55 wxDEFINE_FLAGS( wxMenuStyle )
56 wxBEGIN_FLAGS( wxMenuStyle )
57 wxFLAGS_MEMBER(wxMENU_TEAROFF)
58 wxEND_FLAGS( wxMenuStyle )
59
60 wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxMenu, wxEvtHandler, "wx/menu.h")
61 wxCOLLECTION_TYPE_INFO( wxMenuItem *, wxMenuItemList ) ;
62
63 template<> void wxCollectionToVariantArray( wxMenuItemList const &theList,
64 wxAnyList &value)
65 {
66 wxListCollectionToAnyList<wxMenuItemList::compatibility_iterator>( theList, value ) ;
67 }
68
69 wxBEGIN_PROPERTIES_TABLE(wxMenu)
70 wxEVENT_PROPERTY( Select, wxEVT_COMMAND_MENU_SELECTED, wxCommandEvent)
71
72 wxPROPERTY( Title, wxString, SetTitle, GetTitle, wxString(), \
73 0 /*flags*/, wxT("Helpstring"), wxT("group") )
74
75 wxREADONLY_PROPERTY_FLAGS( MenuStyle, wxMenuStyle, long, GetStyle, \
76 wxEMPTY_PARAMETER_VALUE, 0 /*flags*/, wxT("Helpstring"), \
77 wxT("group")) // style
78
79 wxPROPERTY_COLLECTION( MenuItems, wxMenuItemList, wxMenuItem*, Append, \
80 GetMenuItems, 0 /*flags*/, wxT("Helpstring"), wxT("group"))
81 wxEND_PROPERTIES_TABLE()
82
83 wxEMPTY_HANDLERS_TABLE(wxMenu)
84
85 wxDIRECT_CONSTRUCTOR_2( wxMenu, wxString, Title, long, MenuStyle )
86
87 wxDEFINE_FLAGS( wxMenuBarStyle )
88
89 wxBEGIN_FLAGS( wxMenuBarStyle )
90 wxFLAGS_MEMBER(wxMB_DOCKABLE)
91 wxEND_FLAGS( wxMenuBarStyle )
92
93 // the negative id would lead the window (its superclass !) to
94 // vetoe streaming out otherwise
95 bool wxMenuBarStreamingCallback( const wxObject *WXUNUSED(object), wxObjectWriter *,
96 wxObjectWriterCallback *, const wxStringToAnyHashMap & )
97 {
98 return true;
99 }
100
101 wxIMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuBar, wxWindow, "wx/menu.h", \
102 wxMenuBarStreamingCallback)
103
104
105 #if wxUSE_EXTENDED_RTTI
106 WX_DEFINE_LIST( wxMenuInfoHelperList )
107
108 wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxMenuInfoHelper, wxObject, "wx/menu.h")
109
110 wxBEGIN_PROPERTIES_TABLE(wxMenuInfoHelper)
111 wxREADONLY_PROPERTY( Menu, wxMenu*, GetMenu, wxEMPTY_PARAMETER_VALUE, \
112 0 /*flags*/, wxT("Helpstring"), wxT("group"))
113
114 wxREADONLY_PROPERTY( Title, wxString, GetTitle, wxString(), \
115 0 /*flags*/, wxT("Helpstring"), wxT("group"))
116 wxEND_PROPERTIES_TABLE()
117
118 wxEMPTY_HANDLERS_TABLE(wxMenuInfoHelper)
119
120 wxCONSTRUCTOR_2( wxMenuInfoHelper, wxMenu*, Menu, wxString, Title )
121
122 wxCOLLECTION_TYPE_INFO( wxMenuInfoHelper *, wxMenuInfoHelperList ) ;
123
124 template<> void wxCollectionToVariantArray( wxMenuInfoHelperList const &theList,
125 wxAnyList &value)
126 {
127 wxListCollectionToAnyList<wxMenuInfoHelperList::compatibility_iterator>( theList, value ) ;
128 }
129
130 #endif
131
132 wxBEGIN_PROPERTIES_TABLE(wxMenuBar)
133 wxPROPERTY_COLLECTION( MenuInfos, wxMenuInfoHelperList, wxMenuInfoHelper*, AppendMenuInfo, \
134 GetMenuInfos, 0 /*flags*/, wxT("Helpstring"), wxT("group"))
135 wxEND_PROPERTIES_TABLE()
136
137 wxEMPTY_HANDLERS_TABLE(wxMenuBar)
138
139 wxCONSTRUCTOR_DUMMY( wxMenuBar )
140
141 #if wxUSE_EXTENDED_RTTI
142
143 const wxMenuInfoHelperList& wxMenuBarBase::GetMenuInfos() const
144 {
145 wxMenuInfoHelperList* list = const_cast< wxMenuInfoHelperList* > (& m_menuInfos);
146 WX_CLEAR_LIST( wxMenuInfoHelperList, *list);
147 for (size_t i = 0 ; i < GetMenuCount(); ++i)
148 {
149 wxMenuInfoHelper* info = new wxMenuInfoHelper();
150 info->Create( GetMenu(i), GetMenuLabel(i));
151 list->Append(info);
152 }
153 return m_menuInfos;
154 }
155
156 #endif
157
158 wxBEGIN_PROPERTIES_TABLE(wxMenuBar)
159 wxPROPERTY_COLLECTION( MenuInfos, wxMenuInfoList, wxMenuInfo*, AppendMenuInfo, \
160 GetMenuInfos, 0 /*flags*/, wxT("Helpstring"), wxT("group"))
161 wxEND_PROPERTIES_TABLE()
162
163 wxEMPTY_HANDLERS_TABLE(wxMenuBar)
164
165 wxCONSTRUCTOR_DUMMY( wxMenuBar )
166
167 // ----------------------------------------------------------------------------
168 // XTI for wxMenuItem
169 // ----------------------------------------------------------------------------
170
171 #if wxUSE_EXTENDED_RTTI
172
173 bool wxMenuItemStreamingCallback( const wxObject *object, wxObjectWriter *,
174 wxObjectWriterCallback *, const wxStringToAnyHashMap & )
175 {
176 const wxMenuItem * mitem = wx_dynamic_cast(const wxMenuItem*, object);
177 if ( mitem->GetMenu() && !mitem->GetMenu()->GetTitle().empty() )
178 {
179 // we don't stream out the first two items for menus with a title,
180 // they will be reconstructed
181 if ( mitem->GetMenu()->FindItemByPosition(0) == mitem ||
182 mitem->GetMenu()->FindItemByPosition(1) == mitem )
183 return false;
184 }
185 return true;
186 }
187
188 #endif
189
190 wxBEGIN_ENUM( wxItemKind )
191 wxENUM_MEMBER( wxITEM_SEPARATOR )
192 wxENUM_MEMBER( wxITEM_NORMAL )
193 wxENUM_MEMBER( wxITEM_CHECK )
194 wxENUM_MEMBER( wxITEM_RADIO )
195 wxEND_ENUM( wxItemKind )
196
197 wxIMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuItem, wxObject, "wx/menuitem.h", \
198 wxMenuItemStreamingCallback)
199
200 wxBEGIN_PROPERTIES_TABLE(wxMenuItem)
201 wxPROPERTY( Parent, wxMenu*, SetMenu, GetMenu, wxEMPTY_PARAMETER_VALUE, \
202 0 /*flags*/, wxT("Helpstring"), wxT("group") )
203 wxPROPERTY( Id, int, SetId, GetId, wxEMPTY_PARAMETER_VALUE, \
204 0 /*flags*/, wxT("Helpstring"), wxT("group") )
205 wxPROPERTY( ItemLabel, wxString, SetItemLabel, GetItemLabel, wxString(), \
206 0 /*flags*/, wxT("Helpstring"), wxT("group") )
207 wxPROPERTY( Help, wxString, SetHelp, GetHelp, wxString(), \
208 0 /*flags*/, wxT("Helpstring"), wxT("group") )
209 wxREADONLY_PROPERTY( Kind, wxItemKind, GetKind, wxEMPTY_PARAMETER_VALUE, \
210 0 /*flags*/, wxT("Helpstring"), wxT("group") )
211 wxPROPERTY( SubMenu, wxMenu*, SetSubMenu, GetSubMenu, wxEMPTY_PARAMETER_VALUE, \
212 0 /*flags*/, wxT("Helpstring"), wxT("group") )
213 wxPROPERTY( Enabled, bool, Enable, IsEnabled, wxAny((bool)true), \
214 0 /*flags*/, wxT("Helpstring"), wxT("group") )
215 wxPROPERTY( Checked, bool, Check, IsChecked, wxAny((bool)false), \
216 0 /*flags*/, wxT("Helpstring"), wxT("group") )
217 wxPROPERTY( Checkable, bool, SetCheckable, IsCheckable, wxAny((bool)false), \
218 0 /*flags*/, wxT("Helpstring"), wxT("group") )
219 wxEND_PROPERTIES_TABLE()
220
221 wxEMPTY_HANDLERS_TABLE(wxMenuItem)
222
223 wxDIRECT_CONSTRUCTOR_6( wxMenuItem, wxMenu*, Parent, int, Id, wxString, \
224 Text, wxString, Help, wxItemKind, Kind, wxMenu*, SubMenu )
225
226 // ----------------------------------------------------------------------------
227 // wxMenuItemBase
228 // ----------------------------------------------------------------------------
229
230 wxMenuItemBase::wxMenuItemBase(wxMenu *parentMenu,
231 int id,
232 const wxString& text,
233 const wxString& help,
234 wxItemKind kind,
235 wxMenu *subMenu)
236 {
237 switch ( id )
238 {
239 case wxID_ANY:
240 m_id = wxWindow::NewControlId();
241 break;
242
243 case wxID_SEPARATOR:
244 m_id = wxID_SEPARATOR;
245
246 // there is a lot of existing code just doing Append(wxID_SEPARATOR)
247 // and it makes sense to omit the following optional parameters,
248 // including the kind one which doesn't default to wxITEM_SEPARATOR,
249 // of course, so override it here
250 kind = wxITEM_SEPARATOR;
251 break;
252
253 case wxID_NONE:
254 // (popup) menu titles in wxMSW use this ID to indicate that
255 // it's not a real menu item, so we don't want the check below to
256 // apply to it
257 m_id = id;
258 break;
259
260 default:
261 // ids are limited to 16 bits under MSW so portable code shouldn't
262 // use ids outside of this range (negative ids generated by wx are
263 // fine though)
264 wxASSERT_MSG( (id >= 0 && id < SHRT_MAX) ||
265 (id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST),
266 wxS("invalid id value") );
267 m_id = id;
268 }
269
270 // notice that parentMenu can be NULL: the item can be attached to the menu
271 // later with SetMenu()
272
273 m_parentMenu = parentMenu;
274 m_subMenu = subMenu;
275 m_isEnabled = true;
276 m_isChecked = false;
277 m_kind = kind;
278
279 SetItemLabel(text);
280 SetHelp(help);
281 }
282
283 wxMenuItemBase::~wxMenuItemBase()
284 {
285 delete m_subMenu;
286 }
287
288 #if wxUSE_ACCEL
289
290 wxAcceleratorEntry *wxMenuItemBase::GetAccel() const
291 {
292 return wxAcceleratorEntry::Create(GetItemLabel());
293 }
294
295 void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel)
296 {
297 wxString text = m_text.BeforeFirst(wxT('\t'));
298 if ( accel )
299 {
300 text += wxT('\t');
301 text += accel->ToString();
302 }
303
304 SetItemLabel(text);
305 }
306
307 #endif // wxUSE_ACCEL
308
309 void wxMenuItemBase::SetItemLabel(const wxString& str)
310 {
311 m_text = str;
312
313 if ( m_text.empty() && !IsSeparator() )
314 {
315 wxASSERT_MSG( wxIsStockID(GetId()),
316 wxT("A non-stock menu item with an empty label?") );
317 m_text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR |
318 wxSTOCK_WITH_MNEMONIC);
319 }
320 }
321
322 void wxMenuItemBase::SetHelp(const wxString& str)
323 {
324 m_help = str;
325
326 if ( m_help.empty() && !IsSeparator() && wxIsStockID(GetId()) )
327 {
328 // get a stock help string
329 m_help = wxGetStockHelpString(GetId());
330 }
331 }
332
333 #ifndef __WXPM__
334 wxString wxMenuItemBase::GetLabelText(const wxString& text)
335 {
336 return wxStripMenuCodes(text);
337 }
338 #endif
339
340 #if WXWIN_COMPATIBILITY_2_8
341 wxString wxMenuItemBase::GetLabelFromText(const wxString& text)
342 {
343 return GetLabelText(text);
344 }
345 #endif
346
347 bool wxMenuBase::ms_locked = true;
348
349 // ----------------------------------------------------------------------------
350 // wxMenu ctor and dtor
351 // ----------------------------------------------------------------------------
352
353 void wxMenuBase::Init(long style)
354 {
355 m_menuBar = NULL;
356 m_menuParent = NULL;
357
358 m_invokingWindow = NULL;
359 m_style = style;
360 m_clientData = NULL;
361 m_eventHandler = this;
362 }
363
364 wxMenuBase::~wxMenuBase()
365 {
366 WX_CLEAR_LIST(wxMenuItemList, m_items);
367 }
368
369 // ----------------------------------------------------------------------------
370 // wxMenu item adding/removing
371 // ----------------------------------------------------------------------------
372
373 void wxMenuBase::AddSubMenu(wxMenu *submenu)
374 {
375 wxCHECK_RET( submenu, wxT("can't add a NULL submenu") );
376
377 submenu->SetParent((wxMenu *)this);
378 }
379
380 wxMenuItem* wxMenuBase::DoAppend(wxMenuItem *item)
381 {
382 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Append()") );
383
384 m_items.Append(item);
385 item->SetMenu((wxMenu*)this);
386 if ( item->IsSubMenu() )
387 {
388 AddSubMenu(item->GetSubMenu());
389 }
390
391 return item;
392 }
393
394 wxMenuItem* wxMenuBase::Insert(size_t pos, wxMenuItem *item)
395 {
396 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert") );
397
398 if ( pos == GetMenuItemCount() )
399 {
400 return DoAppend(item);
401 }
402 else
403 {
404 wxCHECK_MSG( pos < GetMenuItemCount(), NULL,
405 wxT("invalid index in wxMenu::Insert") );
406
407 return DoInsert(pos, item);
408 }
409 }
410
411 wxMenuItem* wxMenuBase::DoInsert(size_t pos, wxMenuItem *item)
412 {
413 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert()") );
414
415 wxMenuItemList::compatibility_iterator node = m_items.Item(pos);
416 wxCHECK_MSG( node, NULL, wxT("invalid index in wxMenu::Insert()") );
417
418 m_items.Insert(node, item);
419 item->SetMenu((wxMenu*)this);
420 if ( item->IsSubMenu() )
421 {
422 AddSubMenu(item->GetSubMenu());
423 }
424
425 return item;
426 }
427
428 wxMenuItem *wxMenuBase::Remove(wxMenuItem *item)
429 {
430 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Remove") );
431
432 return DoRemove(item);
433 }
434
435 wxMenuItem *wxMenuBase::DoRemove(wxMenuItem *item)
436 {
437 wxMenuItemList::compatibility_iterator node = m_items.Find(item);
438
439 // if we get here, the item is valid or one of Remove() functions is broken
440 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
441
442 // we detach the item, but we do delete the list node (i.e. don't call
443 // DetachNode() here!)
444 m_items.Erase(node);
445
446 // item isn't attached to anything any more
447 item->SetMenu(NULL);
448 wxMenu *submenu = item->GetSubMenu();
449 if ( submenu )
450 {
451 submenu->SetParent(NULL);
452 if ( submenu->IsAttached() )
453 submenu->Detach();
454 }
455
456 return item;
457 }
458
459 bool wxMenuBase::Delete(wxMenuItem *item)
460 {
461 wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Delete") );
462
463 return DoDelete(item);
464 }
465
466 bool wxMenuBase::DoDelete(wxMenuItem *item)
467 {
468 wxMenuItem *item2 = DoRemove(item);
469 wxCHECK_MSG( item2, false, wxT("failed to delete menu item") );
470
471 // don't delete the submenu
472 item2->SetSubMenu(NULL);
473
474 delete item2;
475
476 return true;
477 }
478
479 bool wxMenuBase::Destroy(wxMenuItem *item)
480 {
481 wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Destroy") );
482
483 return DoDestroy(item);
484 }
485
486 bool wxMenuBase::DoDestroy(wxMenuItem *item)
487 {
488 wxMenuItem *item2 = DoRemove(item);
489 wxCHECK_MSG( item2, false, wxT("failed to delete menu item") );
490
491 delete item2;
492
493 return true;
494 }
495
496 // ----------------------------------------------------------------------------
497 // wxMenu searching for items
498 // ----------------------------------------------------------------------------
499
500 // Finds the item id matching the given string, wxNOT_FOUND if not found.
501 int wxMenuBase::FindItem(const wxString& text) const
502 {
503 wxString label = wxMenuItem::GetLabelText(text);
504 for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
505 node;
506 node = node->GetNext() )
507 {
508 wxMenuItem *item = node->GetData();
509 if ( item->IsSubMenu() )
510 {
511 int rc = item->GetSubMenu()->FindItem(label);
512 if ( rc != wxNOT_FOUND )
513 return rc;
514 }
515
516 // we execute this code for submenus as well to alllow finding them by
517 // name just like the ordinary items
518 if ( !item->IsSeparator() )
519 {
520 if ( item->GetItemLabelText() == label )
521 return item->GetId();
522 }
523 }
524
525 return wxNOT_FOUND;
526 }
527
528 // recursive search for item by id
529 wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const
530 {
531 if ( itemMenu )
532 *itemMenu = NULL;
533
534 wxMenuItem *item = NULL;
535 for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
536 node && !item;
537 node = node->GetNext() )
538 {
539 item = node->GetData();
540
541 if ( item->GetId() == itemId )
542 {
543 if ( itemMenu )
544 *itemMenu = (wxMenu *)this;
545 }
546 else if ( item->IsSubMenu() )
547 {
548 item = item->GetSubMenu()->FindItem(itemId, itemMenu);
549 }
550 else
551 {
552 // don't exit the loop
553 item = NULL;
554 }
555 }
556
557 return item;
558 }
559
560 // non recursive search
561 wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const
562 {
563 wxMenuItem *item = NULL;
564 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
565
566 size_t pos;
567 for ( pos = 0; node; pos++ )
568 {
569 if ( node->GetData()->GetId() == id )
570 {
571 item = node->GetData();
572
573 break;
574 }
575
576 node = node->GetNext();
577 }
578
579 if ( ppos )
580 {
581 *ppos = item ? pos : (size_t)wxNOT_FOUND;
582 }
583
584 return item;
585 }
586
587 // find by position
588 wxMenuItem* wxMenuBase::FindItemByPosition(size_t position) const
589 {
590 wxCHECK_MSG( position < m_items.GetCount(), NULL,
591 wxT("wxMenu::FindItemByPosition(): invalid menu index") );
592
593 return m_items.Item( position )->GetData();
594 }
595
596 // ----------------------------------------------------------------------------
597 // wxMenu helpers used by derived classes
598 // ----------------------------------------------------------------------------
599
600 // Update a menu and all submenus recursively. source is the object that has
601 // the update event handlers defined for it. If NULL, the menu or associated
602 // window will be used.
603 void wxMenuBase::UpdateUI(wxEvtHandler* source)
604 {
605 if (GetInvokingWindow())
606 {
607 // Don't update menus if the parent
608 // frame is about to get deleted
609 wxWindow *tlw = wxGetTopLevelParent( GetInvokingWindow() );
610 if (tlw && wxPendingDelete.Member(tlw))
611 return;
612 }
613
614 if ( !source && GetInvokingWindow() )
615 source = GetInvokingWindow()->GetEventHandler();
616 if ( !source )
617 source = GetEventHandler();
618 if ( !source )
619 source = this;
620
621 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
622 while ( node )
623 {
624 wxMenuItem* item = node->GetData();
625 if ( !item->IsSeparator() )
626 {
627 wxWindowID id = item->GetId();
628 wxUpdateUIEvent event(id);
629 event.SetEventObject( source );
630
631 if ( source->ProcessEvent(event) )
632 {
633 // if anything changed, update the changed attribute
634 if (event.GetSetText())
635 SetLabel(id, event.GetText());
636 if (event.GetSetChecked())
637 Check(id, event.GetChecked());
638 if (event.GetSetEnabled())
639 Enable(id, event.GetEnabled());
640 }
641
642 // recurse to the submenus
643 if ( item->GetSubMenu() )
644 item->GetSubMenu()->UpdateUI(source);
645 }
646 //else: item is a separator (which doesn't process update UI events)
647
648 node = node->GetNext();
649 }
650 }
651
652 bool wxMenuBase::SendEvent(int id, int checked)
653 {
654 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id);
655 event.SetEventObject(this);
656 event.SetInt(checked);
657
658 bool processed = false;
659
660 // Try the menu's event handler first
661 wxEvtHandler *handler = GetEventHandler();
662 if ( handler )
663 processed = handler->SafelyProcessEvent(event);
664
665 // Try the window the menu was popped up from or its menu bar belongs to
666 if ( !processed )
667 {
668 wxWindow * const win = GetWindow();
669 if ( win )
670 processed = win->HandleWindowEvent(event);
671 }
672
673 return processed;
674 }
675
676 // ----------------------------------------------------------------------------
677 // wxMenu attaching/detaching to/from menu bar
678 // ----------------------------------------------------------------------------
679
680 wxMenuBar* wxMenuBase::GetMenuBar() const
681 {
682 if(GetParent())
683 return GetParent()->GetMenuBar();
684 return m_menuBar;
685 }
686
687 void wxMenuBase::Attach(wxMenuBarBase *menubar)
688 {
689 // use Detach() instead!
690 wxASSERT_MSG( menubar, wxT("menu can't be attached to NULL menubar") );
691
692 // use IsAttached() to prevent this from happening
693 wxASSERT_MSG( !m_menuBar, wxT("attaching menu twice?") );
694
695 m_menuBar = (wxMenuBar *)menubar;
696 }
697
698 void wxMenuBase::Detach()
699 {
700 // use IsAttached() to prevent this from happening
701 wxASSERT_MSG( m_menuBar, wxT("detaching unattached menu?") );
702
703 m_menuBar = NULL;
704 }
705
706 // ----------------------------------------------------------------------------
707 // wxMenu invoking window handling
708 // ----------------------------------------------------------------------------
709
710 void wxMenuBase::SetInvokingWindow(wxWindow *win)
711 {
712 wxASSERT_MSG( !GetParent(),
713 "should only be called for top level popup menus" );
714 wxASSERT_MSG( !IsAttached(),
715 "menus attached to menu bar can't have invoking window" );
716
717 m_invokingWindow = win;
718 }
719
720 wxWindow *wxMenuBase::GetWindow() const
721 {
722 // only the top level menus have non-NULL invoking window or a pointer to
723 // the menu bar so recurse upwards until we find it
724 const wxMenuBase *menu = this;
725 while ( menu->GetParent() )
726 {
727 menu = menu->GetParent();
728 }
729
730 return menu->GetMenuBar() ? menu->GetMenuBar()->GetFrame()
731 : menu->GetInvokingWindow();
732 }
733
734 // ----------------------------------------------------------------------------
735 // wxMenu functions forwarded to wxMenuItem
736 // ----------------------------------------------------------------------------
737
738 void wxMenuBase::Enable( int id, bool enable )
739 {
740 wxMenuItem *item = FindItem(id);
741
742 wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") );
743
744 item->Enable(enable);
745 }
746
747 bool wxMenuBase::IsEnabled( int id ) const
748 {
749 wxMenuItem *item = FindItem(id);
750
751 wxCHECK_MSG( item, false, wxT("wxMenu::IsEnabled: no such item") );
752
753 return item->IsEnabled();
754 }
755
756 void wxMenuBase::Check( int id, bool enable )
757 {
758 wxMenuItem *item = FindItem(id);
759
760 wxCHECK_RET( item, wxT("wxMenu::Check: no such item") );
761
762 item->Check(enable);
763 }
764
765 bool wxMenuBase::IsChecked( int id ) const
766 {
767 wxMenuItem *item = FindItem(id);
768
769 wxCHECK_MSG( item, false, wxT("wxMenu::IsChecked: no such item") );
770
771 return item->IsChecked();
772 }
773
774 void wxMenuBase::SetLabel( int id, const wxString &label )
775 {
776 wxMenuItem *item = FindItem(id);
777
778 wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") );
779
780 item->SetItemLabel(label);
781 }
782
783 wxString wxMenuBase::GetLabel( int id ) const
784 {
785 wxMenuItem *item = FindItem(id);
786
787 wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetLabel: no such item") );
788
789 return item->GetItemLabel();
790 }
791
792 void wxMenuBase::SetHelpString( int id, const wxString& helpString )
793 {
794 wxMenuItem *item = FindItem(id);
795
796 wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") );
797
798 item->SetHelp( helpString );
799 }
800
801 wxString wxMenuBase::GetHelpString( int id ) const
802 {
803 wxMenuItem *item = FindItem(id);
804
805 wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetHelpString: no such item") );
806
807 return item->GetHelp();
808 }
809
810 // ----------------------------------------------------------------------------
811 // wxMenuBarBase ctor and dtor
812 // ----------------------------------------------------------------------------
813
814 wxMenuBarBase::wxMenuBarBase()
815 {
816 // not attached yet
817 m_menuBarFrame = NULL;
818 }
819
820 wxMenuBarBase::~wxMenuBarBase()
821 {
822 WX_CLEAR_LIST(wxMenuList, m_menus);
823 }
824
825 // ----------------------------------------------------------------------------
826 // wxMenuBar item access: the base class versions manage m_menus list, the
827 // derived class should reflect the changes in the real menubar
828 // ----------------------------------------------------------------------------
829
830 wxMenu *wxMenuBarBase::GetMenu(size_t pos) const
831 {
832 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
833 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") );
834
835 return node->GetData();
836 }
837
838 bool wxMenuBarBase::Append(wxMenu *menu, const wxString& title)
839 {
840 wxCHECK_MSG( menu, false, wxT("can't append NULL menu") );
841 wxCHECK_MSG( !title.empty(), false, wxT("can't append menu with empty title") );
842
843 m_menus.Append(menu);
844 menu->Attach(this);
845
846 return true;
847 }
848
849 bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu,
850 const wxString& title)
851 {
852 if ( pos == m_menus.GetCount() )
853 {
854 return wxMenuBarBase::Append(menu, title);
855 }
856 else // not at the end
857 {
858 wxCHECK_MSG( menu, false, wxT("can't insert NULL menu") );
859
860 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
861 wxCHECK_MSG( node, false, wxT("bad index in wxMenuBar::Insert()") );
862
863 m_menus.Insert(node, menu);
864 menu->Attach(this);
865
866 return true;
867 }
868 }
869
870 wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu,
871 const wxString& WXUNUSED(title))
872 {
873 wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") );
874
875 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
876 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") );
877
878 wxMenu *menuOld = node->GetData();
879 node->SetData(menu);
880
881 menu->Attach(this);
882 menuOld->Detach();
883
884 return menuOld;
885 }
886
887 wxMenu *wxMenuBarBase::Remove(size_t pos)
888 {
889 wxMenuList::compatibility_iterator node = m_menus.Item(pos);
890 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") );
891
892 wxMenu *menu = node->GetData();
893 m_menus.Erase(node);
894 menu->Detach();
895
896 return menu;
897 }
898
899 int wxMenuBarBase::FindMenu(const wxString& title) const
900 {
901 wxString label = wxMenuItem::GetLabelText(title);
902
903 size_t count = GetMenuCount();
904 for ( size_t i = 0; i < count; i++ )
905 {
906 wxString title2 = GetMenuLabel(i);
907 if ( (title2 == title) ||
908 (wxMenuItem::GetLabelText(title2) == label) )
909 {
910 // found
911 return (int)i;
912 }
913 }
914
915 return wxNOT_FOUND;
916
917 }
918
919 // ----------------------------------------------------------------------------
920 // wxMenuBar attaching/detaching to/from the frame
921 // ----------------------------------------------------------------------------
922
923 void wxMenuBarBase::Attach(wxFrame *frame)
924 {
925 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
926
927 m_menuBarFrame = frame;
928 }
929
930 void wxMenuBarBase::Detach()
931 {
932 wxASSERT_MSG( IsAttached(), wxT("detaching unattached menubar") );
933
934 m_menuBarFrame = NULL;
935 }
936
937 // ----------------------------------------------------------------------------
938 // wxMenuBar searching for items
939 // ----------------------------------------------------------------------------
940
941 wxMenuItem *wxMenuBarBase::FindItem(int id, wxMenu **menu) const
942 {
943 if ( menu )
944 *menu = NULL;
945
946 wxMenuItem *item = NULL;
947 size_t count = GetMenuCount(), i;
948 wxMenuList::const_iterator it;
949 for ( i = 0, it = m_menus.begin(); !item && (i < count); i++, it++ )
950 {
951 item = (*it)->FindItem(id, menu);
952 }
953
954 return item;
955 }
956
957 int wxMenuBarBase::FindMenuItem(const wxString& menu, const wxString& item) const
958 {
959 wxString label = wxMenuItem::GetLabelText(menu);
960
961 int i = 0;
962 wxMenuList::compatibility_iterator node;
963 for ( node = m_menus.GetFirst(); node; node = node->GetNext(), i++ )
964 {
965 if ( label == wxMenuItem::GetLabelText(GetMenuLabel(i)) )
966 return node->GetData()->FindItem(item);
967 }
968
969 return wxNOT_FOUND;
970 }
971
972 // ---------------------------------------------------------------------------
973 // wxMenuBar functions forwarded to wxMenuItem
974 // ---------------------------------------------------------------------------
975
976 void wxMenuBarBase::Enable(int id, bool enable)
977 {
978 wxMenuItem *item = FindItem(id);
979
980 wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") );
981
982 item->Enable(enable);
983 }
984
985 void wxMenuBarBase::Check(int id, bool check)
986 {
987 wxMenuItem *item = FindItem(id);
988
989 wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") );
990 wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") );
991
992 item->Check(check);
993 }
994
995 bool wxMenuBarBase::IsChecked(int id) const
996 {
997 wxMenuItem *item = FindItem(id);
998
999 wxCHECK_MSG( item, false, wxT("wxMenuBar::IsChecked(): no such item") );
1000
1001 return item->IsChecked();
1002 }
1003
1004 bool wxMenuBarBase::IsEnabled(int id) const
1005 {
1006 wxMenuItem *item = FindItem(id);
1007
1008 wxCHECK_MSG( item, false, wxT("wxMenuBar::IsEnabled(): no such item") );
1009
1010 return item->IsEnabled();
1011 }
1012
1013 void wxMenuBarBase::SetLabel(int id, const wxString& label)
1014 {
1015 wxMenuItem *item = FindItem(id);
1016
1017 wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") );
1018
1019 item->SetItemLabel(label);
1020 }
1021
1022 wxString wxMenuBarBase::GetLabel(int id) const
1023 {
1024 wxMenuItem *item = FindItem(id);
1025
1026 wxCHECK_MSG( item, wxEmptyString,
1027 wxT("wxMenuBar::GetLabel(): no such item") );
1028
1029 return item->GetItemLabel();
1030 }
1031
1032 void wxMenuBarBase::SetHelpString(int id, const wxString& helpString)
1033 {
1034 wxMenuItem *item = FindItem(id);
1035
1036 wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") );
1037
1038 item->SetHelp(helpString);
1039 }
1040
1041 wxString wxMenuBarBase::GetHelpString(int id) const
1042 {
1043 wxMenuItem *item = FindItem(id);
1044
1045 wxCHECK_MSG( item, wxEmptyString,
1046 wxT("wxMenuBar::GetHelpString(): no such item") );
1047
1048 return item->GetHelp();
1049 }
1050
1051 void wxMenuBarBase::UpdateMenus()
1052 {
1053 wxEvtHandler* source;
1054 wxMenu* menu;
1055 int nCount = GetMenuCount();
1056 for (int n = 0; n < nCount; n++)
1057 {
1058 menu = GetMenu( n );
1059 if (menu != NULL)
1060 {
1061 source = menu->GetEventHandler();
1062 if (source != NULL)
1063 menu->UpdateUI( source );
1064 }
1065 }
1066 }
1067
1068 #if WXWIN_COMPATIBILITY_2_8
1069 // get or change the label of the menu at given position
1070 void wxMenuBarBase::SetLabelTop(size_t pos, const wxString& label)
1071 {
1072 SetMenuLabel(pos, label);
1073 }
1074
1075 wxString wxMenuBarBase::GetLabelTop(size_t pos) const
1076 {
1077 return GetMenuLabelText(pos);
1078 }
1079 #endif
1080
1081 #endif // wxUSE_MENUS