diff options
author | Maxim Monastirsky <momonasmon@gmail.com> | 2015-11-27 13:03:28 +0200 |
---|---|---|
committer | Maxim Monastirsky <momonasmon@gmail.com> | 2015-11-28 18:39:13 +0000 |
commit | ac5d31ee131f5b966946af365c64ce0bb1b0d112 (patch) | |
tree | 727d79a68a726a366ae02010a509608cf40940be /framework | |
parent | df506d23a96a489934c948d5f87859ab5313e228 (diff) |
New controller to show toolbar contents as menu
Change-Id: I75911a251b0a38874068b95f496496eccc4d05fb
Reviewed-on: https://gerrit.libreoffice.org/20224
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Maxim Monastirsky <momonasmon@gmail.com>
Diffstat (limited to 'framework')
-rw-r--r-- | framework/Library_fwk.mk | 1 | ||||
-rw-r--r-- | framework/source/uielement/toolbarasmenucontroller.cxx | 362 | ||||
-rw-r--r-- | framework/util/fwk.component | 4 |
3 files changed, 367 insertions, 0 deletions
diff --git a/framework/Library_fwk.mk b/framework/Library_fwk.mk index 3efd33067caa..7cd6fe4cbe0c 100644 --- a/framework/Library_fwk.mk +++ b/framework/Library_fwk.mk @@ -155,6 +155,7 @@ $(eval $(call gb_Library_add_exception_objects,fwk,\ framework/source/uielement/subtoolbarcontroller \ framework/source/uielement/thesaurusmenucontroller \ framework/source/uielement/togglebuttontoolbarcontroller \ + framework/source/uielement/toolbarasmenucontroller \ framework/source/uielement/toolbarmanager \ framework/source/uielement/toolbarmerger \ framework/source/uielement/toolbarwrapper \ diff --git a/framework/source/uielement/toolbarasmenucontroller.cxx b/framework/source/uielement/toolbarasmenucontroller.cxx new file mode 100644 index 000000000000..83fdde469713 --- /dev/null +++ b/framework/source/uielement/toolbarasmenucontroller.cxx @@ -0,0 +1,362 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * 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/. + */ + +#include <cppuhelper/implbase.hxx> +#include <svtools/popupmenucontrollerbase.hxx> +#include <vcl/menu.hxx> + +#include <com/sun/star/ui/ItemType.hpp> +#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/util/URLTransformer.hpp> + +namespace framework { + +class CommandStatusHelper : public cppu::WeakImplHelper< css::frame::XStatusListener > +{ +public: + CommandStatusHelper( const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Reference< css::frame::XFrame >& rxFrame, + const OUString& rCommandURL ); + ~CommandStatusHelper(); + + // XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) throw ( css::uno::RuntimeException, std::exception ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& rEvent ) throw ( css::uno::RuntimeException, std::exception ) override; + + void updateCommand(); + bool isCommandEnabled() { return m_bEnabled; } + bool isCommandChecked() { return m_bChecked; } + +private: + bool m_bEnabled; + bool m_bChecked; + OUString m_aCommandURL; + css::uno::Reference< css::frame::XFrame > m_xFrame; + css::uno::Reference< css::util::XURLTransformer > m_xURLTransformer; +}; + +CommandStatusHelper::CommandStatusHelper( const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Reference< css::frame::XFrame >& rxFrame, + const OUString& rCommandURL ) : + m_bEnabled( true ), + m_bChecked( false ), + m_aCommandURL( rCommandURL ), + m_xFrame( rxFrame ), + m_xURLTransformer( css::util::URLTransformer::create( rxContext ) ) +{ +} + +CommandStatusHelper::~CommandStatusHelper() +{ +} + +void CommandStatusHelper::updateCommand() +{ + css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider( m_xFrame, css::uno::UNO_QUERY ); + if ( xDispatchProvider.is() ) + { + css::util::URL aTargetURL; + aTargetURL.Complete = m_aCommandURL; + m_xURLTransformer->parseStrict( aTargetURL ); + + css::uno::Reference< css::frame::XDispatch > xDispatch( xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 ) ); + if ( xDispatch.is() ) + { + xDispatch->addStatusListener( this, aTargetURL ); + xDispatch->removeStatusListener( this, aTargetURL ); + } + } +} + +void CommandStatusHelper::statusChanged( const css::frame::FeatureStateEvent& rEvent ) + throw ( css::uno::RuntimeException, std::exception ) +{ + OUString aStringStatus; + if ( rEvent.State >>= aStringStatus ) + { + const OUString aEnumPart( rEvent.FeatureURL.Complete.getToken( 2, '.' ) ); + if ( !aEnumPart.isEmpty() && rEvent.FeatureURL.Protocol == ".uno:" ) + m_bChecked = aStringStatus == aEnumPart; + } + rEvent.State >>= m_bChecked; + m_bEnabled = rEvent.IsEnabled; +} + +void CommandStatusHelper::disposing( const css::lang::EventObject& /*rEvent*/ ) + throw ( css::uno::RuntimeException, std::exception ) +{ + // We aren't holding reference to the dispatcher, so nothing to do here. +} + + +class ToolbarAsMenuController : public cppu::ImplInheritanceHelper< svt::PopupMenuControllerBase, css::ui::XUIConfigurationListener > +{ +public: + ToolbarAsMenuController( const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Sequence< css::uno::Any >& rxArgs ); + ~ToolbarAsMenuController(); + + // XPopupMenuController + virtual void SAL_CALL updatePopupMenu() throw ( css::uno::RuntimeException, std::exception ) override; + + // XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) throw ( css::uno::RuntimeException, std::exception ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& rEvent ) throw ( css::uno::RuntimeException, std::exception ) override; + + // XUIConfigurationListener + virtual void SAL_CALL elementInserted( const css::ui::ConfigurationEvent& rEvent ) throw ( css::uno::RuntimeException, std::exception ) override; + virtual void SAL_CALL elementRemoved( const css::ui::ConfigurationEvent& rEvent ) throw ( css::uno::RuntimeException, std::exception ) override; + virtual void SAL_CALL elementReplaced( const css::ui::ConfigurationEvent& rEvent ) throw ( css::uno::RuntimeException, std::exception ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() throw ( css::uno::RuntimeException, std::exception ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() throw ( css::uno::RuntimeException, std::exception ) override; + +private: + OUString m_aToolbarURL; + css::uno::Reference< css::container::XIndexAccess > m_xToolbarContainer; + css::uno::Reference< css::uno::XComponentContext > m_xContext; + css::uno::Reference< css::ui::XUIConfigurationManager > m_xConfigManager, m_xModuleConfigManager; + void fillPopupMenu(); + virtual void SAL_CALL disposing() override; + virtual void impl_setPopupMenu() override; +}; + +ToolbarAsMenuController::ToolbarAsMenuController( const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Sequence< css::uno::Any >& rxArgs ) : + ImplInheritanceHelper( rxContext ), + m_xContext( rxContext ) +{ + css::beans::PropertyValue aPropValue; + for ( const auto& arg: rxArgs ) + { + if ( ( arg >>= aPropValue ) && aPropValue.Name == "Value" ) + { + OUString aToolbarName; + aPropValue.Value >>= aToolbarName; + m_aToolbarURL = "private:resource/toolbar/" + aToolbarName; + break; + } + } +} + +ToolbarAsMenuController::~ToolbarAsMenuController() +{ +} + +void ToolbarAsMenuController::impl_setPopupMenu() +{ + if ( m_aToolbarURL.isEmpty() ) + return; + + if ( !m_xConfigManager.is() ) + { + try + { + css::uno::Reference< css::frame::XController > xController( m_xFrame->getController() ); + css::uno::Reference< css::frame::XModel > xModel( xController->getModel() ); + css::uno::Reference< css::ui::XUIConfigurationManagerSupplier > xSupplier( xModel, css::uno::UNO_QUERY_THROW ); + m_xConfigManager.set( xSupplier->getUIConfigurationManager() ); + css::uno::Reference< css::ui::XUIConfiguration > xConfig( m_xConfigManager, css::uno::UNO_QUERY_THROW ); + xConfig->addConfigurationListener( this ); + } + catch( const css::uno::RuntimeException& ) + {} + } + + if ( !m_xModuleConfigManager.is() ) + { + try + { + css::uno::Reference< css::ui::XModuleUIConfigurationManagerSupplier > xModuleCfgMgrSupplier( + css::ui::theModuleUIConfigurationManagerSupplier::get( m_xContext ) ); + m_xModuleConfigManager.set( xModuleCfgMgrSupplier->getUIConfigurationManager( m_aModuleName ) ); + css::uno::Reference< css::ui::XUIConfiguration > xConfig( m_xModuleConfigManager, css::uno::UNO_QUERY_THROW ); + xConfig->addConfigurationListener( this ); + } + catch ( const css::container::NoSuchElementException& ) + { + SAL_WARN( "fwk.uielement", "Invalid module identifier: " << m_aModuleName ); + } + catch( const css::uno::RuntimeException& ) + {} + } + + try + { + if ( m_xConfigManager.is() && m_xConfigManager->hasSettings( m_aToolbarURL ) ) + m_xToolbarContainer.set( m_xConfigManager->getSettings( m_aToolbarURL, sal_False ) ); + else if ( m_xModuleConfigManager.is() && m_xModuleConfigManager->hasSettings( m_aToolbarURL ) ) + m_xToolbarContainer.set( m_xModuleConfigManager->getSettings( m_aToolbarURL, sal_False ) ); + } + catch ( const css::container::NoSuchElementException& ) + { + SAL_WARN( "fwk.uielement", "Can not find settings for " << m_aToolbarURL ); + } + catch ( const css::lang::IllegalArgumentException& ) + { + SAL_WARN( "fwk.uielement", "The given URL is not valid: " << m_aToolbarURL ); + } + + fillPopupMenu(); +} + +void ToolbarAsMenuController::fillPopupMenu() +{ + resetPopupMenu( m_xPopupMenu ); + if ( !m_xToolbarContainer.is() ) + return; + + VCLXMenu* pAwtMenu = VCLXMenu::GetImplementation( m_xPopupMenu ); + Menu* pVCLMenu = pAwtMenu->GetMenu(); + + css::uno::Sequence< css::beans::PropertyValue > aPropSequence; + for ( sal_Int32 i = 0; i < m_xToolbarContainer->getCount(); ++i ) + { + try + { + if ( m_xToolbarContainer->getByIndex( i ) >>= aPropSequence ) + { + OUString aCommandURL; + sal_uInt16 nType = css::ui::ItemType::DEFAULT; + bool bVisible = true; + + for ( const auto& aProp: aPropSequence ) + { + if ( aProp.Name == "CommandURL" ) + aProp.Value >>= aCommandURL; + else if ( aProp.Name == "Type" ) + aProp.Value >>= nType; + else if ( aProp.Name == "IsVisible" ) + aProp.Value >>= bVisible; + } + + switch ( nType ) + { + case css::ui::ItemType::DEFAULT: + if ( bVisible ) + pVCLMenu->InsertItem( aCommandURL, m_xFrame ); + break; + case css::ui::ItemType::SEPARATOR_LINE: + if ( bVisible && pVCLMenu->GetItemId( pVCLMenu->GetItemCount() - 1 ) != 0 ) + pVCLMenu->InsertSeparator(); + break; + default: ; + } + } + } + catch ( const css::uno::Exception& ) + { + break; + } + } +} + +void ToolbarAsMenuController::updatePopupMenu() + throw ( css::uno::RuntimeException, std::exception ) +{ + VCLXMenu* pAwtMenu = VCLXMenu::GetImplementation( m_xPopupMenu ); + Menu* pVCLMenu = pAwtMenu->GetMenu(); + + for ( sal_uInt16 i = 0; i < pVCLMenu->GetItemCount(); ++i ) + { + const sal_uInt16 nItemId( pVCLMenu->GetItemId( i ) ); + const OUString aCommandURL( pVCLMenu->GetItemCommand( nItemId ) ); + if ( !aCommandURL.isEmpty() ) + { + rtl::Reference< CommandStatusHelper > xHelper( new CommandStatusHelper( m_xContext, m_xFrame, aCommandURL ) ); + xHelper->updateCommand(); + pVCLMenu->EnableItem( nItemId, xHelper->isCommandEnabled() ); + pVCLMenu->CheckItem( nItemId, xHelper->isCommandChecked() ); + } + } +} + +void ToolbarAsMenuController::disposing() +{ + svt::PopupMenuControllerBase::disposing(); + + css::uno::Reference< css::ui::XUIConfiguration > xConfig( m_xConfigManager, css::uno::UNO_QUERY ); + if ( xConfig.is() ) + xConfig->removeConfigurationListener( this ); + + css::uno::Reference< css::ui::XUIConfiguration > xModuleConfig( m_xModuleConfigManager, css::uno::UNO_QUERY ); + if ( xModuleConfig.is() ) + xModuleConfig->removeConfigurationListener( this ); + + m_xConfigManager.clear(); + m_xModuleConfigManager.clear(); +} + +void ToolbarAsMenuController::statusChanged( const css::frame::FeatureStateEvent& /*rEvent*/ ) + throw ( css::uno::RuntimeException, std::exception ) +{ +} + +void ToolbarAsMenuController::disposing( const css::lang::EventObject& rEvent ) + throw ( css::uno::RuntimeException, std::exception ) +{ + if ( rEvent.Source == m_xConfigManager ) + m_xConfigManager.clear(); + else if ( rEvent.Source == m_xModuleConfigManager ) + m_xModuleConfigManager.clear(); + else + svt::PopupMenuControllerBase::disposing( rEvent ); +} + +void ToolbarAsMenuController::elementInserted( const css::ui::ConfigurationEvent& rEvent ) + throw ( css::uno::RuntimeException, std::exception ) +{ + if ( rEvent.ResourceURL == m_aToolbarURL ) + impl_setPopupMenu(); +} + +void ToolbarAsMenuController::elementRemoved( const css::ui::ConfigurationEvent& rEvent ) + throw ( css::uno::RuntimeException, std::exception ) +{ + if ( rEvent.ResourceURL == m_aToolbarURL ) + impl_setPopupMenu(); +} + +void ToolbarAsMenuController::elementReplaced( const css::ui::ConfigurationEvent& rEvent ) + throw ( css::uno::RuntimeException, std::exception ) +{ + if ( rEvent.ResourceURL == m_aToolbarURL ) + impl_setPopupMenu(); +} + +OUString ToolbarAsMenuController::getImplementationName() + throw ( css::uno::RuntimeException, std::exception ) +{ + return OUString( "com.sun.star.comp.framework.ToolbarAsMenuController" ); +} + +css::uno::Sequence< OUString > ToolbarAsMenuController::getSupportedServiceNames() + throw ( css::uno::RuntimeException, std::exception ) +{ + css::uno::Sequence< OUString > aRet { "com.sun.star.frame.PopupMenuController" }; + return aRet; +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL +com_sun_star_comp_framework_ToolbarAsMenuController_get_implementation( + css::uno::XComponentContext* xContext, + css::uno::Sequence< css::uno::Any > const & args ) +{ + return cppu::acquire( new framework::ToolbarAsMenuController( xContext, args ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/util/fwk.component b/framework/util/fwk.component index 418f8159d5f2..9d5dbbc2e82a 100644 --- a/framework/util/fwk.component +++ b/framework/util/fwk.component @@ -208,4 +208,8 @@ constructor="com_sun_star_comp_framework_ThesaurusMenuController_get_implementation"> <service name="com.sun.star.frame.PopupMenuController"/> </implementation> + <implementation name="com.sun.star.comp.framework.ToolbarAsMenuController" + constructor="com_sun_star_comp_framework_ToolbarAsMenuController_get_implementation"> + <service name="com.sun.star.frame.PopupMenuController"/> + </implementation> </component> |