///////////////////////////////////////////////////////////////////////////// // Name: src/qt/menu.cpp // Author: Peter Most, Mariano Reingart // Copyright: (c) 2010 wxWidgets dev team // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #include "wx/menu.h" #include "wx/qt/private/utils.h" #include "wx/qt/private/converter.h" #include "wx/stockitem.h" #include #include static void ApplyStyle( QMenu *qtMenu, long style ) { if ( style & wxMENU_TEAROFF ) qtMenu->setTearOffEnabled( true ); } wxMenu::wxMenu(long style) : wxMenuBase( style ) { m_qtMenu = new QMenu(); ApplyStyle( m_qtMenu, style ); } wxMenu::wxMenu(const wxString& title, long style) : wxMenuBase( title, style ) { m_qtMenu = new QMenu( wxQtConvertString( title )); ApplyStyle( m_qtMenu, style ); } static wxMenuItem *GetMenuItemAt( const wxMenu *menu, size_t position ) { // FindItemByPosition() is doing the same test, but we want to prevent // the warning message it prints when an illegal index is used. if ( position < menu->GetMenuItemCount() ) return menu->FindItemByPosition( position ); else return NULL; } static void AddItemActionToGroup( const wxMenuItem *groupItem, QAction *itemAction ) { QAction *groupItemAction = groupItem->GetHandle(); QActionGroup *itemActionGroup = groupItemAction->actionGroup(); wxASSERT_MSG( itemActionGroup != NULL, "An action group should have been setup" ); itemActionGroup->addAction( itemAction ); } static void InsertMenuItemAction( const wxMenu *menu, const wxMenuItem *previousItem, wxMenuItem *item, const wxMenuItem *successiveItem ) { QMenu *qtMenu = menu->GetHandle(); QAction *itemAction = item->GetHandle(); switch ( item->GetKind() ) { case wxITEM_RADIO: // If a neighbouring menu item is a radio item then add this item to the // same action group, otherwise start a new group: if ( previousItem != NULL && previousItem->GetKind() == wxITEM_RADIO ) { AddItemActionToGroup( previousItem, itemAction ); } else if ( successiveItem != NULL && successiveItem->GetKind() == wxITEM_RADIO ) { AddItemActionToGroup( successiveItem, itemAction ); } else { QActionGroup *actionGroup = new QActionGroup( qtMenu ); actionGroup->addAction( itemAction ); item->Check(); wxASSERT_MSG( itemAction->actionGroup() == actionGroup, "Must be the same action group" ); } break; case wxITEM_NORMAL: { // If the inserted action is a submenu, set the owner for the submenu. if ( item->IsSubMenu() ) { item->GetSubMenu()->GetHandle()->setParent(qtMenu, Qt::Popup); } wxWindowID id = item->GetId(); if ( wxIsStockID( id ) ) { itemAction->setText( wxQtConvertString( wxGetStockLabel( id ) ) ); wxAcceleratorEntry accel = wxGetStockAccelerator( id ); QString shortcut; if ( id == wxID_EXIT ) { shortcut = QStringLiteral("Ctrl+Q"); } else if ( accel.IsOk() ) { shortcut = wxQtConvertString( accel.ToRawString() ); } if ( !shortcut.isEmpty() ) { itemAction->setShortcut( QKeySequence( shortcut ) ); } } break; } default: break; } // Insert the action into the actual menu: QAction *successiveItemAction = ( successiveItem != NULL ) ? successiveItem->GetHandle() : NULL; qtMenu->insertAction( successiveItemAction, itemAction ); // Menu items in Qt can be part of multiple menus, so a menu will not take ownership // when one is added to it. Take it explicitly, otherwise it will create a memory leak. itemAction->setParent(qtMenu); } wxMenuItem *wxMenu::DoAppend(wxMenuItem *item) { // Get the previous/successive items *before* we call the base class methods, // because afterwards it is less clear where these items end up: wxMenuItem *previousItem = GetMenuItemAt( this, GetMenuItemCount() - 1 ); wxMenuItem *successiveItem = GetMenuItemAt( this, GetMenuItemCount() ); if ( wxMenuBase::DoAppend( item ) == NULL ) return NULL; InsertMenuItemAction( this, previousItem, item, successiveItem ); return item; } wxMenuItem *wxMenu::DoInsert(size_t insertPosition, wxMenuItem *item) { // Get the previous/successive items *before* we call the base class methods, // because afterwards it is less clear where these items end up: wxMenuItem *previousItem = GetMenuItemAt( this, insertPosition - 1 ); wxMenuItem *successiveItem = GetMenuItemAt( this, insertPosition ); if ( wxMenuBase::DoInsert( insertPosition, item ) == NULL ) return NULL; InsertMenuItemAction( this, previousItem, item, successiveItem ); return item; } wxMenuItem *wxMenu::DoRemove(wxMenuItem *item) { if ( wxMenuBase::DoRemove( item ) == NULL ) return NULL; m_qtMenu->removeAction( item->GetHandle() ); return item; } QMenu *wxMenu::GetHandle() const { return m_qtMenu; } //############################################################################## wxMenuBar::wxMenuBar() { m_qtMenuBar = new QMenuBar(); PostCreation(false); } wxMenuBar::wxMenuBar( long WXUNUSED( style )) { m_qtMenuBar = new QMenuBar(); PostCreation(false); } wxMenuBar::wxMenuBar(size_t count, wxMenu *menus[], const wxString titles[], long WXUNUSED( style )) { m_qtMenuBar = new QMenuBar(); for ( size_t i = 0; i < count; ++i ) Append( menus[ i ], titles[ i ] ); PostCreation(false); } static QMenu *SetTitle( wxMenu *menu, const wxString &title ) { menu->SetTitle(title); QMenu *qtMenu = menu->GetHandle(); qtMenu->setTitle( wxQtConvertString( title )); return qtMenu; } bool wxMenuBar::Append( wxMenu *menu, const wxString& title ) { if ( !wxMenuBarBase::Append( menu, title )) return false; // Override the stored menu title with the given one: QMenu *qtMenu = SetTitle( menu, title ); m_qtMenuBar->addMenu( qtMenu ); // Menus in Qt can be reused as popups, so a menu bar will not take ownership when // one is added to it. Take it explicitly, otherwise there will be a memory leak. qtMenu->setParent(m_qtMenuBar, Qt::Popup); // must specify window type for correct display! return true; } static QAction *GetActionAt( const QWidget *qtWidget, size_t pos ) { QList< QAction * > actions = qtWidget->actions(); return pos < static_cast< unsigned >( actions.size() ) ? actions.at( pos ) : NULL; } bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title) { if ( !wxMenuBarBase::Insert( pos, menu, title )) return false; // Override the stored menu title with the given one: QMenu *qtMenu = SetTitle( menu, title ); QAction *qtAction = GetActionAt( m_qtMenuBar, pos ); m_qtMenuBar->insertMenu( qtAction, qtMenu ); qtMenu->setParent(m_qtMenuBar, Qt::Popup); // must specify window type for correct display! return true; } wxMenu *wxMenuBar::Remove(size_t pos) { wxMenu *menu; if (( menu = wxMenuBarBase::Remove( pos )) == NULL ) return NULL; m_qtMenuBar->removeAction( GetActionAt( m_qtMenuBar, pos )); return menu; } void wxMenuBar::EnableTop(size_t pos, bool enable) { QAction *qtAction = GetActionAt( m_qtMenuBar, pos ); qtAction->setEnabled( enable ); } bool wxMenuBar::IsEnabledTop(size_t pos) const { QAction *qtAction = GetActionAt( m_qtMenuBar, pos ); return qtAction->isEnabled(); } void wxMenuBar::SetMenuLabel(size_t pos, const wxString& label) { QAction *qtAction = GetActionAt( m_qtMenuBar, pos ); QMenu *qtMenu = qtAction->menu(); qtMenu->setTitle( wxQtConvertString( label )); } wxString wxMenuBar::GetMenuLabel(size_t pos) const { QAction *qtAction = GetActionAt( m_qtMenuBar, pos ); QMenu *qtMenu = qtAction->menu(); return wxQtConvertString( qtMenu->title() ); } void wxMenuBar::Attach(wxFrame *frame) { // sanity check as setMenuBar takes ownership wxCHECK_RET( m_qtMenuBar, "Menu bar has been previously deleted by Qt"); wxMenuBarBase::Attach(frame); } void wxMenuBar::Detach() { // the QMenuBar probably was deleted by Qt as setMenuBar takes ownership m_qtMenuBar = NULL; wxMenuBarBase::Detach(); } QWidget *wxMenuBar::GetHandle() const { return m_qtMenuBar; }