From 3a46e402adfd8e0ac1f162de382e03ba92842bcb Mon Sep 17 00:00:00 2001 From: Maxim Monastirsky Date: Wed, 26 Aug 2020 14:00:50 +0300 Subject: MenuBarManager: Extract the window list to own controller Change-Id: Iad3df8cfe0814f510effaac2b7ba6dd926baab7d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101476 Tested-by: Jenkins Reviewed-by: Maxim Monastirsky --- framework/inc/menuconfiguration.hxx | 2 - framework/inc/uielement/menubarmanager.hxx | 1 - framework/source/uielement/menubarmanager.cxx | 227 +++++---------------- .../source/uielement/resourcemenucontroller.cxx | 161 ++++++++++++++- framework/util/fwk.component | 4 + 5 files changed, 219 insertions(+), 176 deletions(-) (limited to 'framework') diff --git a/framework/inc/menuconfiguration.hxx b/framework/inc/menuconfiguration.hxx index 0c8ae43545bd..84943f5326a6 100644 --- a/framework/inc/menuconfiguration.hxx +++ b/framework/inc/menuconfiguration.hxx @@ -29,8 +29,6 @@ namespace com::sun::star::io { class XInputStream; } namespace com::sun::star::io { class XOutputStream; } namespace com::sun::star::uno { class XComponentContext; } -const sal_uInt16 START_ITEMID_WINDOWLIST = 4600; -const sal_uInt16 END_ITEMID_WINDOWLIST = 4699; const sal_uInt16 ITEMID_ADDONLIST = 6678; // used to be a SID in sfx2, now just a unique id... namespace framework diff --git a/framework/inc/uielement/menubarmanager.hxx b/framework/inc/uielement/menubarmanager.hxx index 4fa42c8e8fd1..698b46341579 100644 --- a/framework/inc/uielement/menubarmanager.hxx +++ b/framework/inc/uielement/menubarmanager.hxx @@ -162,7 +162,6 @@ class MenuBarManager final : }; void RetrieveShortcuts( std::vector< std::unique_ptr >& aMenuShortCuts ); - static void UpdateSpecialWindowMenu( Menu* pMenu, const css::uno::Reference< css::uno::XComponentContext >& xContext ); static void FillMenuImages( css::uno::Reference< css::frame::XFrame > const & xFrame, Menu* _pMenu, bool bShowMenuImages ); static void impl_RetrieveShortcutsFromConfiguration( const css::uno::Reference< css::ui::XAcceleratorConfiguration >& rAccelCfg, const css::uno::Sequence< OUString >& rCommands, diff --git a/framework/source/uielement/menubarmanager.cxx b/framework/source/uielement/menubarmanager.cxx index 5359bc712f53..eb3fe530acce 100644 --- a/framework/source/uielement/menubarmanager.cxx +++ b/framework/source/uielement/menubarmanager.cxx @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -51,10 +50,8 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -615,9 +612,6 @@ IMPL_LINK( MenuBarManager, Activate, Menu *, pMenu, bool ) m_bActive = true; - if ( m_aMenuItemCommand == aSpecialWindowCommand ) - UpdateSpecialWindowMenu( pMenu, m_xContext ); - // Check if some modes have changed so we have to update our menu images OUString sIconTheme = SvtMiscOptions().GetIconTheme(); @@ -687,64 +681,57 @@ IMPL_LINK( MenuBarManager, Activate, Menu *, pMenu, bool ) if ( !menuItemHandler->xMenuItemDispatch.is() && !menuItemHandler->xSubMenuManager.is() ) { - // There is no dispatch mechanism for the special window list menu items, - // because they are handled directly through XFrame->activate!!! - // Don't update dispatches for special file menu items. - if ( menuItemHandler->nItemId < START_ITEMID_WINDOWLIST || - menuItemHandler->nItemId >= END_ITEMID_WINDOWLIST ) - { - Reference< XDispatch > xMenuItemDispatch; + Reference< XDispatch > xMenuItemDispatch; - aTargetURL.Complete = menuItemHandler->aMenuItemURL; + aTargetURL.Complete = menuItemHandler->aMenuItemURL; - m_xURLTransformer->parseStrict( aTargetURL ); + m_xURLTransformer->parseStrict( aTargetURL ); - if ( bHasDisabledEntries ) - { - if ( aCmdOptions.Lookup( SvtCommandOptions::CMDOPTION_DISABLED, aTargetURL.Path )) - pMenu->HideItem( menuItemHandler->nItemId ); - } + if ( bHasDisabledEntries ) + { + if ( aCmdOptions.Lookup( SvtCommandOptions::CMDOPTION_DISABLED, aTargetURL.Path )) + pMenu->HideItem( menuItemHandler->nItemId ); + } - if ( aTargetURL.Complete.startsWith( ".uno:StyleApply?" ) ) - xMenuItemDispatch = new StyleDispatcher( m_xFrame, m_xURLTransformer, aTargetURL ); - else if ( m_bIsBookmarkMenu ) - xMenuItemDispatch = xDispatchProvider->queryDispatch( aTargetURL, menuItemHandler->aTargetFrame, 0 ); - else - xMenuItemDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 ); + if ( aTargetURL.Complete.startsWith( ".uno:StyleApply?" ) ) + xMenuItemDispatch = new StyleDispatcher( m_xFrame, m_xURLTransformer, aTargetURL ); + else if ( m_bIsBookmarkMenu ) + xMenuItemDispatch = xDispatchProvider->queryDispatch( aTargetURL, menuItemHandler->aTargetFrame, 0 ); + else + xMenuItemDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 ); - bool bPopupMenu( false ); - if ( !menuItemHandler->xPopupMenuController.is() && - m_xPopupMenuControllerFactory->hasController( menuItemHandler->aMenuItemURL, m_aModuleIdentifier ) ) - { - if( xMenuItemDispatch.is() || menuItemHandler->aMenuItemURL != ".uno:RecentFileList" ) - bPopupMenu = CreatePopupMenuController(menuItemHandler.get()); - } - else if ( menuItemHandler->xPopupMenuController.is() ) - { - // Force update of popup menu - menuItemHandler->xPopupMenuController->updatePopupMenu(); - bPopupMenu = true; - if (PopupMenu* pThisPopup = pMenu->GetPopupMenu( menuItemHandler->nItemId )) - pMenu->EnableItem( menuItemHandler->nItemId, pThisPopup->GetItemCount() != 0 ); - } - lcl_CheckForChildren(pMenu, menuItemHandler->nItemId); + bool bPopupMenu( false ); + if ( !menuItemHandler->xPopupMenuController.is() && + m_xPopupMenuControllerFactory->hasController( menuItemHandler->aMenuItemURL, m_aModuleIdentifier ) ) + { + if( xMenuItemDispatch.is() || menuItemHandler->aMenuItemURL != ".uno:RecentFileList" ) + bPopupMenu = CreatePopupMenuController(menuItemHandler.get()); + } + else if ( menuItemHandler->xPopupMenuController.is() ) + { + // Force update of popup menu + menuItemHandler->xPopupMenuController->updatePopupMenu(); + bPopupMenu = true; + if (PopupMenu* pThisPopup = pMenu->GetPopupMenu( menuItemHandler->nItemId )) + pMenu->EnableItem( menuItemHandler->nItemId, pThisPopup->GetItemCount() != 0 ); + } + lcl_CheckForChildren(pMenu, menuItemHandler->nItemId); + + if ( xMenuItemDispatch.is() ) + { + menuItemHandler->xMenuItemDispatch = xMenuItemDispatch; + menuItemHandler->aParsedItemURL = aTargetURL.Complete; - if ( xMenuItemDispatch.is() ) + if ( !bPopupMenu ) { - menuItemHandler->xMenuItemDispatch = xMenuItemDispatch; - menuItemHandler->aParsedItemURL = aTargetURL.Complete; - - if ( !bPopupMenu ) - { - xMenuItemDispatch->addStatusListener( static_cast< XStatusListener* >( this ), aTargetURL ); - // For the menubar, we have to keep status listening to support Ubuntu's HUD. - if ( !m_bHasMenuBar ) - xMenuItemDispatch->removeStatusListener( static_cast< XStatusListener* >( this ), aTargetURL ); - } + xMenuItemDispatch->addStatusListener( static_cast< XStatusListener* >( this ), aTargetURL ); + // For the menubar, we have to keep status listening to support Ubuntu's HUD. + if ( !m_bHasMenuBar ) + xMenuItemDispatch->removeStatusListener( static_cast< XStatusListener* >( this ), aTargetURL ); } - else if ( !bPopupMenu ) - pMenu->EnableItem( menuItemHandler->nItemId, false ); } + else if ( !bPopupMenu ) + pMenu->EnableItem( menuItemHandler->nItemId, false ); } else if ( menuItemHandler->xPopupMenuController.is() ) { @@ -826,49 +813,21 @@ IMPL_LINK( MenuBarManager, Select, Menu *, pMenu, bool ) if ( pMenu == m_pVCLMenu && pMenu->GetItemType( nCurPos ) != MenuItemType::SEPARATOR ) { - if ( nCurItemId >= START_ITEMID_WINDOWLIST && - nCurItemId <= END_ITEMID_WINDOWLIST ) + MenuItemHandler* pMenuItemHandler = GetMenuItemHandler( nCurItemId ); + if ( pMenuItemHandler && pMenuItemHandler->xMenuItemDispatch.is() ) { - // window list menu item selected - - Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( m_xContext ); + aTargetURL.Complete = pMenuItemHandler->aMenuItemURL; + m_xURLTransformer->parseStrict( aTargetURL ); - sal_uInt16 nTaskId = START_ITEMID_WINDOWLIST; - Reference< XIndexAccess > xList = xDesktop->getFrames(); - sal_Int32 nCount = xList->getCount(); - for ( sal_Int32 i=0; i xFrame; - xList->getByIndex(i) >>= xFrame; - if ( xFrame.is() && nTaskId == nCurItemId ) - { - VclPtr pWin = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() ); - pWin->GrabFocus(); - pWin->ToTop( ToTopFlags::RestoreWhenMin ); - break; - } - - nTaskId++; + // bookmark menu item selected + aArgs.realloc( 1 ); + aArgs[0].Name = "Referer"; + aArgs[0].Value <<= OUString( "private:user" ); } - } - else - { - MenuItemHandler* pMenuItemHandler = GetMenuItemHandler( nCurItemId ); - if ( pMenuItemHandler && pMenuItemHandler->xMenuItemDispatch.is() ) - { - aTargetURL.Complete = pMenuItemHandler->aMenuItemURL; - m_xURLTransformer->parseStrict( aTargetURL ); - if ( m_bIsBookmarkMenu ) - { - // bookmark menu item selected - aArgs.realloc( 1 ); - aArgs[0].Name = "Referer"; - aArgs[0].Value <<= OUString( "private:user" ); - } - - xDispatch = pMenuItemHandler->xMenuItemDispatch; - } + xDispatch = pMenuItemHandler->xMenuItemDispatch; } } } @@ -1058,23 +1017,19 @@ void MenuBarManager::FillMenuManager( Menu* pMenu, const Reference< XFrame >& rF } if ( m_xPopupMenuControllerFactory.is() && - pPopup->GetItemCount() == 0 && m_xPopupMenuControllerFactory->hasController( aItemCommand, m_aModuleIdentifier ) ) { // Check if we have to create a popup menu for a uno based popup menu controller. // We have to set an empty popup menu into our menu structure so the controller also - // works with inplace OLE. Remove old dummy popup menu! + // works with inplace OLE. MenuItemHandler* pItemHandler = new MenuItemHandler( nItemId, xStatusListener, xDispatch ); - VCLXPopupMenu* pVCLXPopupMenu = new VCLXPopupMenu; - PopupMenu* pNewPopupMenu = static_cast(pVCLXPopupMenu->GetMenu()); - pMenu->SetPopupMenu( nItemId, pNewPopupMenu ); + VCLXPopupMenu* pVCLXPopupMenu = new VCLXPopupMenu(pPopup); pItemHandler->xPopupMenu = pVCLXPopupMenu; pItemHandler->aMenuItemURL = aItemCommand; m_aMenuItemHandlerVector.push_back( std::unique_ptr(pItemHandler) ); - pPopup.disposeAndClear(); - if ( bAccessibilityEnabled ) + if ( bAccessibilityEnabled || pMenu->IsMenuBar()) { if ( CreatePopupMenuController( pItemHandler )) pItemHandler->xPopupMenuController->updatePopupMenu(); @@ -1761,78 +1716,6 @@ void MenuBarManager::SetHdl() m_xURLTransformer.set( URLTransformer::create( m_xContext) ); } -void MenuBarManager::UpdateSpecialWindowMenu( Menu* pMenu,const Reference< XComponentContext >& xContext ) -{ - // update window list - ::std::vector< OUString > aNewWindowListVector; - - Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( xContext ); - - sal_uInt16 nActiveItemId = 0; - sal_uInt16 nItemId = START_ITEMID_WINDOWLIST; - - Reference< XFrame > xCurrentFrame = xDesktop->getCurrentFrame(); - Reference< XIndexAccess > xList = xDesktop->getFrames(); - sal_Int32 nFrameCount = xList->getCount(); - aNewWindowListVector.reserve(nFrameCount); - for (sal_Int32 i=0; i xFrame; - xList->getByIndex(i) >>= xFrame; - - if (xFrame.is()) - { - if ( xFrame == xCurrentFrame ) - nActiveItemId = nItemId; - - VclPtr pWin = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() ); - OUString sWindowTitle; - if ( pWin && pWin->IsVisible() ) - sWindowTitle = pWin->GetText(); - - // tdf#101658 In case the frame is embedded somewhere, LO has no control over it. - // So we just skip it. - if ( sWindowTitle.isEmpty() ) - continue; - - aNewWindowListVector.push_back( sWindowTitle ); - ++nItemId; - } - } - - { - SolarMutexGuard g; - - int nItemCount = pMenu->GetItemCount(); - - if ( nItemCount > 0 ) - { - // remove all old window list entries from menu - sal_uInt16 nPos = pMenu->GetItemPos( START_ITEMID_WINDOWLIST ); - for ( sal_uInt16 n = nPos; n < pMenu->GetItemCount(); ) - pMenu->RemoveItem( n ); - - if ( pMenu->GetItemType( pMenu->GetItemCount()-1 ) == MenuItemType::SEPARATOR ) - pMenu->RemoveItem( pMenu->GetItemCount()-1 ); - } - - if ( !aNewWindowListVector.empty() ) - { - // append new window list entries to menu - pMenu->InsertSeparator(); - nItemId = START_ITEMID_WINDOWLIST; - const sal_uInt32 nCount = aNewWindowListVector.size(); - for ( sal_uInt32 i = 0; i < nCount; i++ ) - { - pMenu->InsertItem( nItemId, aNewWindowListVector.at( i ), MenuItemBits::RADIOCHECK ); - if ( nItemId == nActiveItemId ) - pMenu->CheckItem( nItemId ); - ++nItemId; - } - } - } -} - void MenuBarManager::FillMenuImages(Reference< XFrame > const & _xFrame, Menu* _pMenu,bool bShowMenuImages) { AddonsOptions aAddonOptions; diff --git a/framework/source/uielement/resourcemenucontroller.cxx b/framework/source/uielement/resourcemenucontroller.cxx index ea2ff5b6dbf0..6b10e152909b 100644 --- a/framework/source/uielement/resourcemenucontroller.cxx +++ b/framework/source/uielement/resourcemenucontroller.cxx @@ -5,6 +5,16 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include @@ -12,11 +22,14 @@ #include #include #include +#include #include +#include #include #include #include +#include #include #include #include @@ -61,10 +74,12 @@ private: sal_uInt16 m_nNewMenuId; rtl::Reference< framework::MenuBarManager > m_xMenuBarManager; css::uno::Reference< css::container::XIndexAccess > m_xMenuContainer; - css::uno::Reference< css::uno::XComponentContext > m_xContext; css::uno::Reference< css::ui::XUIConfigurationManager > m_xConfigManager, m_xModuleConfigManager; void addVerbs( const css::uno::Sequence< css::embed::VerbDescriptor >& rVerbs ); virtual void SAL_CALL disposing() override; + +protected: + css::uno::Reference< css::uno::XComponentContext > m_xContext; }; ResourceMenuController::ResourceMenuController( const css::uno::Reference< css::uno::XComponentContext >& rxContext, @@ -386,6 +401,142 @@ OUString SaveAsMenuController::getImplementationName() return "com.sun.star.comp.framework.SaveAsMenuController"; } +class WindowListMenuController : public ResourceMenuController +{ +public: + using ResourceMenuController::ResourceMenuController; + + // XMenuListener + void SAL_CALL itemActivated( const css::awt::MenuEvent& rEvent ) override; + void SAL_CALL itemSelected( const css::awt::MenuEvent& rEvent ) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + +private: + void impl_setPopupMenu() override; +}; + +constexpr sal_uInt16 START_ITEMID_WINDOWLIST = 4600; +constexpr sal_uInt16 END_ITEMID_WINDOWLIST = 4699; + +void WindowListMenuController::itemActivated( const css::awt::MenuEvent& rEvent ) +{ + ResourceMenuController::itemActivated( rEvent ); + + // update window list + ::std::vector< OUString > aNewWindowListVector; + + css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( m_xContext ); + + sal_uInt16 nActiveItemId = 0; + sal_uInt16 nItemId = START_ITEMID_WINDOWLIST; + + css::uno::Reference< css::frame::XFrame > xCurrentFrame = xDesktop->getCurrentFrame(); + css::uno::Reference< css::container::XIndexAccess > xList = xDesktop->getFrames(); + sal_Int32 nFrameCount = xList->getCount(); + aNewWindowListVector.reserve(nFrameCount); + for (sal_Int32 i=0; i xFrame; + xList->getByIndex(i) >>= xFrame; + + if (xFrame.is()) + { + if ( xFrame == xCurrentFrame ) + nActiveItemId = nItemId; + + VclPtr pWin = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() ); + OUString sWindowTitle; + if ( pWin && pWin->IsVisible() ) + sWindowTitle = pWin->GetText(); + + // tdf#101658 In case the frame is embedded somewhere, LO has no control over it. + // So we just skip it. + if ( sWindowTitle.isEmpty() ) + continue; + + aNewWindowListVector.push_back( sWindowTitle ); + ++nItemId; + } + } + + { + SolarMutexGuard g; + + VCLXMenu* pAwtMenu = comphelper::getUnoTunnelImplementation( m_xPopupMenu ); + Menu* pVCLMenu = pAwtMenu->GetMenu(); + int nItemCount = pVCLMenu->GetItemCount(); + + if ( nItemCount > 0 ) + { + // remove all old window list entries from menu + sal_uInt16 nPos = pVCLMenu->GetItemPos( START_ITEMID_WINDOWLIST ); + for ( sal_uInt16 n = nPos; n < pVCLMenu->GetItemCount(); ) + pVCLMenu->RemoveItem( n ); + + if ( pVCLMenu->GetItemType( pVCLMenu->GetItemCount()-1 ) == MenuItemType::SEPARATOR ) + pVCLMenu->RemoveItem( pVCLMenu->GetItemCount()-1 ); + } + + if ( !aNewWindowListVector.empty() ) + { + // append new window list entries to menu + pVCLMenu->InsertSeparator(); + nItemId = START_ITEMID_WINDOWLIST; + const sal_uInt32 nCount = aNewWindowListVector.size(); + for ( sal_uInt32 i = 0; i < nCount; i++ ) + { + pVCLMenu->InsertItem( nItemId, aNewWindowListVector.at( i ), MenuItemBits::RADIOCHECK ); + if ( nItemId == nActiveItemId ) + pVCLMenu->CheckItem( nItemId ); + ++nItemId; + } + } + } +} + +void WindowListMenuController::itemSelected( const css::awt::MenuEvent& rEvent ) +{ + if ( rEvent.MenuId >= START_ITEMID_WINDOWLIST && + rEvent.MenuId <= END_ITEMID_WINDOWLIST ) + { + // window list menu item selected + css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( m_xContext ); + + sal_uInt16 nTaskId = START_ITEMID_WINDOWLIST; + css::uno::Reference< css::container::XIndexAccess > xList = xDesktop->getFrames(); + sal_Int32 nCount = xList->getCount(); + for ( sal_Int32 i=0; i xFrame; + xList->getByIndex(i) >>= xFrame; + if ( xFrame.is() && nTaskId == rEvent.MenuId ) + { + VclPtr pWin = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() ); + pWin->GrabFocus(); + pWin->ToTop( ToTopFlags::RestoreWhenMin ); + break; + } + + nTaskId++; + } + } +} + +void WindowListMenuController::impl_setPopupMenu() +{ + // Make this controller work also with initially empty + // menu, which PopupMenu::ImplExecute doesn't allow. + if (m_xPopupMenu.is() && !m_xPopupMenu->getItemCount()) + m_xPopupMenu->insertSeparator(0); +} + +OUString WindowListMenuController::getImplementationName() +{ + return "com.sun.star.comp.framework.WindowListMenuController"; +} + } extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * @@ -404,6 +555,14 @@ com_sun_star_comp_framework_ToolbarAsMenuController_get_implementation( return cppu::acquire( new ResourceMenuController( context, args, true ) ); } +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_framework_WindowListMenuController_get_implementation( + css::uno::XComponentContext* context, + css::uno::Sequence< css::uno::Any > const & args ) +{ + return cppu::acquire( new WindowListMenuController( context, args, false ) ); +} + extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_framework_SaveAsMenuController_get_implementation( css::uno::XComponentContext* context, diff --git a/framework/util/fwk.component b/framework/util/fwk.component index 79538a58e8e4..e056e8a9aeb6 100644 --- a/framework/util/fwk.component +++ b/framework/util/fwk.component @@ -121,6 +121,10 @@ constructor="com_sun_star_comp_framework_SaveAsMenuController_get_implementation"> + + + -- cgit