diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /framework/source/uielement/toolbarmanager.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'framework/source/uielement/toolbarmanager.cxx')
-rw-r--r-- | framework/source/uielement/toolbarmanager.cxx | 2365 |
1 files changed, 2365 insertions, 0 deletions
diff --git a/framework/source/uielement/toolbarmanager.cxx b/framework/source/uielement/toolbarmanager.cxx new file mode 100644 index 000000000..3cce6eef4 --- /dev/null +++ b/framework/source/uielement/toolbarmanager.cxx @@ -0,0 +1,2365 @@ +/* + * 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/. + * + * 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 <sal/config.h> +#include <sal/log.hxx> + +#include <cassert> + +#include <uielement/toolbarmanager.hxx> + +#include <framework/generictoolbarcontroller.hxx> +#include <officecfg/Office/Common.hxx> +#include <uielement/styletoolbarcontroller.hxx> +#include <properties.h> +#include <framework/sfxhelperfunctions.hxx> +#include <classes/fwkresid.hxx> +#include <classes/resource.hxx> +#include <strings.hrc> +#include <uielement/toolbarmerger.hxx> + +#include <com/sun/star/ui/ItemType.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/awt/XDockableWindow.hpp> +#include <com/sun/star/frame/XLayoutManager.hpp> +#include <com/sun/star/ui/DockingArea.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/frame/ModuleManager.hpp> +#include <com/sun/star/frame/theToolbarControllerFactory.hpp> +#include <com/sun/star/ui/ItemStyle.hpp> +#include <com/sun/star/ui/XUIElementSettings.hpp> +#include <com/sun/star/ui/XUIConfigurationPersistence.hpp> +#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/ui/ImageType.hpp> +#include <com/sun/star/ui/UIElementType.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/util/URLTransformer.hpp> + +#include <svtools/toolboxcontroller.hxx> +#include <unotools/cmdoptions.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <unotools/mediadescriptor.hxx> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/sequence.hxx> +#include <svtools/miscopt.hxx> +#include <svtools/imgdef.hxx> +#include <utility> +#include <vcl/event.hxx> +#include <vcl/graph.hxx> +#include <vcl/svapp.hxx> +#include <vcl/menu.hxx> +#include <vcl/syswin.hxx> +#include <vcl/taskpanelist.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/settings.hxx> +#include <vcl/commandinfoprovider.hxx> +#include <vcl/weldutils.hxx> +#include <tools/debug.hxx> + +// namespaces + +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::graphic; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::ui; +using namespace ::com::sun::star; + +namespace framework +{ + +const char ITEM_DESCRIPTOR_COMMANDURL[] = "CommandURL"; +const char ITEM_DESCRIPTOR_VISIBLE[] = "IsVisible"; + +const sal_uInt16 STARTID_CUSTOMIZE_POPUPMENU = 1000; + +static css::uno::Reference< css::frame::XLayoutManager > getLayoutManagerFromFrame( + css::uno::Reference< css::frame::XFrame > const & rFrame ) +{ + css::uno::Reference< css::frame::XLayoutManager > xLayoutManager; + + Reference< XPropertySet > xPropSet( rFrame, UNO_QUERY ); + if ( xPropSet.is() ) + { + try + { + xPropSet->getPropertyValue("LayoutManager") >>= xLayoutManager; + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception&) + { + } + } + + return xLayoutManager; +} +namespace +{ + +sal_Int16 getCurrentImageType() +{ + SvtMiscOptions aMiscOptions; + sal_Int16 nImageType = css::ui::ImageType::SIZE_DEFAULT; + if (aMiscOptions.GetCurrentSymbolsSize() == SFX_SYMBOLS_SIZE_LARGE) + nImageType |= css::ui::ImageType::SIZE_LARGE; + else if (aMiscOptions.GetCurrentSymbolsSize() == SFX_SYMBOLS_SIZE_32) + nImageType |= css::ui::ImageType::SIZE_32; + return nImageType; +} + +class VclToolBarManager : public ToolBarManagerImpl +{ + DECL_LINK(Click, ToolBox*, void); + +public: + VclToolBarManager(VclPtr<ToolBox> pToolbar) + : m_pToolBar(std::move(pToolbar)) + , m_bAddedToTaskPaneList(true) + , m_pManager(nullptr) + {} + + ~VclToolBarManager() + { + OSL_ASSERT( !m_bAddedToTaskPaneList ); + } + + virtual void Init() override + { + vcl::Window* pWindow = m_pToolBar; + while ( pWindow && !pWindow->IsSystemWindow() ) + pWindow = pWindow->GetParent(); + + if ( pWindow ) + static_cast<SystemWindow *>(pWindow)->GetTaskPaneList()->AddWindow( m_pToolBar ); + } + + virtual void Destroy() override + { + OSL_ASSERT( m_pToolBar != nullptr ); + SolarMutexGuard g; + if ( m_bAddedToTaskPaneList ) + { + vcl::Window* pWindow = m_pToolBar; + while ( pWindow && !pWindow->IsSystemWindow() ) + pWindow = pWindow->GetParent(); + + if ( pWindow ) + static_cast<SystemWindow *>(pWindow)->GetTaskPaneList()->RemoveWindow( m_pToolBar ); + m_bAddedToTaskPaneList = false; + } + + // Delete the additional add-ons data + for ( ToolBox::ImplToolItems::size_type i = 0; i < m_pToolBar->GetItemCount(); i++ ) + { + ToolBoxItemId nItemId = m_pToolBar->GetItemId( i ); + if ( nItemId > ToolBoxItemId(0) ) + delete static_cast< AddonsParams* >( m_pToolBar->GetItemData( nItemId )); + } + + // #i93173# note we can still be in one of the toolbar's handlers + m_pToolBar->SetSelectHdl( Link<ToolBox *, void>() ); + m_pToolBar->SetActivateHdl( Link<ToolBox *, void>() ); + m_pToolBar->SetDeactivateHdl( Link<ToolBox *, void>() ); + m_pToolBar->SetClickHdl( Link<ToolBox *, void>() ); + m_pToolBar->SetDropdownClickHdl( Link<ToolBox *, void>() ); + m_pToolBar->SetDoubleClickHdl( Link<ToolBox *, void>() ); + m_pToolBar->SetStateChangedHdl( Link<StateChangedType const *, void>() ); + m_pToolBar->SetDataChangedHdl( Link<DataChangedEvent const *, void>() ); + + m_pToolBar.disposeAndClear(); + } + + virtual css::uno::Reference<css::awt::XWindow> GetInterface() override + { + return VCLUnoHelper::GetInterface(m_pToolBar); + } + + virtual css::uno::Reference<css::frame::XStatusListener> CreateToolBoxController( + const css::uno::Reference<css::frame::XFrame>& rFrame, + ToolBoxItemId nId, + const OUString& rCommandURL ) override + { + rtl::Reference<svt::ToolboxController> pController + = ::framework::CreateToolBoxController( rFrame, m_pToolBar, nId, rCommandURL ); + css::uno::Reference<css::frame::XStatusListener> xListener; + if (pController) + xListener = pController; + return xListener; + } + + virtual void ConnectCallbacks(ToolBarManager* pManager) override + { + m_pManager = pManager; + m_pToolBar->SetSelectHdl( LINK( pManager, ToolBarManager, Select) ); + m_pToolBar->SetClickHdl( LINK( this, VclToolBarManager, Click ) ); + m_pToolBar->SetDropdownClickHdl( LINK( pManager, ToolBarManager, DropdownClick ) ); + m_pToolBar->SetDoubleClickHdl( LINK( pManager, ToolBarManager, DoubleClick ) ); + m_pToolBar->SetStateChangedHdl( LINK( pManager, ToolBarManager, StateChanged ) ); + m_pToolBar->SetDataChangedHdl( LINK( pManager, ToolBarManager, DataChanged ) ); + + m_pToolBar->SetMenuButtonHdl( LINK( pManager, ToolBarManager, MenuButton ) ); + m_pToolBar->SetMenuExecuteHdl( LINK( pManager, ToolBarManager, MenuPreExecute ) ); + m_pToolBar->GetMenu()->SetSelectHdl( LINK( pManager, ToolBarManager, MenuSelect ) ); + } + + virtual void InsertItem(ToolBoxItemId nId, + const OUString& rString, + const OUString& rCommandURL, + const OUString& rTooltip, + const OUString& rLabel, + ToolBoxItemBits nItemBits) override + { + m_pToolBar->InsertItem( nId, rString, nItemBits ); + m_pToolBar->SetItemCommand( nId, rCommandURL ); + m_pToolBar->SetQuickHelpText(nId, rTooltip); + m_pToolBar->SetItemText( nId, rLabel ); + m_pToolBar->EnableItem( nId ); + m_pToolBar->SetItemState( nId, TRISTATE_FALSE ); + } + + virtual void InsertSeparator() override + { + m_pToolBar->InsertSeparator(); + } + + virtual void InsertSpace() override + { + m_pToolBar->InsertSpace(); + } + + virtual void InsertBreak() override + { + m_pToolBar->InsertBreak(); + } + + virtual ToolBoxItemId GetItemId(sal_uInt16 nPos) override + { + return m_pToolBar->GetItemId(nPos); + } + + virtual ToolBoxItemId GetCurItemId() override + { + return m_pToolBar->GetCurItemId(); + } + + virtual OUString GetItemCommand(ToolBoxItemId nId) override + { + return m_pToolBar->GetItemCommand(nId); + } + + virtual sal_uInt16 GetItemCount() override + { + return m_pToolBar->GetItemCount(); + } + + virtual void SetItemCheckable(ToolBoxItemId nId) override + { + m_pToolBar->SetItemBits( nId, m_pToolBar->GetItemBits( nId ) | ToolBoxItemBits::CHECKABLE ); + } + + virtual void HideItem(ToolBoxItemId nId, const OUString& /*rCommandURL*/) override + { + m_pToolBar->HideItem( nId ); + } + + virtual bool IsItemVisible(ToolBoxItemId nId, const OUString& /*rCommandURL*/) override + { + return m_pToolBar->IsItemVisible(nId); + } + + virtual void Clear() override + { + m_pToolBar->Clear(); + } + + virtual void SetName(const OUString& rName) override + { + m_pToolBar->SetText( rName ); + } + + virtual void SetHelpId(const OString& rHelpId) override + { + m_pToolBar->SetHelpId( rHelpId ); + } + + virtual bool WillUsePopupMode() override + { + return m_pToolBar->WillUsePopupMode(); + } + + virtual bool IsReallyVisible() override + { + return m_pToolBar->IsReallyVisible(); + } + + virtual void SetIconSize(ToolBoxButtonSize eSize) override + { + m_pToolBar->SetToolboxButtonSize(eSize); + } + + virtual vcl::ImageType GetImageSize() override + { + return m_pToolBar->GetImageSize(); + } + + virtual void SetMenuType(ToolBoxMenuType eType) override + { + m_pToolBar->SetMenuType( eType ); + } + + virtual void MergeToolbar(ToolBoxItemId & rItemId, + const OUString& rModuleIdentifier, + CommandToInfoMap& rCommandMap, + MergeToolbarInstruction& rInstruction) override + { + ReferenceToolbarPathInfo aRefPoint = ToolBarMerger::FindReferencePoint( m_pToolBar, rInstruction.aMergePoint ); + + // convert the sequence< sequence< propertyvalue > > structure to + // something we can better handle. A vector with item data + AddonToolbarItemContainer aItems; + ToolBarMerger::ConvertSeqSeqToVector( rInstruction.aMergeToolbarItems, aItems ); + + if ( aRefPoint.bResult ) + { + ToolBarMerger::ProcessMergeOperation( m_pToolBar, + aRefPoint.nPos, + rItemId, + rCommandMap, + rModuleIdentifier, + rInstruction.aMergeCommand, + rInstruction.aMergeCommandParameter, + aItems ); + } + else + { + ToolBarMerger::ProcessMergeFallback( m_pToolBar, + rItemId, + rCommandMap, + rModuleIdentifier, + rInstruction.aMergeCommand, + rInstruction.aMergeFallback, + aItems ); + } + } + + virtual void SetItemImage(ToolBoxItemId nId, + const OUString& /*rCommandURL*/, + const Image& rImage) override + { + m_pToolBar->SetItemImage(nId, rImage); + } + + virtual void UpdateSize() override + { + ::Size aSize = m_pToolBar->CalcWindowSizePixel(); + m_pToolBar->SetOutputSizePixel( aSize ); + } + + virtual void SetItemWindow(ToolBoxItemId nItemId, vcl::Window* pNewWindow) override + { + m_pToolBar->SetItemWindow( nItemId, pNewWindow ); + } + +private: + VclPtr<ToolBox> m_pToolBar; + bool m_bAddedToTaskPaneList; + ToolBarManager* m_pManager; +}; + +IMPL_LINK_NOARG(VclToolBarManager, Click, ToolBox*, void) +{ + m_pManager->OnClick(); +} + +class WeldToolBarManager : public ToolBarManagerImpl +{ + DECL_LINK(Click, const OString&, void); + DECL_LINK(ToggleMenuHdl, const OString&, void); + +public: + WeldToolBarManager(weld::Toolbar* pToolbar, + weld::Builder* pBuilder) + : m_pWeldedToolBar(pToolbar) + , m_pBuilder(pBuilder) + , m_pManager(nullptr) + , m_nCurrentId(0) + {} + + virtual void Init() override {} + + virtual void Destroy() override {} + + virtual css::uno::Reference<css::awt::XWindow> GetInterface() override + { + return new weld::TransportAsXWindow(m_pWeldedToolBar); + } + + virtual css::uno::Reference<css::frame::XStatusListener> CreateToolBoxController( + const css::uno::Reference<css::frame::XFrame>& rFrame, + ToolBoxItemId /*nId*/, + const OUString& rCommandURL ) override + { + css::uno::Reference<css::frame::XToolbarController> xController + = ::framework::CreateWeldToolBoxController(rFrame, m_pWeldedToolBar, m_pBuilder, rCommandURL); + css::uno::Reference<css::frame::XStatusListener> xListener; + if (xController.is()) + xListener = css::uno::Reference<css::frame::XStatusListener>( xController, UNO_QUERY ); + return xListener; + } + + virtual void ConnectCallbacks(ToolBarManager* pManager) override + { + m_pManager = pManager; + m_pWeldedToolBar->connect_clicked(LINK(this, WeldToolBarManager, Click)); + m_pWeldedToolBar->connect_menu_toggled(LINK(this, WeldToolBarManager, ToggleMenuHdl)); + } + + virtual void InsertItem(ToolBoxItemId nId, + const OUString& /*rString*/, + const OUString& rCommandURL, + const OUString& rTooltip, + const OUString& rLabel, + ToolBoxItemBits /*nItemBits*/) override + { + OString sId = OUStringToOString(rCommandURL, RTL_TEXTENCODING_UTF8); + m_aCommandToId[sId] = nId; + m_aIdToCommand[nId] = sId; + m_aCommandOrder.push_back(sId); + + m_pWeldedToolBar->insert_item(m_aCommandOrder.size(), rCommandURL); + m_pWeldedToolBar->set_item_tooltip_text(sId, rTooltip); + m_pWeldedToolBar->set_item_label( sId, rLabel ); + m_pWeldedToolBar->set_item_sensitive( sId, true ); + m_pWeldedToolBar->set_item_active( sId, false ); + } + + virtual void InsertSeparator() override + { + m_pWeldedToolBar->append_separator(""); + } + + virtual void InsertSpace() override {} + + virtual void InsertBreak() override {} + + virtual ToolBoxItemId GetItemId(sal_uInt16 nPos) override + { + return m_aCommandToId[m_aCommandOrder[nPos]]; + } + + virtual ToolBoxItemId GetCurItemId() override + { + return m_nCurrentId; + } + + virtual OUString GetItemCommand(ToolBoxItemId nId) override + { + return OStringToOUString(m_aIdToCommand[nId], RTL_TEXTENCODING_UTF8); + } + + virtual sal_uInt16 GetItemCount() override + { + return m_aCommandOrder.size(); + } + + virtual void SetItemCheckable(ToolBoxItemId /*nId*/) override {} + + virtual void HideItem(ToolBoxItemId /*nId*/, const OUString& rCommandURL) override + { + OString sId = OUStringToOString(rCommandURL, RTL_TEXTENCODING_UTF8); + m_pWeldedToolBar->set_item_visible(sId, false); + } + + virtual bool IsItemVisible(ToolBoxItemId /*nId*/, const OUString& rCommandURL) override + { + OString sId = OUStringToOString(rCommandURL, RTL_TEXTENCODING_UTF8); + return m_pWeldedToolBar->get_item_visible(sId); + } + + virtual void Clear() override {} + + virtual void SetName(const OUString& /*rName*/) override {} + + virtual void SetHelpId(const OString& /*rHelpId*/) override {} + + virtual bool WillUsePopupMode() override { return true; } + + virtual bool IsReallyVisible() override { return true; } + + virtual void SetIconSize(ToolBoxButtonSize /*eSize*/) override {} + + virtual vcl::ImageType GetImageSize() override + { + return vcl::ImageType::Size32; + } + + virtual void SetMenuType(ToolBoxMenuType /*eType*/) override {} + + virtual void MergeToolbar(ToolBoxItemId & /*rItemId*/, + const OUString& /*rModuleIdentifier*/, + CommandToInfoMap& /*rCommandMap*/, + MergeToolbarInstruction& /*rInstruction*/) override {} + + virtual void SetItemImage(ToolBoxItemId /*nId*/, + const OUString& rCommandURL, + const Image& rImage) override + { + OString sId = OUStringToOString(rCommandURL, RTL_TEXTENCODING_UTF8); + m_pWeldedToolBar->set_item_image(sId, Graphic(rImage).GetXGraphic()); + } + + virtual void UpdateSize() override {} + + virtual void SetItemWindow(ToolBoxItemId /*nItemId*/, vcl::Window* /*pNewWindow*/) override {} + +private: + weld::Toolbar* m_pWeldedToolBar; + weld::Builder* m_pBuilder; + ToolBarManager* m_pManager; + ToolBoxItemId m_nCurrentId; + std::map<const OString, ToolBoxItemId> m_aCommandToId; + std::map<ToolBoxItemId, OString> m_aIdToCommand; + std::vector<OString> m_aCommandOrder; +}; + +IMPL_LINK(WeldToolBarManager, Click, const OString&, rCommand, void) +{ + m_nCurrentId = m_aCommandToId[rCommand]; + m_pManager->OnClick(true); +} + +IMPL_LINK(WeldToolBarManager, ToggleMenuHdl, const OString&, rCommand, void) +{ + m_nCurrentId = m_aCommandToId[rCommand]; + m_pManager->OnDropdownClick(false); +} + +} // end anonymous namespace + +// XInterface, XTypeProvider, XServiceInfo + +ToolBarManager::ToolBarManager( const Reference< XComponentContext >& rxContext, + const Reference< XFrame >& rFrame, + OUString aResourceName, + ToolBox* pToolBar ) : + m_bDisposed( false ), + m_bFrameActionRegistered( false ), + m_bUpdateControllers( false ), + m_eSymbolSize(SvtMiscOptions().GetCurrentSymbolsSize()), + m_pImpl( new VclToolBarManager( pToolBar ) ), + m_pToolBar( pToolBar ), + m_aResourceName(std::move( aResourceName )), + m_xFrame( rFrame ), + m_xContext( rxContext ), + m_aAsyncUpdateControllersTimer( "framework::ToolBarManager m_aAsyncUpdateControllersTimer" ), + m_sIconTheme( SvtMiscOptions().GetIconTheme() ) +{ + Init(); +} + +ToolBarManager::ToolBarManager( const Reference< XComponentContext >& rxContext, + const Reference< XFrame >& rFrame, + OUString aResourceName, + weld::Toolbar* pToolBar, + weld::Builder* pBuilder ) : + m_bDisposed( false ), + m_bFrameActionRegistered( false ), + m_bUpdateControllers( false ), + m_eSymbolSize( SvtMiscOptions().GetCurrentSymbolsSize() ), + m_pImpl( new WeldToolBarManager( pToolBar, pBuilder ) ), + m_pToolBar( nullptr ), + m_aResourceName(std::move( aResourceName )), + m_xFrame( rFrame ), + m_xContext( rxContext ), + m_aAsyncUpdateControllersTimer( "framework::ToolBarManager m_aAsyncUpdateControllersTimer" ), + m_sIconTheme( SvtMiscOptions().GetIconTheme() ) +{ + Init(); +} + +void ToolBarManager::Init() +{ + OSL_ASSERT( m_xContext.is() ); + + m_pImpl->Init(); + + m_xToolbarControllerFactory = frame::theToolbarControllerFactory::get( m_xContext ); + m_xURLTransformer = URLTransformer::create( m_xContext ); + + m_pImpl->ConnectCallbacks(this); + + if (m_eSymbolSize == SFX_SYMBOLS_SIZE_LARGE) + m_pImpl->SetIconSize(ToolBoxButtonSize::Large); + else if (m_eSymbolSize == SFX_SYMBOLS_SIZE_32) + m_pImpl->SetIconSize(ToolBoxButtonSize::Size32); + else + m_pImpl->SetIconSize(ToolBoxButtonSize::Small); + + // enables a menu for clipped items and customization + SvtCommandOptions aCmdOptions; + ToolBoxMenuType nMenuType = ToolBoxMenuType::ClippedItems; + if ( !aCmdOptions.Lookup( SvtCommandOptions::CMDOPTION_DISABLED, "CreateDialog")) + nMenuType |= ToolBoxMenuType::Customize; + + m_pImpl->SetMenuType( nMenuType ); + + // set name for testtool, the useful part is after the last '/' + sal_Int32 idx = m_aResourceName.lastIndexOf('/'); + idx++; // will become 0 if '/' not found: use full string + std::u16string_view aToolbarName = m_aResourceName.subView( idx ); + OString aHelpIdAsString = ".HelpId:" + OUStringToOString( aToolbarName, RTL_TEXTENCODING_UTF8 ); + m_pImpl->SetHelpId( aHelpIdAsString ); + + m_aAsyncUpdateControllersTimer.SetTimeout( 50 ); + m_aAsyncUpdateControllersTimer.SetInvokeHandler( LINK( this, ToolBarManager, AsyncUpdateControllersHdl ) ); + + SvtMiscOptions().AddListenerLink( LINK( this, ToolBarManager, MiscOptionsChanged ) ); +} + +ToolBarManager::~ToolBarManager() +{ + assert(!m_aAsyncUpdateControllersTimer.IsActive()); + assert(!m_pToolBar); // must be disposed by ToolbarLayoutManager +} + +void ToolBarManager::Destroy() +{ + m_pImpl->Destroy(); + + SvtMiscOptions().RemoveListenerLink( LINK( this, ToolBarManager, MiscOptionsChanged ) ); +} + +ToolBox* ToolBarManager::GetToolBar() const +{ + SolarMutexGuard g; + return m_pToolBar; +} + +void ToolBarManager::CheckAndUpdateImages() +{ + SolarMutexGuard g; + bool bRefreshImages = false; + + SvtMiscOptions aMiscOptions; + sal_Int16 eNewSymbolSize = aMiscOptions.GetCurrentSymbolsSize(); + + if (m_eSymbolSize != eNewSymbolSize ) + { + bRefreshImages = true; + m_eSymbolSize = eNewSymbolSize; + } + + const OUString& sCurrentIconTheme = aMiscOptions.GetIconTheme(); + if ( m_sIconTheme != sCurrentIconTheme ) + { + bRefreshImages = true; + m_sIconTheme = sCurrentIconTheme; + } + + // Refresh images if requested + if ( bRefreshImages ) + RefreshImages(); +} + +void ToolBarManager::RefreshImages() +{ + SolarMutexGuard g; + + if (m_eSymbolSize == SFX_SYMBOLS_SIZE_LARGE) + m_pImpl->SetIconSize(ToolBoxButtonSize::Large); + else if (m_eSymbolSize == SFX_SYMBOLS_SIZE_32) + m_pImpl->SetIconSize(ToolBoxButtonSize::Size32); + else + m_pImpl->SetIconSize(ToolBoxButtonSize::Small); + + for ( auto const& it : m_aControllerMap ) + { + Reference< XSubToolbarController > xController( it.second, UNO_QUERY ); + if ( xController.is() && xController->opensSubToolbar() ) + { + // The button should show the last function that was selected from the + // dropdown. The controller should know better than us what it was. + xController->updateImage(); + } + else + { + OUString aCommandURL = m_pImpl->GetItemCommand( it.first ); + vcl::ImageType eImageType = m_pImpl->GetImageSize(); + Image aImage = vcl::CommandInfoProvider::GetImageForCommand(aCommandURL, m_xFrame, eImageType); + // Try also to query for add-on images before giving up and use an + // empty image. + bool bBigImages = eImageType != vcl::ImageType::Size16; + if ( !aImage ) + aImage = Image(framework::AddonsOptions().GetImageFromURL(aCommandURL, bBigImages)); + m_pImpl->SetItemImage( it.first, aCommandURL, aImage ); + } + } + + m_pImpl->UpdateSize(); +} + +void ToolBarManager::UpdateControllers() +{ + + if( officecfg::Office::Common::Misc::DisableUICustomization::get() ) + { + Any a; + Reference< XLayoutManager > xLayoutManager; + Reference< XPropertySet > xFramePropSet( m_xFrame, UNO_QUERY ); + if ( xFramePropSet.is() ) + a = xFramePropSet->getPropertyValue("LayoutManager"); + a >>= xLayoutManager; + Reference< XDockableWindow > xDockable( m_pImpl->GetInterface(), UNO_QUERY ); + if ( xLayoutManager.is() && xDockable.is() ) + { + css::awt::Point aPoint; + aPoint.X = aPoint.Y = SAL_MAX_INT32; + xLayoutManager->dockWindow( m_aResourceName, DockingArea_DOCKINGAREA_DEFAULT, aPoint ); + xLayoutManager->lockWindow( m_aResourceName ); + } + } + + if ( !m_bUpdateControllers ) + { + m_bUpdateControllers = true; + for (auto const& controller : m_aControllerMap) + { + try + { + Reference< XUpdatable > xUpdatable( controller.second, UNO_QUERY ); + if ( xUpdatable.is() ) + xUpdatable->update(); + } + catch (const Exception&) + { + } + } + } + m_bUpdateControllers = false; +} + +//for update toolbar controller via Support Visible +void ToolBarManager::UpdateController( const css::uno::Reference< css::frame::XToolbarController >& xController) +{ + + if ( !m_bUpdateControllers ) + { + m_bUpdateControllers = true; + try + { if(xController.is()) + { + Reference< XUpdatable > xUpdatable( xController, UNO_QUERY ); + if ( xUpdatable.is() ) + xUpdatable->update(); + } + } + catch (const Exception&) + { + } + + } + m_bUpdateControllers = false; +} + +void ToolBarManager::frameAction( const FrameActionEvent& Action ) +{ + SolarMutexGuard g; + if ( Action.Action == FrameAction_CONTEXT_CHANGED && !m_bDisposed ) + { + m_aAsyncUpdateControllersTimer.Start(); + } +} + +void SAL_CALL ToolBarManager::disposing( const EventObject& Source ) +{ + SolarMutexGuard g; + + if ( m_bDisposed ) + return; + + RemoveControllers(); + + if ( m_xDocImageManager.is() ) + { + try + { + m_xDocImageManager->removeConfigurationListener( + Reference< XUIConfigurationListener >(this) ); + } + catch (const Exception&) + { + } + } + + if ( m_xModuleImageManager.is() ) + { + try + { + m_xModuleImageManager->removeConfigurationListener( + Reference< XUIConfigurationListener >(this) ); + } + catch (const Exception&) + { + } + } + + m_xDocImageManager.clear(); + m_xModuleImageManager.clear(); + + if ( Source.Source == Reference< XInterface >( m_xFrame, UNO_QUERY )) + m_xFrame.clear(); + + m_xContext.clear(); +} + +// XComponent +void SAL_CALL ToolBarManager::dispose() +{ + Reference< XComponent > xThis(this); + + { + EventObject aEvent( xThis ); + std::unique_lock aGuard(m_mutex); + m_aListenerContainer.disposeAndClear( aGuard, aEvent ); + } + { + SolarMutexGuard g; + + if (m_bDisposed) + { + return; + } + + RemoveControllers(); + + if ( m_xDocImageManager.is() ) + { + try + { + m_xDocImageManager->removeConfigurationListener( + Reference< XUIConfigurationListener >(this) ); + } + catch (const Exception&) + { + } + } + m_xDocImageManager.clear(); + if ( m_xModuleImageManager.is() ) + { + try + { + m_xModuleImageManager->removeConfigurationListener( + Reference< XUIConfigurationListener >(this) ); + } + catch (const Exception&) + { + } + } + m_xModuleImageManager.clear(); + + if ( m_aOverflowManager.is() ) + { + m_aOverflowManager->dispose(); + m_aOverflowManager.clear(); + } + + // We have to destroy our toolbar instance now. + Destroy(); + m_pToolBar.clear(); + + if ( m_bFrameActionRegistered && m_xFrame.is() ) + { + try + { + m_xFrame->removeFrameActionListener( Reference< XFrameActionListener >(this) ); + } + catch (const Exception&) + { + } + } + + m_xFrame.clear(); + m_xContext.clear(); + + // stop timer to prevent timer events after dispose + // do it last because other calls could restart timer in StateChanged() + m_aAsyncUpdateControllersTimer.Stop(); + + m_bDisposed = true; + } +} + +void SAL_CALL ToolBarManager::addEventListener( const Reference< XEventListener >& xListener ) +{ + SolarMutexGuard g; + + /* SAFE AREA ----------------------------------------------------------------------------------------------- */ + if ( m_bDisposed ) + throw DisposedException(); + + std::unique_lock aGuard(m_mutex); + m_aListenerContainer.addInterface( aGuard, xListener ); +} + +void SAL_CALL ToolBarManager::removeEventListener( const Reference< XEventListener >& xListener ) +{ + std::unique_lock aGuard(m_mutex); + m_aListenerContainer.removeInterface( aGuard, xListener ); +} + +// XUIConfigurationListener +void SAL_CALL ToolBarManager::elementInserted( const css::ui::ConfigurationEvent& Event ) +{ + impl_elementChanged(false,Event); +} + +void SAL_CALL ToolBarManager::elementRemoved( const css::ui::ConfigurationEvent& Event ) +{ + impl_elementChanged(true,Event); +} +void ToolBarManager::impl_elementChanged(bool const isRemove, + const css::ui::ConfigurationEvent& Event) +{ + SolarMutexGuard g; + + /* SAFE AREA ----------------------------------------------------------------------------------------------- */ + if ( m_bDisposed ) + return; + + Reference< XNameAccess > xNameAccess; + sal_Int16 nImageType = sal_Int16(); + sal_Int16 nCurrentImageType = getCurrentImageType(); + + if (!(( Event.aInfo >>= nImageType ) && + ( nImageType == nCurrentImageType ) && + ( Event.Element >>= xNameAccess ))) + return; + + sal_Int16 nImageInfo( 1 ); + Reference< XInterface > xIfacDocImgMgr( m_xDocImageManager, UNO_QUERY ); + if ( xIfacDocImgMgr == Event.Source ) + nImageInfo = 0; + + const Sequence< OUString > aSeq = xNameAccess->getElementNames(); + for ( OUString const & commandName : aSeq ) + { + CommandToInfoMap::iterator pIter = m_aCommandMap.find( commandName ); + if ( pIter != m_aCommandMap.end() && ( pIter->second.nImageInfo >= nImageInfo )) + { + if (isRemove) + { + Image aImage; + if (( pIter->second.nImageInfo == 0 ) && ( pIter->second.nImageInfo == nImageInfo )) + { + // Special case: An image from the document image manager has been removed. + // It is possible that we have an image at our module image manager. Before + // we can remove our image we have to ask our module image manager. + Sequence< OUString > aCmdURLSeq{ pIter->first }; + Sequence< Reference< XGraphic > > aGraphicSeq; + aGraphicSeq = m_xModuleImageManager->getImages( nImageType, aCmdURLSeq ); + aImage = Image( aGraphicSeq[0] ); + } + + setToolBarImage(aImage,pIter); + } // if (isRemove) + else + { + Reference< XGraphic > xGraphic; + if ( xNameAccess->getByName( commandName ) >>= xGraphic ) + { + Image aImage( xGraphic ); + setToolBarImage(aImage,pIter); + } + pIter->second.nImageInfo = nImageInfo; + } + } + } +} +void ToolBarManager::setToolBarImage(const Image& rImage, + const CommandToInfoMap::const_iterator& rIter) +{ + const ::std::vector<ToolBoxItemId>& rIDs = rIter->second.aIds; + m_pImpl->SetItemImage( rIter->second.nId, rIter->first, rImage ); + for (auto const& it : rIDs) + { + m_pImpl->SetItemImage(it, rIter->first, rImage); + } +} + +void SAL_CALL ToolBarManager::elementReplaced( const css::ui::ConfigurationEvent& Event ) +{ + impl_elementChanged(false,Event); +} + +void ToolBarManager::RemoveControllers() +{ + DBG_TESTSOLARMUTEX(); + assert(!m_bDisposed); + + m_aSubToolBarControllerMap.clear(); + + // i90033 + // Remove item window pointers from the toolbar. They were + // destroyed by the dispose() at the XComponent. This is needed + // as VCL code later tries to access the item window data in certain + // dtors where the item window is already invalid! + for ( ToolBox::ImplToolItems::size_type i = 0; i < m_pImpl->GetItemCount(); i++ ) + { + ToolBoxItemId nItemId = m_pImpl->GetItemId( i ); + if ( nItemId > ToolBoxItemId(0) ) + { + Reference< XComponent > xComponent( m_aControllerMap[ nItemId ], UNO_QUERY ); + if ( xComponent.is() ) + { + try + { + xComponent->dispose(); + } + catch (const Exception&) + { + } + } + m_pImpl->SetItemWindow(nItemId, nullptr); + } + } + m_aControllerMap.clear(); +} + +void ToolBarManager::CreateControllers() +{ + Reference< XWindow > xToolbarWindow = m_pImpl->GetInterface(); + + css::util::URL aURL; + bool bHasDisabledEntries = SvtCommandOptions().HasEntries( SvtCommandOptions::CMDOPTION_DISABLED ); + SvtCommandOptions aCmdOptions; + + for ( ToolBox::ImplToolItems::size_type i = 0; i < m_pImpl->GetItemCount(); i++ ) + { + ToolBoxItemId nId = m_pImpl->GetItemId( i ); + if ( nId == ToolBoxItemId(0) ) + continue; + + bool bInit( true ); + bool bCreate( true ); + Reference< XStatusListener > xController; + + rtl::Reference<svt::ToolboxController> pController; + + OUString aCommandURL( m_pImpl->GetItemCommand( nId ) ); + // Command can be just an alias to another command. + auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCommandURL, m_aModuleIdentifier); + OUString aRealCommandURL( vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties) ); + if ( !aRealCommandURL.isEmpty() ) + aCommandURL = aRealCommandURL; + + if ( bHasDisabledEntries ) + { + aURL.Complete = aCommandURL; + m_xURLTransformer->parseStrict( aURL ); + if ( aCmdOptions.Lookup( SvtCommandOptions::CMDOPTION_DISABLED, aURL.Path )) + { + m_aControllerMap[ nId ] = xController; + m_pImpl->HideItem( nId, aCommandURL ); + continue; + } + } + + if ( m_xToolbarControllerFactory.is() && + m_xToolbarControllerFactory->hasController( aCommandURL, m_aModuleIdentifier )) + { + PropertyValue aPropValue; + std::vector< Any > aPropertyVector; + + aPropValue.Name = "ModuleIdentifier"; + aPropValue.Value <<= m_aModuleIdentifier; + aPropertyVector.push_back( Any( aPropValue )); + aPropValue.Name = "Frame"; + aPropValue.Value <<= m_xFrame; + aPropertyVector.push_back( Any( aPropValue )); + aPropValue.Name = "ServiceManager"; + Reference<XMultiServiceFactory> xMSF(m_xContext->getServiceManager(), UNO_QUERY_THROW); + aPropValue.Value <<= xMSF; + aPropertyVector.push_back( Any( aPropValue )); + aPropValue.Name = "ParentWindow"; + aPropValue.Value <<= xToolbarWindow; + aPropertyVector.push_back( Any( aPropValue )); + aPropValue.Name = "Identifier"; + aPropValue.Value <<= sal_uInt16(nId); + aPropertyVector.push_back( uno::Any( aPropValue ) ); + + Sequence< Any > aArgs( comphelper::containerToSequence( aPropertyVector )); + xController.set( m_xToolbarControllerFactory->createInstanceWithArgumentsAndContext( aCommandURL, aArgs, m_xContext ), + UNO_QUERY ); + bInit = false; // Initialization is done through the factory service + } + + if (( aCommandURL == ".uno:OpenUrl" ) && ( !m_pImpl->IsItemVisible(nId, aCommandURL))) + bCreate = false; + + if ( !xController.is() && bCreate ) + { + xController = m_pImpl->CreateToolBoxController( m_xFrame, nId, aCommandURL ); + if ( !xController ) + { + if ( aCommandURL.startsWith( ".uno:StyleApply?" ) ) + { + xController.set( new StyleToolbarController( m_xContext, m_xFrame, aCommandURL )); + m_pImpl->SetItemCheckable( nId ); + } + else if ( aCommandURL.startsWith( "private:resource/" ) ) + { + xController.set( m_xContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.comp.framework.GenericPopupToolbarController", m_xContext ), UNO_QUERY ); + } + else if ( m_pToolBar && m_pToolBar->GetItemData( nId ) != nullptr ) + { + // retrieve additional parameters + OUString aControlType = static_cast< AddonsParams* >( m_pToolBar->GetItemData( nId ))->aControlType; + sal_uInt16 nWidth = static_cast< AddonsParams* >( m_pToolBar->GetItemData( nId ))->nWidth; + + Reference< XStatusListener > xStatusListener( + ToolBarMerger::CreateController( m_xContext, + m_xFrame, + m_pToolBar, + aCommandURL, + nId, + nWidth, + aControlType ).get(), UNO_QUERY ); + + xController = xStatusListener; + } + else if (m_pToolBar) + { + xController.set( + new GenericToolbarController( m_xContext, m_xFrame, m_pToolBar, nId, aCommandURL )); + + // Accessibility support: Set toggle button role for specific commands + sal_Int32 nProps = vcl::CommandInfoProvider::GetPropertiesForCommand(aCommandURL, m_aModuleIdentifier); + if ( nProps & UICOMMANDDESCRIPTION_PROPERTIES_TOGGLEBUTTON ) + m_pImpl->SetItemCheckable( nId ); + } + } + } + + // Associate ID and controller to be able to retrieve + // the controller from the ID later. + m_aControllerMap[ nId ] = xController; + + // Fill sub-toolbars into our hash-map + Reference< XSubToolbarController > xSubToolBar( xController, UNO_QUERY ); + if ( xSubToolBar.is() && xSubToolBar->opensSubToolbar() ) + { + OUString aSubToolBarName = xSubToolBar->getSubToolbarName(); + if ( !aSubToolBarName.isEmpty() ) + { + SubToolBarToSubToolBarControllerMap::iterator pIter = + m_aSubToolBarControllerMap.find( aSubToolBarName ); + if ( pIter == m_aSubToolBarControllerMap.end() ) + { + SubToolBarControllerVector aSubToolBarVector; + aSubToolBarVector.push_back( xSubToolBar ); + m_aSubToolBarControllerMap.emplace( + aSubToolBarName, aSubToolBarVector ); + } + else + pIter->second.push_back( xSubToolBar ); + } + } + + Reference< XInitialization > xInit( xController, UNO_QUERY ); + if ( xInit.is() ) + { + if ( bInit ) + { + Reference<XMultiServiceFactory> xMSF(m_xContext->getServiceManager(), UNO_QUERY_THROW); + Sequence< Any > aArgs { + Any( comphelper::makePropertyValue("Frame", m_xFrame) ), + Any( comphelper::makePropertyValue("CommandURL", aCommandURL) ), + Any( comphelper::makePropertyValue("ServiceManager", xMSF) ), + Any( comphelper::makePropertyValue("ParentWindow", xToolbarWindow) ), + Any( comphelper::makePropertyValue("ModuleIdentifier", m_aModuleIdentifier) ), + Any( comphelper::makePropertyValue("Identifier", sal_uInt16(nId)) ), + }; + + xInit->initialize( aArgs ); + + if (pController) + { + if (aCommandURL == ".uno:SwitchXFormsDesignMode" || aCommandURL == ".uno:ViewDataSourceBrowser") + pController->setFastPropertyValue_NoBroadcast(1, Any(true)); + } + } + + // Request an item window from the toolbar controller and set it at the VCL toolbar + Reference< XToolbarController > xTbxController( xController, UNO_QUERY ); + if ( xTbxController.is() && xToolbarWindow.is() ) + { + Reference< XWindow > xWindow = xTbxController->createItemWindow( xToolbarWindow ); + if ( xWindow.is() ) + { + VclPtr<vcl::Window> pItemWin = VCLUnoHelper::GetWindow( xWindow ); + if ( pItemWin ) + { + WindowType nType = pItemWin->GetType(); + if ( m_pToolBar && (nType == WindowType::LISTBOX || nType == WindowType::MULTILISTBOX || nType == WindowType::COMBOBOX) ) + pItemWin->SetAccessibleName( m_pToolBar->GetItemText( nId ) ); + m_pImpl->SetItemWindow( nId, pItemWin ); + } + } + } + } + + //for update Controller via support visible state + Reference< XPropertySet > xPropSet( xController, UNO_QUERY ); + if ( xPropSet.is() ) + { + try + { + bool bSupportVisible = true; + Any a( xPropSet->getPropertyValue("SupportsVisible") ); + a >>= bSupportVisible; + if (bSupportVisible) + { + Reference< XToolbarController > xTbxController( xController, UNO_QUERY ); + UpdateController(xTbxController); + } + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception&) + { + } + } + } + + AddFrameActionListener(); +} + +void ToolBarManager::AddFrameActionListener() +{ + if ( !m_bFrameActionRegistered && m_xFrame.is() ) + { + m_bFrameActionRegistered = true; + m_xFrame->addFrameActionListener( Reference< XFrameActionListener >(this) ); + } +} + +ToolBoxItemBits ToolBarManager::ConvertStyleToToolboxItemBits( sal_Int32 nStyle ) +{ + ToolBoxItemBits nItemBits( ToolBoxItemBits::NONE ); + if ( nStyle & css::ui::ItemStyle::RADIO_CHECK ) + nItemBits |= ToolBoxItemBits::RADIOCHECK; + if ( nStyle & css::ui::ItemStyle::ALIGN_LEFT ) + nItemBits |= ToolBoxItemBits::LEFT; + if ( nStyle & css::ui::ItemStyle::AUTO_SIZE ) + nItemBits |= ToolBoxItemBits::AUTOSIZE; + if ( nStyle & css::ui::ItemStyle::DROP_DOWN ) + nItemBits |= ToolBoxItemBits::DROPDOWN; + if ( nStyle & css::ui::ItemStyle::REPEAT ) + nItemBits |= ToolBoxItemBits::REPEAT; + if ( nStyle & css::ui::ItemStyle::DROPDOWN_ONLY ) + nItemBits |= ToolBoxItemBits::DROPDOWNONLY; + if ( nStyle & css::ui::ItemStyle::TEXT ) + nItemBits |= ToolBoxItemBits::TEXT_ONLY; + if ( nStyle & css::ui::ItemStyle::ICON ) + nItemBits |= ToolBoxItemBits::ICON_ONLY; + + return nItemBits; +} + +void ToolBarManager::InitImageManager() +{ + Reference< XModuleManager2 > xModuleManager = ModuleManager::create( m_xContext ); + if ( !m_xDocImageManager.is() ) + { + Reference< XModel > xModel( GetModelFromFrame() ); + if ( xModel.is() ) + { + Reference< XUIConfigurationManagerSupplier > xSupplier( xModel, UNO_QUERY ); + if ( xSupplier.is() ) + { + Reference< XUIConfigurationManager > xDocUICfgMgr = xSupplier->getUIConfigurationManager(); + m_xDocImageManager.set( xDocUICfgMgr->getImageManager(), UNO_QUERY ); + m_xDocImageManager->addConfigurationListener( + Reference< XUIConfigurationListener >(this) ); + } + } + } + + try + { + m_aModuleIdentifier = xModuleManager->identify( Reference< XInterface >( m_xFrame, UNO_QUERY ) ); + } + catch (const Exception&) + { + } + + if ( !m_xModuleImageManager.is() ) + { + Reference< XModuleUIConfigurationManagerSupplier > xModuleCfgMgrSupplier = + theModuleUIConfigurationManagerSupplier::get( m_xContext ); + Reference< XUIConfigurationManager > xUICfgMgr = xModuleCfgMgrSupplier->getUIConfigurationManager( m_aModuleIdentifier ); + m_xModuleImageManager.set( xUICfgMgr->getImageManager(), UNO_QUERY ); + m_xModuleImageManager->addConfigurationListener( Reference< XUIConfigurationListener >(this) ); + } +} + +void ToolBarManager::FillToolbar( const Reference< XIndexAccess >& rItemContainer ) +{ + OString aTbxName = OUStringToOString( m_aResourceName, RTL_TEXTENCODING_ASCII_US ); + SAL_INFO( "fwk.uielement", "framework (cd100003) ::ToolBarManager::FillToolbar " << aTbxName ); + + SolarMutexGuard g; + + if ( m_bDisposed ) + return; + + InitImageManager(); + + RemoveControllers(); + + // reset and fill command map + m_pImpl->Clear(); + m_aControllerMap.clear(); + m_aCommandMap.clear(); + + ToolBoxItemId nId( 1 ); + CommandInfo aCmdInfo; + for ( sal_Int32 n = 0; n < rItemContainer->getCount(); n++ ) + { + Sequence< PropertyValue > aProps; + OUString aCommandURL; + OUString aLabel; + OUString aTooltip; + sal_uInt16 nType( css::ui::ItemType::DEFAULT ); + sal_uInt32 nStyle( 0 ); + + try + { + if ( rItemContainer->getByIndex( n ) >>= aProps ) + { + bool bIsVisible( true ); + for ( PropertyValue const & prop : std::as_const(aProps) ) + { + if ( prop.Name == ITEM_DESCRIPTOR_COMMANDURL ) + prop.Value >>= aCommandURL; + else if ( prop.Name == "Label" ) + prop.Value >>= aLabel; + else if ( prop.Name == "Tooltip" ) + prop.Value >>= aTooltip; + else if ( prop.Name == "Type" ) + prop.Value >>= nType; + else if ( prop.Name == ITEM_DESCRIPTOR_VISIBLE ) + prop.Value >>= bIsVisible; + else if ( prop.Name == "Style" ) + prop.Value >>= nStyle; + } + + if (!aCommandURL.isEmpty() && vcl::CommandInfoProvider::IsExperimental(aCommandURL, m_aModuleIdentifier) && + !officecfg::Office::Common::Misc::ExperimentalMode::get()) + { + continue; + } + + if (( nType == css::ui::ItemType::DEFAULT ) && !aCommandURL.isEmpty() ) + { + auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCommandURL, m_aModuleIdentifier); + if (!aProperties.hasElements()) // E.g., user-provided macro command? + aProperties = aProps; // Use existing info, including user-provided Label + OUString aString(vcl::CommandInfoProvider::GetLabelForCommand(aProperties)); + + ToolBoxItemBits nItemBits = ConvertStyleToToolboxItemBits( nStyle ); + + if ( aTooltip.isEmpty() ) + aTooltip = vcl::CommandInfoProvider::GetTooltipForCommand(aCommandURL, aProperties, m_xFrame); + + if ( aLabel.isEmpty() ) + aLabel = aString; + + m_pImpl->InsertItem(nId, aString, aCommandURL, aTooltip, aLabel, nItemBits); + + // Fill command map. It stores all our commands and from what + // image manager we got our image. So we can decide if we have to use an + // image from a notification message. + auto pIter = m_aCommandMap.emplace( aCommandURL, aCmdInfo ); + if ( pIter.second ) + { + aCmdInfo.nId = nId; + pIter.first->second.nId = nId; + } + else + { + pIter.first->second.aIds.push_back( nId ); + } + + if ( !bIsVisible ) + m_pImpl->HideItem( nId, aCommandURL ); + + ++nId; + } + else if ( nType == css::ui::ItemType::SEPARATOR_LINE ) + { + m_pImpl->InsertSeparator(); + } + else if ( nType == css::ui::ItemType::SEPARATOR_SPACE ) + { + m_pImpl->InsertSpace(); + } + else if ( nType == css::ui::ItemType::SEPARATOR_LINEBREAK ) + { + m_pImpl->InsertBreak(); + } + } + } + catch (const css::lang::IndexOutOfBoundsException&) + { + break; + } + } + + // Support add-on toolbar merging here. Working directly on the toolbar object is much + // simpler and faster. + constexpr sal_uInt16 TOOLBAR_ITEM_STARTID = 1000; + + MergeToolbarInstructionContainer aMergeInstructionContainer; + + // Retrieve the toolbar name from the resource name + OUString aToolbarName( m_aResourceName ); + sal_Int32 nIndex = aToolbarName.lastIndexOf( '/' ); + if (( nIndex > 0 ) && ( nIndex < aToolbarName.getLength() )) + aToolbarName = aToolbarName.copy( nIndex+1 ); + + AddonsOptions().GetMergeToolbarInstructions( aToolbarName, aMergeInstructionContainer ); + + if ( !aMergeInstructionContainer.empty() ) + { + ToolBoxItemId nItemId( TOOLBAR_ITEM_STARTID ); + const sal_uInt32 nCount = aMergeInstructionContainer.size(); + for ( sal_uInt32 i=0; i < nCount; i++ ) + { + MergeToolbarInstruction& rInstruction = aMergeInstructionContainer[i]; + if ( ToolBarMerger::IsCorrectContext( rInstruction.aMergeContext, m_aModuleIdentifier )) + { + m_pImpl->MergeToolbar(nItemId, m_aModuleIdentifier, m_aCommandMap, rInstruction); + } + } + } + + // Request images for all toolbar items. Must be done before CreateControllers as + // some controllers need access to the image. + RequestImages(); + + // Create controllers after we set the images. There are controllers which needs + // an image at the toolbar at creation time! + CreateControllers(); + + // Notify controllers that they are now correctly initialized and can start listening + // toolbars that will open in popup mode will be updated immediately to avoid flickering + if( m_pImpl->WillUsePopupMode() ) + UpdateControllers(); + else if ( m_pImpl->IsReallyVisible() ) + { + m_aAsyncUpdateControllersTimer.Start(); + } + + // Try to retrieve UIName from the container property set and set it as the title + // if it is not empty. + Reference< XPropertySet > xPropSet( rItemContainer, UNO_QUERY ); + if ( !xPropSet.is() ) + return; + + try + { + OUString aUIName; + xPropSet->getPropertyValue("UIName") >>= aUIName; + if ( !aUIName.isEmpty() ) + m_pImpl->SetName( aUIName ); + } + catch (const Exception&) + { + } +} + +void ToolBarManager::FillAddonToolbar( const Sequence< Sequence< PropertyValue > >& rAddonToolbar ) +{ + if (!m_pToolBar) + return; + + SolarMutexGuard g; + + if ( m_bDisposed ) + return; + + InitImageManager(); + + RemoveControllers(); + + // reset and fill command map + m_pToolBar->Clear(); + m_aControllerMap.clear(); + m_aCommandMap.clear(); + + ToolBoxItemId nId( 1 ); + CommandInfo aCmdInfo; + for ( const Sequence< PropertyValue >& rSeq : rAddonToolbar ) + { + OUString aURL; + OUString aTitle; + OUString aContext; + OUString aTarget; + OUString aControlType; + sal_uInt16 nWidth( 0 ); + + ToolBarMerger::ConvertSequenceToValues( rSeq, aURL, aTitle, aTarget, aContext, aControlType, nWidth ); + + if ( ToolBarMerger::IsCorrectContext( aContext, m_aModuleIdentifier ) ) + { + if ( aURL == "private:separator" ) + { + ToolBox::ImplToolItems::size_type nCount = m_pToolBar->GetItemCount(); + if ( nCount > 0 && m_pToolBar->GetItemType( nCount-1 ) != ToolBoxItemType::SEPARATOR ) + m_pToolBar->InsertSeparator(); + } + else + { + m_pToolBar->InsertItem( nId, aTitle ); + + OUString aShortcut(vcl::CommandInfoProvider::GetCommandShortcut(aURL, m_xFrame)); + if (!aShortcut.isEmpty()) + m_pToolBar->SetQuickHelpText(nId, aTitle + " (" + aShortcut + ")"); + + // Create AddonsParams to hold additional information we will need in the future + AddonsParams* pRuntimeItemData = new AddonsParams; + pRuntimeItemData->aControlType = aControlType; + pRuntimeItemData->nWidth = nWidth; + m_pToolBar->SetItemData( nId, pRuntimeItemData ); + m_pToolBar->SetItemCommand( nId, aURL ); + + // Fill command map. It stores all our commands and from what + // image manager we got our image. So we can decide if we have to use an + // image from a notification message. + auto pIter = m_aCommandMap.emplace( aURL, aCmdInfo ); + if ( pIter.second ) + { + aCmdInfo.nId = nId; + pIter.first->second.nId = nId; + } + else + { + pIter.first->second.aIds.push_back( nId ); + } + ++nId; + } + } + } + + // Don't setup images yet, AddonsToolbarWrapper::populateImages does that. + // (But some controllers might need an image at the toolbar at creation time!) + CreateControllers(); + + // Notify controllers that they are now correctly initialized and can start listening. + UpdateControllers(); +} + +void ToolBarManager::FillOverflowToolbar( ToolBox const * pParent ) +{ + if (!m_pToolBar) + return; + + CommandInfo aCmdInfo; + bool bInsertSeparator = false; + for ( ToolBox::ImplToolItems::size_type i = 0; i < pParent->GetItemCount(); ++i ) + { + ToolBoxItemId nId = pParent->GetItemId( i ); + if ( pParent->IsItemClipped( nId ) ) + { + if ( bInsertSeparator ) + { + m_pToolBar->InsertSeparator(); + bInsertSeparator = false; + } + + const OUString aCommandURL( pParent->GetItemCommand( nId ) ); + m_pToolBar->InsertItem( nId, pParent->GetItemText( nId ) ); + m_pToolBar->SetItemCommand( nId, aCommandURL ); + m_pToolBar->SetQuickHelpText( nId, pParent->GetQuickHelpText( nId ) ); + + // Handle possible add-on controls. + AddonsParams* pAddonParams = static_cast< AddonsParams* >( pParent->GetItemData( nId ) ); + if ( pAddonParams ) + m_pToolBar->SetItemData( nId, new AddonsParams( *pAddonParams ) ); + + // Fill command map. It stores all our commands and from what + // image manager we got our image. So we can decide if we have to use an + // image from a notification message. + auto pIter = m_aCommandMap.emplace( aCommandURL, aCmdInfo ); + if ( pIter.second ) + { + aCmdInfo.nId = nId; + pIter.first->second.nId = nId; + } + else + { + pIter.first->second.aIds.push_back( nId ); + } + } + else + { + ToolBoxItemType eType = pParent->GetItemType( i ); + if ( m_pToolBar->GetItemCount() && + ( eType == ToolBoxItemType::SEPARATOR || eType == ToolBoxItemType::BREAK ) ) + bInsertSeparator = true; + } + } + + InitImageManager(); + + // Request images for all toolbar items. Must be done before CreateControllers as + // some controllers need access to the image. + RequestImages(); + + // Create controllers after we set the images. There are controllers which needs + // an image at the toolbar at creation time! + CreateControllers(); + + // Notify controllers that they are now correctly initialized and can start listening + // toolbars that will open in popup mode will be updated immediately to avoid flickering + UpdateControllers(); +} + +void ToolBarManager::RequestImages() +{ + + // Request images from image manager + Sequence< OUString > aCmdURLSeq( comphelper::mapKeysToSequence(m_aCommandMap) ); + Sequence< Reference< XGraphic > > aDocGraphicSeq; + Sequence< Reference< XGraphic > > aModGraphicSeq; + + SvtMiscOptions aMiscOptions; + + sal_Int16 nImageType = getCurrentImageType(); + + if ( m_xDocImageManager.is() ) + aDocGraphicSeq = m_xDocImageManager->getImages(nImageType, aCmdURLSeq); + aModGraphicSeq = m_xModuleImageManager->getImages(nImageType, aCmdURLSeq); + + sal_uInt32 i = 0; + CommandToInfoMap::iterator pIter = m_aCommandMap.begin(); + CommandToInfoMap::iterator pEnd = m_aCommandMap.end(); + while ( pIter != pEnd ) + { + Image aImage; + if ( aDocGraphicSeq.hasElements() ) + aImage = Image( aDocGraphicSeq[i] ); + if ( !aImage ) + { + aImage = Image( aModGraphicSeq[i] ); + // Try also to query for add-on images before giving up and use an + // empty image. + if ( !aImage ) + aImage = Image(framework::AddonsOptions().GetImageFromURL(aCmdURLSeq[i], aMiscOptions.AreCurrentSymbolsLarge())); + + pIter->second.nImageInfo = 1; // mark image as module based + } + else + { + pIter->second.nImageInfo = 0; // mark image as document based + } + setToolBarImage(aImage,pIter); + ++pIter; + ++i; + } +} + +void ToolBarManager::notifyRegisteredControllers( const OUString& aUIElementName, const OUString& aCommand ) +{ + SolarMutexClearableGuard aGuard; + if ( m_aSubToolBarControllerMap.empty() ) + return; + + SubToolBarToSubToolBarControllerMap::const_iterator pIter = + m_aSubToolBarControllerMap.find( aUIElementName ); + + if ( pIter == m_aSubToolBarControllerMap.end() ) + return; + + const SubToolBarControllerVector& rSubToolBarVector = pIter->second; + if ( rSubToolBarVector.empty() ) + return; + + SubToolBarControllerVector aNotifyVector = rSubToolBarVector; + aGuard.clear(); + + const sal_uInt32 nCount = aNotifyVector.size(); + for ( sal_uInt32 i=0; i < nCount; i++ ) + { + try + { + Reference< XSubToolbarController > xController = aNotifyVector[i]; + if ( xController.is() ) + xController->functionSelected( aCommand ); + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception&) + { + } + } +} + +void ToolBarManager::HandleClick(ClickAction eClickAction) +{ + SolarMutexGuard g; + + if ( m_bDisposed ) + return; + + ToolBoxItemId nId( m_pImpl->GetCurItemId() ); + ToolBarControllerMap::const_iterator pIter = m_aControllerMap.find( nId ); + if ( pIter == m_aControllerMap.end() ) + return; + + Reference< XToolbarController > xController( pIter->second, UNO_QUERY ); + + if ( xController.is() ) + { + switch (eClickAction) + { + case ClickAction::Click: + xController->click(); + break; + + case ClickAction::DblClick: + xController->doubleClick(); + break; + + case ClickAction::Execute: + xController->execute(0); + break; + } + } +} + +void ToolBarManager::OnClick(bool bUseExecute) +{ + if (bUseExecute) + HandleClick(ClickAction::Execute); + else + HandleClick(ClickAction::Click); +} + +IMPL_LINK_NOARG(ToolBarManager, DropdownClick, ToolBox *, void) +{ + OnDropdownClick(true); +} + +void ToolBarManager::OnDropdownClick(bool bCreatePopupWindow) +{ + SolarMutexGuard g; + + if ( m_bDisposed ) + return; + + ToolBoxItemId nId( m_pImpl->GetCurItemId() ); + ToolBarControllerMap::const_iterator pIter = m_aControllerMap.find( nId ); + if ( pIter == m_aControllerMap.end() ) + return; + + Reference< XToolbarController > xController( pIter->second, UNO_QUERY ); + + if ( xController.is() ) + { + if (bCreatePopupWindow) + { + Reference< XWindow > xWin = xController->createPopupWindow(); + if ( xWin.is() ) + xWin->setFocus(); + } + else + { + xController->click(); + } + } +} + +IMPL_LINK_NOARG(ToolBarManager, DoubleClick, ToolBox *, void) +{ + HandleClick(ClickAction::DblClick); +} + +Reference< XModel > ToolBarManager::GetModelFromFrame() const +{ + Reference< XController > xController = m_xFrame->getController(); + Reference< XModel > xModel; + if ( xController.is() ) + xModel = xController->getModel(); + + return xModel; +} + +bool ToolBarManager::IsPluginMode() const +{ + bool bPluginMode( false ); + + if ( m_xFrame.is() ) + { + Reference< XModel > xModel = GetModelFromFrame(); + if ( xModel.is() ) + { + Sequence< PropertyValue > aSeq = xModel->getArgs(); + utl::MediaDescriptor aMediaDescriptor( aSeq ); + bPluginMode = aMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_VIEWONLY, false ); + } + } + + return bPluginMode; +} + +void ToolBarManager::AddCustomizeMenuItems(ToolBox const * pToolBar) +{ + if (!m_pToolBar) + return; + + // No config menu entries if command ".uno:ConfigureDialog" is not enabled + Reference< XDispatch > xDisp; + css::util::URL aURL; + if ( m_xFrame.is() ) + { + Reference< XDispatchProvider > xProv( m_xFrame, UNO_QUERY ); + aURL.Complete = ".uno:ConfigureDialog"; + m_xURLTransformer->parseStrict( aURL ); + if ( xProv.is() ) + xDisp = xProv->queryDispatch( aURL, OUString(), 0 ); + + if ( !xDisp.is() || IsPluginMode() ) + return; + } + + // popup menu for quick customization + bool bHideDisabledEntries = !officecfg::Office::Common::View::Menu::DontHideDisabledEntry::get(); + + ::PopupMenu *pMenu = pToolBar->GetMenu(); + + // copy all menu items 'Visible buttons, Customize toolbar, Dock toolbar, + // Dock all Toolbars) from the loaded resource into the toolbar menu + sal_uInt16 nGroupLen = pMenu->GetItemCount(); + if (nGroupLen) + pMenu->InsertSeparator(); + + VclPtr<PopupMenu> xVisibleItemsPopupMenu; + + if (!m_aResourceName.startsWith("private:resource/toolbar/addon_")) + { + pMenu->InsertItem(MENUITEM_TOOLBAR_VISIBLEBUTTON, FwkResId(STR_TOOLBAR_VISIBLE_BUTTONS)); + xVisibleItemsPopupMenu = VclPtr<PopupMenu>::Create(); + pMenu->SetPopupMenu(MENUITEM_TOOLBAR_VISIBLEBUTTON, xVisibleItemsPopupMenu); + + if (m_pToolBar->IsCustomize()) + { + pMenu->InsertItem(MENUITEM_TOOLBAR_CUSTOMIZETOOLBAR, FwkResId(STR_TOOLBAR_CUSTOMIZE_TOOLBAR)); + pMenu->SetItemCommand(MENUITEM_TOOLBAR_CUSTOMIZETOOLBAR, ".uno:ConfigureToolboxVisible"); + } + pMenu->InsertSeparator(); + } + + if (pToolBar->IsFloatingMode()) + { + pMenu->InsertItem(MENUITEM_TOOLBAR_DOCKTOOLBAR, FwkResId(STR_TOOLBAR_DOCK_TOOLBAR)); + pMenu->SetAccelKey(MENUITEM_TOOLBAR_DOCKTOOLBAR, vcl::KeyCode(KEY_F10, true, true, false, false)); + } + else + { + pMenu->InsertItem(MENUITEM_TOOLBAR_UNDOCKTOOLBAR, FwkResId(STR_TOOLBAR_UNDOCK_TOOLBAR)); + pMenu->SetAccelKey(MENUITEM_TOOLBAR_UNDOCKTOOLBAR, vcl::KeyCode(KEY_F10, true, true, false, false)); + } + + pMenu->InsertItem(MENUITEM_TOOLBAR_DOCKALLTOOLBAR, FwkResId(STR_TOOLBAR_DOCK_ALL_TOOLBARS)); + pMenu->InsertSeparator(); + pMenu->InsertItem(MENUITEM_TOOLBAR_LOCKTOOLBARPOSITION, FwkResId(STR_TOOLBAR_LOCK_TOOLBAR), MenuItemBits::CHECKABLE); + pMenu->InsertItem(MENUITEM_TOOLBAR_CLOSE, FwkResId(STR_TOOLBAR_CLOSE_TOOLBAR)); + + if (m_pToolBar->IsCustomize()) + { + bool bIsFloating( false ); + + DockingManager* pDockMgr = vcl::Window::GetDockingManager(); + if ( pDockMgr ) + bIsFloating = pDockMgr->IsFloating( m_pToolBar ); + + if ( !bIsFloating ) + { + pMenu->EnableItem(MENUITEM_TOOLBAR_DOCKALLTOOLBAR, false); + Reference< XDockableWindow > xDockable( VCLUnoHelper::GetInterface( m_pToolBar ), UNO_QUERY ); + if( xDockable.is() ) + pMenu->CheckItem(MENUITEM_TOOLBAR_LOCKTOOLBARPOSITION, xDockable->isLocked()); + } + else + pMenu->EnableItem(MENUITEM_TOOLBAR_LOCKTOOLBARPOSITION, false); + + if (officecfg::Office::Common::Misc::DisableUICustomization::get()) + { + pMenu->EnableItem(MENUITEM_TOOLBAR_VISIBLEBUTTON, false); + pMenu->EnableItem(MENUITEM_TOOLBAR_CUSTOMIZETOOLBAR, false); + pMenu->EnableItem(MENUITEM_TOOLBAR_LOCKTOOLBARPOSITION, false); + } + + // Disable menu item CLOSE if the toolbar has no closer + if( !(pToolBar->GetFloatStyle() & WB_CLOSEABLE) ) + pMenu->EnableItem(MENUITEM_TOOLBAR_CLOSE, false); + + // Temporary stores a Command --> Url map to update contextual menu with the + // correct icons. The popup icons are by default the same as those in the + // toolbar. They are not correct for contextual popup menu. + std::map< OUString, Image > commandToImage; + + if (xVisibleItemsPopupMenu) + { + // Go through all toolbar items and add them to the context menu + for ( ToolBox::ImplToolItems::size_type nPos = 0; nPos < m_pToolBar->GetItemCount(); ++nPos ) + { + if ( m_pToolBar->GetItemType(nPos) == ToolBoxItemType::BUTTON ) + { + ToolBoxItemId nId = m_pToolBar->GetItemId(nPos); + OUString aCommandURL = m_pToolBar->GetItemCommand( nId ); + xVisibleItemsPopupMenu->InsertItem( STARTID_CUSTOMIZE_POPUPMENU+nPos, m_pToolBar->GetItemText( nId ), MenuItemBits::CHECKABLE ); + xVisibleItemsPopupMenu->CheckItem( STARTID_CUSTOMIZE_POPUPMENU+nPos, m_pToolBar->IsItemVisible( nId ) ); + xVisibleItemsPopupMenu->SetItemCommand( STARTID_CUSTOMIZE_POPUPMENU+nPos, aCommandURL ); + Image aImage(vcl::CommandInfoProvider::GetImageForCommand(aCommandURL, m_xFrame)); + commandToImage[aCommandURL] = aImage; + xVisibleItemsPopupMenu->SetItemImage( STARTID_CUSTOMIZE_POPUPMENU+nPos, aImage ); + vcl::KeyCode aKeyCodeShortCut = vcl::CommandInfoProvider::GetCommandKeyCodeShortcut( aCommandURL, m_xFrame ); + xVisibleItemsPopupMenu->SetAccelKey( STARTID_CUSTOMIZE_POPUPMENU+nPos, aKeyCodeShortCut ); + } + else + { + xVisibleItemsPopupMenu->InsertSeparator(); + } + } + } + + // Now we go through all the contextual menu to update the icons + // and accelerator key shortcuts + std::map< OUString, Image >::iterator it; + for ( sal_uInt16 nPos = 0; nPos < pMenu->GetItemCount(); ++nPos ) + { + sal_uInt16 nId = pMenu->GetItemId( nPos ); + OUString cmdUrl = pMenu->GetItemCommand( nId ); + it = commandToImage.find( cmdUrl ); + if (it != commandToImage.end()) { + pMenu->SetItemImage( nId, it->second ); + } + vcl::KeyCode aKeyCodeShortCut = vcl::CommandInfoProvider::GetCommandKeyCodeShortcut( cmdUrl, m_xFrame ); + if ( aKeyCodeShortCut.GetFullCode() != 0 ) + pMenu->SetAccelKey( nId, aKeyCodeShortCut ); + } + } + + // Set the title of the menu + pMenu->SetText( pToolBar->GetText() ); + + if ( bHideDisabledEntries ) + pMenu->RemoveDisabledEntries(); +} + +IMPL_LINK( ToolBarManager, MenuButton, ToolBox*, pToolBar, void ) +{ + SolarMutexGuard g; + + if ( m_bDisposed ) + return; + + assert( !m_aOverflowManager.is() ); + + VclPtrInstance<ToolBox> pOverflowToolBar( pToolBar, WB_BORDER | WB_SCROLL ); + pOverflowToolBar->SetLineSpacing(true); + m_aOverflowManager.set( new ToolBarManager( m_xContext, m_xFrame, OUString(), pOverflowToolBar ) ); + m_aOverflowManager->FillOverflowToolbar( pToolBar ); + + ::Size aActSize( pOverflowToolBar->GetSizePixel() ); + ::Size aSize( pOverflowToolBar->CalcWindowSizePixel() ); + aSize.setWidth( aActSize.Width() ); + pOverflowToolBar->SetOutputSizePixel( aSize ); + + aSize = pOverflowToolBar->CalcPopupWindowSizePixel(); + pOverflowToolBar->SetSizePixel( aSize ); + + pOverflowToolBar->EnableDocking(); + pOverflowToolBar->AddEventListener( LINK( this, ToolBarManager, OverflowEventListener ) ); + vcl::Window::GetDockingManager()->StartPopupMode( pToolBar, pOverflowToolBar, FloatWinPopupFlags::AllMouseButtonClose ); + + // send HOME key to subtoolbar in order to select first item if keyboard activated + if(pToolBar->IsKeyEvent() ) + { + ::KeyEvent aEvent( 0, vcl::KeyCode( KEY_HOME ) ); + pOverflowToolBar->KeyInput(aEvent); + } +} + +IMPL_LINK( ToolBarManager, OverflowEventListener, VclWindowEvent&, rWindowEvent, void ) +{ + if ( rWindowEvent.GetId() != VclEventId::WindowEndPopupMode ) + return; + + if ( m_aOverflowManager.is() ) + { + m_aOverflowManager->dispose(); + m_aOverflowManager.clear(); + } +} + +IMPL_LINK( ToolBarManager, MenuPreExecute, ToolBox*, pToolBar, void ) +{ + SolarMutexGuard g; + + if ( m_bDisposed ) + return; + + AddCustomizeMenuItems( pToolBar ); +} + +IMPL_LINK( ToolBarManager, MenuSelect, Menu*, pMenu, bool ) +{ + // We have to hold a reference to ourself as it is possible that we will be disposed and + // our refcount could be zero (destruction) otherwise. + Reference< XInterface > xKeepAlive( static_cast< OWeakObject* >( this ), UNO_QUERY ); + + { + // The guard must be in its own context as the we can get destroyed when our + // own xInterface reference get destroyed! + SolarMutexGuard g; + + if ( m_bDisposed ) + return true; + + switch ( pMenu->GetCurItemId() ) + { + case MENUITEM_TOOLBAR_CUSTOMIZETOOLBAR: + { + Reference< XDispatch > xDisp; + css::util::URL aURL; + if ( m_xFrame.is() ) + { + Reference< XDispatchProvider > xProv( m_xFrame, UNO_QUERY ); + aURL.Complete = ".uno:ConfigureDialog"; + m_xURLTransformer->parseStrict( aURL ); + if ( xProv.is() ) + xDisp = xProv->queryDispatch( aURL, OUString(), 0 ); + } + + if ( xDisp.is() ) + { + Sequence< PropertyValue > aPropSeq{ comphelper::makePropertyValue( + "ResourceURL", m_aResourceName) }; + + xDisp->dispatch( aURL, aPropSeq ); + } + break; + } + + case MENUITEM_TOOLBAR_UNDOCKTOOLBAR: + { + ExecuteInfo* pExecuteInfo = new ExecuteInfo; + + pExecuteInfo->aToolbarResName = m_aResourceName; + pExecuteInfo->nCmd = EXEC_CMD_UNDOCKTOOLBAR; + pExecuteInfo->xLayoutManager = getLayoutManagerFromFrame( m_xFrame ); + + Application::PostUserEvent( LINK(nullptr, ToolBarManager, ExecuteHdl_Impl), pExecuteInfo ); + break; + } + + case MENUITEM_TOOLBAR_DOCKTOOLBAR: + { + ExecuteInfo* pExecuteInfo = new ExecuteInfo; + + pExecuteInfo->aToolbarResName = m_aResourceName; + pExecuteInfo->nCmd = EXEC_CMD_DOCKTOOLBAR; + pExecuteInfo->xLayoutManager = getLayoutManagerFromFrame( m_xFrame ); + + Application::PostUserEvent( LINK(nullptr, ToolBarManager, ExecuteHdl_Impl), pExecuteInfo ); + break; + } + + case MENUITEM_TOOLBAR_DOCKALLTOOLBAR: + { + ExecuteInfo* pExecuteInfo = new ExecuteInfo; + + pExecuteInfo->aToolbarResName = m_aResourceName; + pExecuteInfo->nCmd = EXEC_CMD_DOCKALLTOOLBARS; + pExecuteInfo->xLayoutManager = getLayoutManagerFromFrame( m_xFrame ); + + Application::PostUserEvent( LINK(nullptr, ToolBarManager, ExecuteHdl_Impl), pExecuteInfo ); + break; + } + + case MENUITEM_TOOLBAR_LOCKTOOLBARPOSITION: + { + Reference< XLayoutManager > xLayoutManager = getLayoutManagerFromFrame( m_xFrame ); + if ( xLayoutManager.is() ) + { + Reference< XDockableWindow > xDockable( VCLUnoHelper::GetInterface( m_pToolBar ), UNO_QUERY ); + + if( xDockable->isLocked() ) + xLayoutManager->unlockWindow( m_aResourceName ); + else + xLayoutManager->lockWindow( m_aResourceName ); + } + break; + } + + case MENUITEM_TOOLBAR_CLOSE: + { + ExecuteInfo* pExecuteInfo = new ExecuteInfo; + + pExecuteInfo->aToolbarResName = m_aResourceName; + pExecuteInfo->nCmd = EXEC_CMD_CLOSETOOLBAR; + pExecuteInfo->xLayoutManager = getLayoutManagerFromFrame( m_xFrame ); + pExecuteInfo->xWindow = VCLUnoHelper::GetInterface( m_pToolBar ); + + Application::PostUserEvent( LINK(nullptr, ToolBarManager, ExecuteHdl_Impl), pExecuteInfo ); + break; + } + + default: + { + sal_uInt16 nId = pMenu->GetCurItemId(); + if(( nId > 0 ) && ( nId < TOOLBOX_MENUITEM_START )) + // Items in the "enable/disable" sub-menu + { + // toggle toolbar button visibility + OUString aCommand = pMenu->GetItemCommand( nId ); + + Reference< XLayoutManager > xLayoutManager = getLayoutManagerFromFrame( m_xFrame ); + if ( xLayoutManager.is() ) + { + Reference< XUIElementSettings > xUIElementSettings( xLayoutManager->getElement( m_aResourceName ), UNO_QUERY ); + if ( xUIElementSettings.is() ) + { + Reference< XIndexContainer > xItemContainer( xUIElementSettings->getSettings( true ), UNO_QUERY ); + sal_Int32 nCount = xItemContainer->getCount(); + for ( sal_Int32 i = 0; i < nCount; i++ ) + { + Sequence< PropertyValue > aProp; + sal_Int32 nVisibleIndex( -1 ); + OUString aCommandURL; + bool bVisible( false ); + + if ( xItemContainer->getByIndex( i ) >>= aProp ) + { + for ( sal_Int32 j = 0; j < aProp.getLength(); j++ ) + { + if ( aProp[j].Name == ITEM_DESCRIPTOR_COMMANDURL ) + { + aProp[j].Value >>= aCommandURL; + } + else if ( aProp[j].Name == ITEM_DESCRIPTOR_VISIBLE ) + { + aProp[j].Value >>= bVisible; + nVisibleIndex = j; + } + } + + if (( aCommandURL == aCommand ) && ( nVisibleIndex >= 0 )) + { + // We have found the requested item, toggle the visible flag + // and write back the configuration settings to the toolbar + aProp.getArray()[nVisibleIndex].Value <<= !bVisible; + try + { + xItemContainer->replaceByIndex( i, Any( aProp )); + xUIElementSettings->setSettings( xItemContainer ); + Reference< XPropertySet > xPropSet( xUIElementSettings, UNO_QUERY ); + if ( xPropSet.is() ) + { + Reference< XUIConfigurationPersistence > xUICfgMgr; + if (( xPropSet->getPropertyValue("ConfigurationSource") >>= xUICfgMgr ) && ( xUICfgMgr.is() )) + xUICfgMgr->store(); + } + } + catch (const Exception&) + { + } + + break; + } + } + } + } + } + } + break; + } + } + } + + return true; +} + +IMPL_LINK_NOARG(ToolBarManager, Select, ToolBox *, void) +{ + if ( m_bDisposed ) + return; + + sal_Int16 nKeyModifier( static_cast<sal_Int16>(m_pToolBar->GetModifier()) ); + ToolBoxItemId nId( m_pToolBar->GetCurItemId() ); + + ToolBarControllerMap::const_iterator pIter = m_aControllerMap.find( nId ); + if ( pIter != m_aControllerMap.end() ) + { + Reference< XToolbarController > xController( pIter->second, UNO_QUERY ); + + if ( xController.is() ) + xController->execute( nKeyModifier ); + } +} + +IMPL_LINK( ToolBarManager, StateChanged, StateChangedType const *, pStateChangedType, void ) +{ + if ( m_bDisposed ) + return; + + if ( *pStateChangedType == StateChangedType::ControlBackground ) + { + CheckAndUpdateImages(); + } + else if ( *pStateChangedType == StateChangedType::Visible ) + { + if ( m_pToolBar->IsReallyVisible() ) + { + m_aAsyncUpdateControllersTimer.Start(); + } + } + else if ( *pStateChangedType == StateChangedType::InitShow ) + { + m_aAsyncUpdateControllersTimer.Start(); + } +} + +IMPL_LINK( ToolBarManager, DataChanged, DataChangedEvent const *, pDataChangedEvent, void ) +{ + if ((( pDataChangedEvent->GetType() == DataChangedEventType::SETTINGS ) || + ( pDataChangedEvent->GetType() == DataChangedEventType::DISPLAY )) && + ( pDataChangedEvent->GetFlags() & AllSettingsFlags::STYLE )) + { + CheckAndUpdateImages(); + } + + for ( ToolBox::ImplToolItems::size_type nPos = 0; nPos < m_pToolBar->GetItemCount(); ++nPos ) + { + const ToolBoxItemId nId = m_pToolBar->GetItemId(nPos); + vcl::Window* pWindow = m_pToolBar->GetItemWindow( nId ); + if ( pWindow ) + { + const DataChangedEvent& rDCEvt( *pDataChangedEvent ); + pWindow->DataChanged( rDCEvt ); + } + } + + if ( !m_pToolBar->IsFloatingMode() && + m_pToolBar->IsVisible() ) + { + // Resize toolbar, layout manager is resize listener and will calc + // the layout automatically. + ::Size aSize( m_pToolBar->CalcWindowSizePixel() ); + m_pToolBar->SetOutputSizePixel( aSize ); + } +} + +IMPL_LINK_NOARG(ToolBarManager, MiscOptionsChanged, LinkParamNone*, void) +{ + CheckAndUpdateImages(); +} + +IMPL_LINK_NOARG(ToolBarManager, AsyncUpdateControllersHdl, Timer *, void) +{ + // The guard must be in its own context as the we can get destroyed when our + // own xInterface reference get destroyed! + Reference< XComponent > xThis(this); + + SolarMutexGuard g; + + if ( m_bDisposed ) + return; + + // Request to update our controllers + m_aAsyncUpdateControllersTimer.Stop(); + UpdateControllers(); +} + +IMPL_STATIC_LINK( ToolBarManager, ExecuteHdl_Impl, void*, p, void ) +{ + ExecuteInfo* pExecuteInfo = static_cast<ExecuteInfo*>(p); + try + { + // Asynchronous execution as this can lead to our own destruction! + if (( pExecuteInfo->nCmd == EXEC_CMD_CLOSETOOLBAR ) && + ( pExecuteInfo->xLayoutManager.is() ) && + ( pExecuteInfo->xWindow.is() )) + { + // Use docking window close to close the toolbar. The toolbar layout manager is + // listener and will react correctly according to the context sensitive + // flag of our toolbar. + VclPtr<vcl::Window> pWin = VCLUnoHelper::GetWindow( pExecuteInfo->xWindow ); + DockingWindow* pDockWin = dynamic_cast< DockingWindow* >( pWin.get() ); + if ( pDockWin ) + pDockWin->Close(); + } + else if (( pExecuteInfo->nCmd == EXEC_CMD_UNDOCKTOOLBAR ) && + ( pExecuteInfo->xLayoutManager.is() )) + { + pExecuteInfo->xLayoutManager->floatWindow( pExecuteInfo->aToolbarResName ); + } + else if (( pExecuteInfo->nCmd == EXEC_CMD_DOCKTOOLBAR ) && + ( pExecuteInfo->xLayoutManager.is() )) + { + css::awt::Point aPoint; + aPoint.X = aPoint.Y = SAL_MAX_INT32; + pExecuteInfo->xLayoutManager->dockWindow( pExecuteInfo->aToolbarResName, + DockingArea_DOCKINGAREA_DEFAULT, + aPoint ); + } + else if (( pExecuteInfo->nCmd == EXEC_CMD_DOCKALLTOOLBARS ) && + ( pExecuteInfo->xLayoutManager.is() )) + { + pExecuteInfo->xLayoutManager->dockAllWindows( UIElementType::TOOLBAR ); + } + } + catch (const Exception&) + { + } + + delete pExecuteInfo; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |