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