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