Files
wxWidgets/src/common/menucmn.cpp
Vadim Zeitlin 4ed3f4abd8 Pass menu events to the handler in the associated menu bar.
We handled the menu events in the menu itself and the associated window, but
not in the menu bar that the menu belonged to. This was unexpected, so allow
handling the events in the menu bar itself too.

Closes #15095.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@73922 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2013-05-04 23:59:32 +00:00

1078 lines
30 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/common/menucmn.cpp
// Purpose: wxMenu and wxMenuBar methods common to all ports
// Author: Vadim Zeitlin
// Modified by:
// Created: 26.10.99
// RCS-ID: $Id$
// Copyright: (c) wxWidgets team
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_MENUS
#ifndef WX_PRECOMP
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/menu.h"
#include "wx/frame.h"
#endif
#include "wx/stockitem.h"
// ----------------------------------------------------------------------------
// template lists
// ----------------------------------------------------------------------------
#include "wx/listimpl.cpp"
WX_DEFINE_LIST(wxMenuList)
WX_DEFINE_LIST(wxMenuItemList)
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// XTI for wxMenu(Bar)
// ----------------------------------------------------------------------------
wxDEFINE_FLAGS( wxMenuStyle )
wxBEGIN_FLAGS( wxMenuStyle )
wxFLAGS_MEMBER(wxMENU_TEAROFF)
wxEND_FLAGS( wxMenuStyle )
wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxMenu, wxEvtHandler, "wx/menu.h")
wxCOLLECTION_TYPE_INFO( wxMenuItem *, wxMenuItemList ) ;
#if wxUSE_EXTENDED_RTTI
template<> void wxCollectionToVariantArray( wxMenuItemList const &theList,
wxAnyList &value)
{
wxListCollectionToAnyList<wxMenuItemList::compatibility_iterator>( theList, value ) ;
}
#endif
wxBEGIN_PROPERTIES_TABLE(wxMenu)
wxEVENT_PROPERTY( Select, wxEVT_MENU, wxCommandEvent)
wxPROPERTY( Title, wxString, SetTitle, GetTitle, wxString(), \
0 /*flags*/, wxT("Helpstring"), wxT("group") )
wxREADONLY_PROPERTY_FLAGS( MenuStyle, wxMenuStyle, long, GetStyle, \
wxEMPTY_PARAMETER_VALUE, 0 /*flags*/, wxT("Helpstring"), \
wxT("group")) // style
wxPROPERTY_COLLECTION( MenuItems, wxMenuItemList, wxMenuItem*, Append, \
GetMenuItems, 0 /*flags*/, wxT("Helpstring"), wxT("group"))
wxEND_PROPERTIES_TABLE()
wxEMPTY_HANDLERS_TABLE(wxMenu)
wxDIRECT_CONSTRUCTOR_2( wxMenu, wxString, Title, long, MenuStyle )
wxDEFINE_FLAGS( wxMenuBarStyle )
wxBEGIN_FLAGS( wxMenuBarStyle )
wxFLAGS_MEMBER(wxMB_DOCKABLE)
wxEND_FLAGS( wxMenuBarStyle )
#if wxUSE_EXTENDED_RTTI
// the negative id would lead the window (its superclass !) to
// vetoe streaming out otherwise
bool wxMenuBarStreamingCallback( const wxObject *WXUNUSED(object), wxObjectWriter *,
wxObjectWriterCallback *, const wxStringToAnyHashMap & )
{
return true;
}
#endif
wxIMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuBar, wxWindow, "wx/menu.h", \
wxMenuBarStreamingCallback)
#if wxUSE_EXTENDED_RTTI
WX_DEFINE_LIST( wxMenuInfoHelperList )
wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxMenuInfoHelper, wxObject, "wx/menu.h")
wxBEGIN_PROPERTIES_TABLE(wxMenuInfoHelper)
wxREADONLY_PROPERTY( Menu, wxMenu*, GetMenu, wxEMPTY_PARAMETER_VALUE, \
0 /*flags*/, wxT("Helpstring"), wxT("group"))
wxREADONLY_PROPERTY( Title, wxString, GetTitle, wxString(), \
0 /*flags*/, wxT("Helpstring"), wxT("group"))
wxEND_PROPERTIES_TABLE()
wxEMPTY_HANDLERS_TABLE(wxMenuInfoHelper)
wxCONSTRUCTOR_2( wxMenuInfoHelper, wxMenu*, Menu, wxString, Title )
wxCOLLECTION_TYPE_INFO( wxMenuInfoHelper *, wxMenuInfoHelperList ) ;
template<> void wxCollectionToVariantArray( wxMenuInfoHelperList const &theList,
wxAnyList &value)
{
wxListCollectionToAnyList<wxMenuInfoHelperList::compatibility_iterator>( theList, value ) ;
}
#endif
wxBEGIN_PROPERTIES_TABLE(wxMenuBar)
wxPROPERTY_COLLECTION( MenuInfos, wxMenuInfoHelperList, wxMenuInfoHelper*, AppendMenuInfo, \
GetMenuInfos, 0 /*flags*/, wxT("Helpstring"), wxT("group"))
wxEND_PROPERTIES_TABLE()
wxEMPTY_HANDLERS_TABLE(wxMenuBar)
wxCONSTRUCTOR_DUMMY( wxMenuBar )
#if wxUSE_EXTENDED_RTTI
const wxMenuInfoHelperList& wxMenuBarBase::GetMenuInfos() const
{
wxMenuInfoHelperList* list = const_cast< wxMenuInfoHelperList* > (& m_menuInfos);
WX_CLEAR_LIST( wxMenuInfoHelperList, *list);
for (size_t i = 0 ; i < GetMenuCount(); ++i)
{
wxMenuInfoHelper* info = new wxMenuInfoHelper();
info->Create( GetMenu(i), GetMenuLabel(i));
list->Append(info);
}
return m_menuInfos;
}
#endif
// ----------------------------------------------------------------------------
// XTI for wxMenuItem
// ----------------------------------------------------------------------------
#if wxUSE_EXTENDED_RTTI
bool wxMenuItemStreamingCallback( const wxObject *object, wxObjectWriter *,
wxObjectWriterCallback *, const wxStringToAnyHashMap & )
{
const wxMenuItem * mitem = wx_dynamic_cast(const wxMenuItem*, object);
if ( mitem->GetMenu() && !mitem->GetMenu()->GetTitle().empty() )
{
// we don't stream out the first two items for menus with a title,
// they will be reconstructed
if ( mitem->GetMenu()->FindItemByPosition(0) == mitem ||
mitem->GetMenu()->FindItemByPosition(1) == mitem )
return false;
}
return true;
}
#endif
wxBEGIN_ENUM( wxItemKind )
wxENUM_MEMBER( wxITEM_SEPARATOR )
wxENUM_MEMBER( wxITEM_NORMAL )
wxENUM_MEMBER( wxITEM_CHECK )
wxENUM_MEMBER( wxITEM_RADIO )
wxEND_ENUM( wxItemKind )
wxIMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuItem, wxObject, "wx/menuitem.h", \
wxMenuItemStreamingCallback)
wxBEGIN_PROPERTIES_TABLE(wxMenuItem)
wxPROPERTY( Parent, wxMenu*, SetMenu, GetMenu, wxEMPTY_PARAMETER_VALUE, \
0 /*flags*/, wxT("Helpstring"), wxT("group") )
wxPROPERTY( Id, int, SetId, GetId, wxEMPTY_PARAMETER_VALUE, \
0 /*flags*/, wxT("Helpstring"), wxT("group") )
wxPROPERTY( ItemLabel, wxString, SetItemLabel, GetItemLabel, wxString(), \
0 /*flags*/, wxT("Helpstring"), wxT("group") )
wxPROPERTY( Help, wxString, SetHelp, GetHelp, wxString(), \
0 /*flags*/, wxT("Helpstring"), wxT("group") )
wxREADONLY_PROPERTY( Kind, wxItemKind, GetKind, wxEMPTY_PARAMETER_VALUE, \
0 /*flags*/, wxT("Helpstring"), wxT("group") )
wxPROPERTY( SubMenu, wxMenu*, SetSubMenu, GetSubMenu, wxEMPTY_PARAMETER_VALUE, \
0 /*flags*/, wxT("Helpstring"), wxT("group") )
wxPROPERTY( Enabled, bool, Enable, IsEnabled, wxAny((bool)true), \
0 /*flags*/, wxT("Helpstring"), wxT("group") )
wxPROPERTY( Checked, bool, Check, IsChecked, wxAny((bool)false), \
0 /*flags*/, wxT("Helpstring"), wxT("group") )
wxPROPERTY( Checkable, bool, SetCheckable, IsCheckable, wxAny((bool)false), \
0 /*flags*/, wxT("Helpstring"), wxT("group") )
wxEND_PROPERTIES_TABLE()
wxEMPTY_HANDLERS_TABLE(wxMenuItem)
wxDIRECT_CONSTRUCTOR_6( wxMenuItem, wxMenu*, Parent, int, Id, wxString, \
Text, wxString, Help, wxItemKind, Kind, wxMenu*, SubMenu )
// ----------------------------------------------------------------------------
// wxMenuItemBase
// ----------------------------------------------------------------------------
wxMenuItemBase::wxMenuItemBase(wxMenu *parentMenu,
int itemid,
const wxString& text,
const wxString& help,
wxItemKind kind,
wxMenu *subMenu)
{
switch ( itemid )
{
case wxID_ANY:
m_id = wxWindow::NewControlId();
break;
case wxID_SEPARATOR:
m_id = wxID_SEPARATOR;
// there is a lot of existing code just doing Append(wxID_SEPARATOR)
// and it makes sense to omit the following optional parameters,
// including the kind one which doesn't default to wxITEM_SEPARATOR,
// of course, so override it here
kind = wxITEM_SEPARATOR;
break;
case wxID_NONE:
// (popup) menu titles in wxMSW use this ID to indicate that
// it's not a real menu item, so we don't want the check below to
// apply to it
m_id = itemid;
break;
default:
// ids are limited to 16 bits under MSW so portable code shouldn't
// use ids outside of this range (negative ids generated by wx are
// fine though)
wxASSERT_MSG( (itemid >= 0 && itemid < SHRT_MAX) ||
(itemid >= wxID_AUTO_LOWEST && itemid <= wxID_AUTO_HIGHEST),
wxS("invalid itemid value") );
m_id = itemid;
}
// notice that parentMenu can be NULL: the item can be attached to the menu
// later with SetMenu()
m_parentMenu = parentMenu;
m_subMenu = subMenu;
m_isEnabled = true;
m_isChecked = false;
m_kind = kind;
SetItemLabel(text);
SetHelp(help);
}
wxMenuItemBase::~wxMenuItemBase()
{
delete m_subMenu;
}
#if wxUSE_ACCEL
wxAcceleratorEntry *wxMenuItemBase::GetAccel() const
{
return wxAcceleratorEntry::Create(GetItemLabel());
}
void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel)
{
wxString text = m_text.BeforeFirst(wxT('\t'));
if ( accel )
{
text += wxT('\t');
text += accel->ToString();
}
SetItemLabel(text);
}
#endif // wxUSE_ACCEL
void wxMenuItemBase::SetItemLabel(const wxString& str)
{
m_text = str;
if ( m_text.empty() && !IsSeparator() )
{
wxASSERT_MSG( wxIsStockID(GetId()),
wxT("A non-stock menu item with an empty label?") );
m_text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR |
wxSTOCK_WITH_MNEMONIC);
}
}
void wxMenuItemBase::SetHelp(const wxString& str)
{
m_help = str;
if ( m_help.empty() && !IsSeparator() && wxIsStockID(GetId()) )
{
// get a stock help string
m_help = wxGetStockHelpString(GetId());
}
}
#ifndef __WXPM__
wxString wxMenuItemBase::GetLabelText(const wxString& text)
{
return wxStripMenuCodes(text);
}
#endif
#if WXWIN_COMPATIBILITY_2_8
wxString wxMenuItemBase::GetLabelFromText(const wxString& text)
{
return GetLabelText(text);
}
#endif
bool wxMenuBase::ms_locked = true;
// ----------------------------------------------------------------------------
// wxMenu ctor and dtor
// ----------------------------------------------------------------------------
void wxMenuBase::Init(long style)
{
m_menuBar = NULL;
m_menuParent = NULL;
m_invokingWindow = NULL;
m_style = style;
m_clientData = NULL;
m_eventHandler = this;
}
wxMenuBase::~wxMenuBase()
{
WX_CLEAR_LIST(wxMenuItemList, m_items);
}
// ----------------------------------------------------------------------------
// wxMenu item adding/removing
// ----------------------------------------------------------------------------
void wxMenuBase::AddSubMenu(wxMenu *submenu)
{
wxCHECK_RET( submenu, wxT("can't add a NULL submenu") );
submenu->SetParent((wxMenu *)this);
}
wxMenuItem* wxMenuBase::DoAppend(wxMenuItem *item)
{
wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Append()") );
m_items.Append(item);
item->SetMenu((wxMenu*)this);
if ( item->IsSubMenu() )
{
AddSubMenu(item->GetSubMenu());
}
return item;
}
wxMenuItem* wxMenuBase::Insert(size_t pos, wxMenuItem *item)
{
wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert") );
if ( pos == GetMenuItemCount() )
{
return DoAppend(item);
}
else
{
wxCHECK_MSG( pos < GetMenuItemCount(), NULL,
wxT("invalid index in wxMenu::Insert") );
return DoInsert(pos, item);
}
}
wxMenuItem* wxMenuBase::DoInsert(size_t pos, wxMenuItem *item)
{
wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert()") );
wxMenuItemList::compatibility_iterator node = m_items.Item(pos);
wxCHECK_MSG( node, NULL, wxT("invalid index in wxMenu::Insert()") );
m_items.Insert(node, item);
item->SetMenu((wxMenu*)this);
if ( item->IsSubMenu() )
{
AddSubMenu(item->GetSubMenu());
}
return item;
}
wxMenuItem *wxMenuBase::Remove(wxMenuItem *item)
{
wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Remove") );
return DoRemove(item);
}
wxMenuItem *wxMenuBase::DoRemove(wxMenuItem *item)
{
wxMenuItemList::compatibility_iterator node = m_items.Find(item);
// if we get here, the item is valid or one of Remove() functions is broken
wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
// we detach the item, but we do delete the list node (i.e. don't call
// DetachNode() here!)
m_items.Erase(node);
// item isn't attached to anything any more
item->SetMenu(NULL);
wxMenu *submenu = item->GetSubMenu();
if ( submenu )
{
submenu->SetParent(NULL);
if ( submenu->IsAttached() )
submenu->Detach();
}
return item;
}
bool wxMenuBase::Delete(wxMenuItem *item)
{
wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Delete") );
return DoDelete(item);
}
bool wxMenuBase::DoDelete(wxMenuItem *item)
{
wxMenuItem *item2 = DoRemove(item);
wxCHECK_MSG( item2, false, wxT("failed to delete menu item") );
// don't delete the submenu
item2->SetSubMenu(NULL);
delete item2;
return true;
}
bool wxMenuBase::Destroy(wxMenuItem *item)
{
wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Destroy") );
return DoDestroy(item);
}
bool wxMenuBase::DoDestroy(wxMenuItem *item)
{
wxMenuItem *item2 = DoRemove(item);
wxCHECK_MSG( item2, false, wxT("failed to delete menu item") );
delete item2;
return true;
}
// ----------------------------------------------------------------------------
// wxMenu searching for items
// ----------------------------------------------------------------------------
// Finds the item id matching the given string, wxNOT_FOUND if not found.
int wxMenuBase::FindItem(const wxString& text) const
{
wxString label = wxMenuItem::GetLabelText(text);
for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
node;
node = node->GetNext() )
{
wxMenuItem *item = node->GetData();
if ( item->IsSubMenu() )
{
int rc = item->GetSubMenu()->FindItem(label);
if ( rc != wxNOT_FOUND )
return rc;
}
// we execute this code for submenus as well to alllow finding them by
// name just like the ordinary items
if ( !item->IsSeparator() )
{
if ( item->GetItemLabelText() == label )
return item->GetId();
}
}
return wxNOT_FOUND;
}
// recursive search for item by id
wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const
{
if ( itemMenu )
*itemMenu = NULL;
wxMenuItem *item = NULL;
for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
node && !item;
node = node->GetNext() )
{
item = node->GetData();
if ( item->GetId() == itemId )
{
if ( itemMenu )
*itemMenu = (wxMenu *)this;
}
else if ( item->IsSubMenu() )
{
item = item->GetSubMenu()->FindItem(itemId, itemMenu);
}
else
{
// don't exit the loop
item = NULL;
}
}
return item;
}
// non recursive search
wxMenuItem *wxMenuBase::FindChildItem(int itemid, size_t *ppos) const
{
wxMenuItem *item = NULL;
wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
size_t pos;
for ( pos = 0; node; pos++ )
{
if ( node->GetData()->GetId() == itemid )
{
item = node->GetData();
break;
}
node = node->GetNext();
}
if ( ppos )
{
*ppos = item ? pos : (size_t)wxNOT_FOUND;
}
return item;
}
// find by position
wxMenuItem* wxMenuBase::FindItemByPosition(size_t position) const
{
wxCHECK_MSG( position < m_items.GetCount(), NULL,
wxT("wxMenu::FindItemByPosition(): invalid menu index") );
return m_items.Item( position )->GetData();
}
// ----------------------------------------------------------------------------
// wxMenu helpers used by derived classes
// ----------------------------------------------------------------------------
// Update a menu and all submenus recursively. source is the object that has
// the update event handlers defined for it. If NULL, the menu or associated
// window will be used.
void wxMenuBase::UpdateUI(wxEvtHandler* source)
{
wxWindow * const win = GetWindow();
if ( !source && win )
source = win->GetEventHandler();
if ( !source )
source = GetEventHandler();
if ( !source )
source = this;
wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
while ( node )
{
wxMenuItem* item = node->GetData();
if ( !item->IsSeparator() )
{
wxWindowID itemid = item->GetId();
wxUpdateUIEvent event(itemid);
event.SetEventObject( this );
if ( source->ProcessEvent(event) )
{
// if anything changed, update the changed attribute
if (event.GetSetText())
SetLabel(itemid, event.GetText());
if (event.GetSetChecked())
Check(itemid, event.GetChecked());
if (event.GetSetEnabled())
Enable(itemid, event.GetEnabled());
}
// recurse to the submenus
if ( item->GetSubMenu() )
item->GetSubMenu()->UpdateUI(source);
}
//else: item is a separator (which doesn't process update UI events)
node = node->GetNext();
}
}
bool wxMenuBase::SendEvent(int itemid, int checked)
{
wxCommandEvent event(wxEVT_MENU, itemid);
event.SetEventObject(this);
event.SetInt(checked);
wxWindow* const win = GetWindow();
wxMenuBar* const mb = GetMenuBar();
// Try the menu's event handler first
wxEvtHandler *handler = GetEventHandler();
if ( handler )
{
// Indicate to the event processing code that we're going to pass this
// event to another handler if it's not processed here to prevent it
// from passing the event to wxTheApp: this will be done below if we do
// have the associated window.
if ( win || mb )
event.SetWillBeProcessedAgain();
if ( handler->SafelyProcessEvent(event) )
return true;
}
// If this menu is part of the menu bar, process the event there: this will
// also propagate it upwards to the window containing the menu bar.
if ( mb )
return mb->HandleWindowEvent(event);
// Try the window the menu was popped up from.
if ( win )
return win->HandleWindowEvent(event);
// Not processed.
return false;
}
// ----------------------------------------------------------------------------
// wxMenu attaching/detaching to/from menu bar
// ----------------------------------------------------------------------------
wxMenuBar* wxMenuBase::GetMenuBar() const
{
if(GetParent())
return GetParent()->GetMenuBar();
return m_menuBar;
}
void wxMenuBase::Attach(wxMenuBarBase *menubar)
{
// use Detach() instead!
wxASSERT_MSG( menubar, wxT("menu can't be attached to NULL menubar") );
// use IsAttached() to prevent this from happening
wxASSERT_MSG( !m_menuBar, wxT("attaching menu twice?") );
m_menuBar = (wxMenuBar *)menubar;
}
void wxMenuBase::Detach()
{
// use IsAttached() to prevent this from happening
wxASSERT_MSG( m_menuBar, wxT("detaching unattached menu?") );
m_menuBar = NULL;
}
// ----------------------------------------------------------------------------
// wxMenu invoking window handling
// ----------------------------------------------------------------------------
void wxMenuBase::SetInvokingWindow(wxWindow *win)
{
wxASSERT_MSG( !GetParent(),
"should only be called for top level popup menus" );
wxASSERT_MSG( !IsAttached(),
"menus attached to menu bar can't have invoking window" );
m_invokingWindow = win;
}
wxWindow *wxMenuBase::GetWindow() const
{
// only the top level menus have non-NULL invoking window or a pointer to
// the menu bar so recurse upwards until we find it
const wxMenuBase *menu = this;
while ( menu->GetParent() )
{
menu = menu->GetParent();
}
return menu->GetMenuBar() ? menu->GetMenuBar()->GetFrame()
: menu->GetInvokingWindow();
}
// ----------------------------------------------------------------------------
// wxMenu functions forwarded to wxMenuItem
// ----------------------------------------------------------------------------
void wxMenuBase::Enable( int itemid, bool enable )
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") );
item->Enable(enable);
}
bool wxMenuBase::IsEnabled( int itemid ) const
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_MSG( item, false, wxT("wxMenu::IsEnabled: no such item") );
return item->IsEnabled();
}
void wxMenuBase::Check( int itemid, bool enable )
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_RET( item, wxT("wxMenu::Check: no such item") );
item->Check(enable);
}
bool wxMenuBase::IsChecked( int itemid ) const
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_MSG( item, false, wxT("wxMenu::IsChecked: no such item") );
return item->IsChecked();
}
void wxMenuBase::SetLabel( int itemid, const wxString &label )
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") );
item->SetItemLabel(label);
}
wxString wxMenuBase::GetLabel( int itemid ) const
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetLabel: no such item") );
return item->GetItemLabel();
}
void wxMenuBase::SetHelpString( int itemid, const wxString& helpString )
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") );
item->SetHelp( helpString );
}
wxString wxMenuBase::GetHelpString( int itemid ) const
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetHelpString: no such item") );
return item->GetHelp();
}
// ----------------------------------------------------------------------------
// wxMenuBarBase ctor and dtor
// ----------------------------------------------------------------------------
wxMenuBarBase::wxMenuBarBase()
{
// not attached yet
m_menuBarFrame = NULL;
}
wxMenuBarBase::~wxMenuBarBase()
{
WX_CLEAR_LIST(wxMenuList, m_menus);
}
// ----------------------------------------------------------------------------
// wxMenuBar item access: the base class versions manage m_menus list, the
// derived class should reflect the changes in the real menubar
// ----------------------------------------------------------------------------
wxMenu *wxMenuBarBase::GetMenu(size_t pos) const
{
wxMenuList::compatibility_iterator node = m_menus.Item(pos);
wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") );
return node->GetData();
}
bool wxMenuBarBase::Append(wxMenu *menu, const wxString& title)
{
wxCHECK_MSG( menu, false, wxT("can't append NULL menu") );
wxCHECK_MSG( !title.empty(), false, wxT("can't append menu with empty title") );
m_menus.Append(menu);
menu->Attach(this);
return true;
}
bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu,
const wxString& title)
{
if ( pos == m_menus.GetCount() )
{
return wxMenuBarBase::Append(menu, title);
}
else // not at the end
{
wxCHECK_MSG( menu, false, wxT("can't insert NULL menu") );
wxMenuList::compatibility_iterator node = m_menus.Item(pos);
wxCHECK_MSG( node, false, wxT("bad index in wxMenuBar::Insert()") );
m_menus.Insert(node, menu);
menu->Attach(this);
return true;
}
}
wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu,
const wxString& WXUNUSED(title))
{
wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") );
wxMenuList::compatibility_iterator node = m_menus.Item(pos);
wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") );
wxMenu *menuOld = node->GetData();
node->SetData(menu);
menu->Attach(this);
menuOld->Detach();
return menuOld;
}
wxMenu *wxMenuBarBase::Remove(size_t pos)
{
wxMenuList::compatibility_iterator node = m_menus.Item(pos);
wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") );
wxMenu *menu = node->GetData();
m_menus.Erase(node);
menu->Detach();
return menu;
}
int wxMenuBarBase::FindMenu(const wxString& title) const
{
wxString label = wxMenuItem::GetLabelText(title);
size_t count = GetMenuCount();
for ( size_t i = 0; i < count; i++ )
{
wxString title2 = GetMenuLabel(i);
if ( (title2 == title) ||
(wxMenuItem::GetLabelText(title2) == label) )
{
// found
return (int)i;
}
}
return wxNOT_FOUND;
}
// ----------------------------------------------------------------------------
// wxMenuBar attaching/detaching to/from the frame
// ----------------------------------------------------------------------------
void wxMenuBarBase::Attach(wxFrame *frame)
{
wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
m_menuBarFrame = frame;
}
void wxMenuBarBase::Detach()
{
wxASSERT_MSG( IsAttached(), wxT("detaching unattached menubar") );
m_menuBarFrame = NULL;
}
// ----------------------------------------------------------------------------
// wxMenuBar searching for items
// ----------------------------------------------------------------------------
wxMenuItem *wxMenuBarBase::FindItem(int itemid, wxMenu **menu) const
{
if ( menu )
*menu = NULL;
wxMenuItem *item = NULL;
size_t count = GetMenuCount(), i;
wxMenuList::const_iterator it;
for ( i = 0, it = m_menus.begin(); !item && (i < count); i++, it++ )
{
item = (*it)->FindItem(itemid, menu);
}
return item;
}
int wxMenuBarBase::FindMenuItem(const wxString& menu, const wxString& item) const
{
wxString label = wxMenuItem::GetLabelText(menu);
int i = 0;
wxMenuList::compatibility_iterator node;
for ( node = m_menus.GetFirst(); node; node = node->GetNext(), i++ )
{
if ( label == wxMenuItem::GetLabelText(GetMenuLabel(i)) )
return node->GetData()->FindItem(item);
}
return wxNOT_FOUND;
}
// ---------------------------------------------------------------------------
// wxMenuBar functions forwarded to wxMenuItem
// ---------------------------------------------------------------------------
void wxMenuBarBase::Enable(int itemid, bool enable)
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") );
item->Enable(enable);
}
void wxMenuBarBase::Check(int itemid, bool check)
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") );
wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") );
item->Check(check);
}
bool wxMenuBarBase::IsChecked(int itemid) const
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_MSG( item, false, wxT("wxMenuBar::IsChecked(): no such item") );
return item->IsChecked();
}
bool wxMenuBarBase::IsEnabled(int itemid) const
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_MSG( item, false, wxT("wxMenuBar::IsEnabled(): no such item") );
return item->IsEnabled();
}
void wxMenuBarBase::SetLabel(int itemid, const wxString& label)
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") );
item->SetItemLabel(label);
}
wxString wxMenuBarBase::GetLabel(int itemid) const
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_MSG( item, wxEmptyString,
wxT("wxMenuBar::GetLabel(): no such item") );
return item->GetItemLabel();
}
void wxMenuBarBase::SetHelpString(int itemid, const wxString& helpString)
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") );
item->SetHelp(helpString);
}
wxString wxMenuBarBase::GetHelpString(int itemid) const
{
wxMenuItem *item = FindItem(itemid);
wxCHECK_MSG( item, wxEmptyString,
wxT("wxMenuBar::GetHelpString(): no such item") );
return item->GetHelp();
}
void wxMenuBarBase::UpdateMenus()
{
wxMenu* menu;
int nCount = GetMenuCount();
for (int n = 0; n < nCount; n++)
{
menu = GetMenu( n );
if (menu != NULL)
menu->UpdateUI( NULL );
}
}
#if WXWIN_COMPATIBILITY_2_8
// get or change the label of the menu at given position
void wxMenuBarBase::SetLabelTop(size_t pos, const wxString& label)
{
SetMenuLabel(pos, label);
}
wxString wxMenuBarBase::GetLabelTop(size_t pos) const
{
return GetMenuLabelText(pos);
}
#endif
#endif // wxUSE_MENUS