/*
* 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 <uielement/generictoolbarcontroller.hxx>
#include <uielement/styletoolbarcontroller.hxx>
#include <services.h>
#include <general.h>
#include <properties.h>
#include <framework/sfxhelperfunctions.hxx>
#include <classes/fwkresid.hxx>
#include <classes/resource.hxx>
#include <strings.hrc>
#include <framework/addonsoptions.hxx>
#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/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/sequence.hxx>
#include <svtools/miscopt.hxx>
#include <svtools/imgdef.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 <svtools/menuoptions.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
{
static const char ITEM_DESCRIPTOR_COMMANDURL[] = "CommandURL";
static const char ITEM_DESCRIPTOR_VISIBLE[] = "IsVisible";
static 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;
}
} // end anonymous namespace
// XInterface, XTypeProvider, XServiceInfo
ToolBarManager::ToolBarManager( const Reference< XComponentContext >& rxContext,
const Reference< XFrame >& rFrame,
const OUString& rResourceName,
ToolBox* pToolBar ) :
m_bDisposed( false ),
m_bAddedToTaskPaneList( true ),
m_bFrameActionRegistered( false ),
m_bUpdateControllers( false ),
m_eSymbolSize(SvtMiscOptions().GetCurrentSymbolsSize()),
m_pToolBar( pToolBar ),
m_aResourceName( rResourceName ),
m_xFrame( rFrame ),
m_aListenerContainer( m_mutex ),
m_xContext( rxContext ),
m_sIconTheme( SvtMiscOptions().GetIconTheme() )
{
OSL_ASSERT( m_xContext.is() );
vcl::Window* pWindow = m_pToolBar;
while ( pWindow && !pWindow->IsSystemWindow() )
pWindow = pWindow->GetParent();
if ( pWindow )
static_cast<SystemWindow *>(pWindow)->GetTaskPaneList()->AddWindow( m_pToolBar );
m_xToolbarControllerFactory = frame::theToolbarControllerFactory::get( m_xContext );
m_xURLTransformer = URLTransformer::create( m_xContext );
m_pToolBar->SetSelectHdl( LINK( this, ToolBarManager, Select) );
m_pToolBar->SetClickHdl( LINK( this, ToolBarManager, Click ) );
m_pToolBar->SetDropdownClickHdl( LINK( this, ToolBarManager, DropdownClick ) );
m_pToolBar->SetDoubleClickHdl( LINK( this, ToolBarManager, DoubleClick ) );
m_pToolBar->SetStateChangedHdl( LINK( this, ToolBarManager, StateChanged ) );
m_pToolBar->SetDataChangedHdl( LINK( this, ToolBarManager, DataChanged ) );
if (m_eSymbolSize == SFX_SYMBOLS_SIZE_LARGE)
m_pToolBar->SetToolboxButtonSize(ToolBoxButtonSize::Large);
else if (m_eSymbolSize == SFX_SYMBOLS_SIZE_32)
m_pToolBar->SetToolboxButtonSize(ToolBoxButtonSize::Size32);
else
m_pToolBar->SetToolboxButtonSize(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_pToolBar->SetMenuType( nMenuType );
m_pToolBar->SetMenuButtonHdl( LINK( this, ToolBarManager, MenuButton ) );
m_pToolBar->SetMenuExecuteHdl( LINK( this, ToolBarManager, MenuPreExecute ) );
m_pToolBar->GetMenu()->SetSelectHdl( LINK( this, ToolBarManager, MenuSelect ) );
// set name for testtool, the useful part is after the last '/'
sal_Int32 idx = rResourceName.lastIndexOf('/');
idx++; // will become 0 if '/' not found: use full string
OString aHelpIdAsString( ".HelpId:" );
OUString aToolbarName = rResourceName.copy( idx );
aHelpIdAsString += OUStringToOString( aToolbarName, RTL_TEXTENCODING_UTF8 );
m_pToolBar->SetHelpId( aHelpIdAsString );
m_aAsyncUpdateControllersTimer.SetTimeout( 50 );
m_aAsyncUpdateControllersTimer.SetInvokeHandler( LINK( this, ToolBarManager, AsyncUpdateControllersHdl ) );
m_aAsyncUpdateControllersTimer.SetDebugName( "framework::ToolBarManager m_aAsyncUpdateControllersTimer" );
SvtMiscOptions().AddListenerLink( LINK( this, ToolBarManager, MiscOptionsChanged ) );
}
ToolBarManager::~ToolBarManager()
{
assert(!m_aAsyncUpdateControllersTimer.IsActive());
assert(!m_pToolBar); // must be disposed by ToolbarLayoutManager
OSL_ASSERT( !m_bAddedToTaskPaneList );
}
void ToolBarManager::Destroy()
{
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++ )
{
sal_uInt16 nItemId = m_pToolBar->GetItemId( i );
if ( nItemId > 0 )
delete static_cast< AddonsParams* >( m_pToolBar->GetItemData( nItemId ));
}
// Hide toolbar as lazy delete can destroy the toolbar much later.
m_pToolBar->Hide();
// #i93173# delete toolbar lazily as we can still be in one of its handlers
// tdf#119390 this will reparent the toolbar, so focus is restored from a
// floating toolbar to the last focused control of the application window.
m_pToolBar->doLazyDelete();
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.clear();
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;
vcl::ImageType eImageType = vcl::ImageType::Size16;
if (m_eSymbolSize == SFX_SYMBOLS_SIZE_LARGE)
{
m_pToolBar->SetToolboxButtonSize(ToolBoxButtonSize::Large);
eImageType = vcl::ImageType::Size26;
}
else if (m_eSymbolSize == SFX_SYMBOLS_SIZE_32)
{
eImageType = vcl::ImageType::Size32;
m_pToolBar->SetToolboxButtonSize(ToolBoxButtonSize::Size32);
}
else
{
m_pToolBar->SetToolboxButtonSize(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_pToolBar->GetItemCommand( it.first );
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 = framework::AddonsOptions().GetImageFromURL(aCommandURL, bBigImages);
m_pToolBar->SetItemImage( it.first, aImage );
}
}
::Size aSize = m_pToolBar->CalcWindowSizePixel();
m_pToolBar->SetOutputSizePixel( aSize );
}
void ToolBarManager::UpdateControllers()
{
if( SvtMiscOptions().DisableUICustomization() )
{
Any a;
Reference< XLayoutManager > xLayoutManager;
Reference< XPropertySet > xFramePropSet( m_xFrame, UNO_QUERY );
if ( xFramePropSet.is() )
a = xFramePropSet->getPropertyValue("LayoutManager");
a >>= xLayoutManager;
Reference< XDockableWindow > xDockable( VCLUnoHelper::GetInterface( m_pToolBar ), 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 >(
static_cast< OWeakObject* >( this ), UNO_QUERY ));
}
catch (const Exception&)
{
}
}
if ( m_xModuleImageManager.is() )
{
try
{
m_xModuleImageManager->removeConfigurationListener(
Reference< XUIConfigurationListener >(
static_cast< OWeakObject* >( this ), UNO_QUERY ));
}
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( static_cast< OWeakObject* >(this), UNO_QUERY );
EventObject aEvent( xThis );
m_aListenerContainer.disposeAndClear( aEvent );
{
SolarMutexGuard g;
if (m_bDisposed)
{
return;
}
RemoveControllers();
if ( m_xDocImageManager.is() )
{
try
{
m_xDocImageManager->removeConfigurationListener(
Reference< XUIConfigurationListener >(
static_cast< OWeakObject* >( this ), UNO_QUERY ));
}
catch (const Exception&)
{
}
}
m_xDocImageManager.clear();
if ( m_xModuleImageManager.is() )
{
try
{
m_xModuleImageManager->removeConfigurationListener(
Reference< XUIConfigurationListener >(
static_cast< OWeakObject* >( this ), UNO_QUERY ));
}
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 >(
static_cast< ::cppu::OWeakObject *>( this ), UNO_QUERY ));
}
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();
m_aListenerContainer.addInterface( cppu::UnoType<XEventListener>::get(), xListener );
}
void SAL_CALL ToolBarManager::removeEventListener( const Reference< XEventListener >& xListener )
{
m_aListenerContainer.removeInterface( cppu::UnoType<XEventListener>::get(), 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 ))
{
sal_Int16 nImageInfo( 1 );
Reference< XInterface > xIfacDocImgMgr( m_xDocImageManager, UNO_QUERY );
if ( xIfacDocImgMgr == Event.Source )
nImageInfo = 0;
Sequence< OUString > aSeq = xNameAccess->getElementNames();
for ( sal_Int32 i = 0; i < aSeq.getLength(); i++ )
{
CommandToInfoMap::iterator pIter = m_aCommandMap.find( aSeq[i] );
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 a image at our module image manager. Before
// we can remove our image we have to ask our module image manager.
Sequence< OUString > aCmdURLSeq( 1 );
Sequence< Reference< XGraphic > > aGraphicSeq;
aCmdURLSeq[0] = pIter->first;
aGraphicSeq = m_xModuleImageManager->getImages( nImageType, aCmdURLSeq );
aImage = Image( aGraphicSeq[0] );
}
setToolBarImage(aImage,pIter);
} // if (isRemove)
else
{
Reference< XGraphic > xGraphic;
if ( xNameAccess->getByName( aSeq[i] ) >>= 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<sal_uInt16>& rIDs = rIter->second.aIds;
m_pToolBar->SetItemImage( rIter->second.nId, rImage );
for (auto const& it : rIDs)
{
m_pToolBar->SetItemImage(it, 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_pToolBar->GetItemCount(); i++ )
{
sal_uInt16 nItemId = m_pToolBar->GetItemId( i );
if ( nItemId > 0 )
{
Reference< XComponent > xComponent( m_aControllerMap[ nItemId ], UNO_QUERY );
if ( xComponent.is() )
{
try
{
xComponent->dispose();
}
catch (const Exception&)
{
}
}
m_pToolBar->SetItemWindow(nItemId, nullptr);
}
}
m_aControllerMap.clear();
}
void ToolBarManager::CreateControllers()
{
Reference< XWindow > xToolbarWindow = VCLUnoHelper::GetInterface( m_pToolBar );
css::util::URL aURL;
bool bHasDisabledEntries = SvtCommandOptions().HasEntries( SvtCommandOptions::CMDOPTION_DISABLED );
SvtCommandOptions aCmdOptions;
for ( ToolBox::ImplToolItems::size_type i = 0; i < m_pToolBar->GetItemCount(); i++ )
{
sal_uInt16 nId = m_pToolBar->GetItemId( i );
if ( nId == 0 )
continue;
bool bInit( true );
bool bCreate( true );
Reference< XStatusListener > xController;
svt::ToolboxController* pController( nullptr );
OUString aCommandURL( m_pToolBar->GetItemCommand( nId ) );
// Command can be just an alias to another command.
OUString aRealCommandURL( vcl::CommandInfoProvider::GetRealCommandForCommand( aCommandURL, m_aModuleIdentifier ) );
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_pToolBar->HideItem( nId );
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( makeAny( aPropValue ));
aPropValue.Name = "Frame";
aPropValue.Value <<= m_xFrame;
aPropertyVector.push_back( makeAny( aPropValue ));
aPropValue.Name = "ServiceManager";
Reference<XMultiServiceFactory> xMSF(m_xContext->getServiceManager(), UNO_QUERY_THROW);
aPropValue.Value <<= xMSF;
aPropertyVector.push_back( makeAny( aPropValue ));
aPropValue.Name = "ParentWindow";
aPropValue.Value <<= xToolbarWindow;
aPropertyVector.push_back( makeAny( aPropValue ));
aPropValue.Name = "Identifier";
aPropValue.Value <<= nId;
aPropertyVector.push_back( uno::makeAny( 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_pToolBar->IsItemVisible(nId)))
bCreate = false;
if ( !xController.is() && bCreate )
{
pController = CreateToolBoxController( m_xFrame, m_pToolBar, nId, aCommandURL );
if ( !pController )
{
if ( 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 ), UNO_QUERY );
xController = xStatusListener;
}
else if ( aCommandURL.startsWith( ".uno:StyleApply?" ) )
{
xController.set( new StyleToolbarController( m_xContext, m_xFrame, aCommandURL ));
m_pToolBar->SetItemBits( nId, m_pToolBar->GetItemBits( nId ) | ToolBoxItemBits::CHECKABLE );
}
else if ( aCommandURL.startsWith( "private:resource/menubar/" ) )
{
xController.set( new MenuToolbarController );
}
else
{
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_pToolBar->SetItemBits( nId, m_pToolBar->GetItemBits( nId ) | ToolBoxItemBits::CHECKABLE );
}
}
else if ( pController )
{
xController.set( static_cast< ::cppu::OWeakObject *>( pController ), UNO_QUERY );
}
}
// 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 )
{
PropertyValue aPropValue;
std::vector< Any > aPropertyVector;
aPropValue.Name = "Frame";
aPropValue.Value <<= m_xFrame;
aPropertyVector.push_back( makeAny( aPropValue ));
aPropValue.Name = "CommandURL";
aPropValue.Value <<= aCommandURL;
aPropertyVector.push_back( makeAny( aPropValue ));
aPropValue.Name = "ServiceManager";
Reference<XMultiServiceFactory> xMSF(m_xContext->getServiceManager(), UNO_QUERY_THROW);
aPropValue.Value <<= xMSF;
aPropertyVector.push_back( makeAny( aPropValue ));
aPropValue.Name = "ParentWindow";
aPropValue.Value <<= xToolbarWindow;
aPropertyVector.push_back( makeAny( aPropValue ));
aPropValue.Name = "ModuleIdentifier";
aPropValue.Value <<= m_aModuleIdentifier;
aPropertyVector.push_back( makeAny( aPropValue ));
aPropValue.Name = "Identifier";
aPropValue.Value <<= nId;
aPropertyVector.push_back( uno::makeAny( aPropValue ) );
Sequence< Any > aArgs( comphelper::containerToSequence( aPropertyVector ));
xInit->initialize( aArgs );
if (pController)
{
if (aCommandURL == ".uno:SwitchXFormsDesignMode" || aCommandURL == ".uno:ViewDataSourceBrowser")
pController->setFastPropertyValue_NoBroadcast(1, makeAny(true));
}
}
// Request a 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 ( nType == WindowType::LISTBOX || nType == WindowType::MULTILISTBOX || nType == WindowType::COMBOBOX )
pItemWin->SetAccessibleName( m_pToolBar->GetItemText( nId ) );
m_pToolBar->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 >(
static_cast< ::cppu::OWeakObject *>( this ), UNO_QUERY ));
}
}
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(), UNO_QUERY );
m_xDocImageManager.set( xDocUICfgMgr->getImageManager(), UNO_QUERY );
m_xDocImageManager->addConfigurationListener(
Reference< XUIConfigurationListener >(
static_cast< OWeakObject* >( this ), UNO_QUERY ));
}
}
}
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 >(
static_cast< OWeakObject* >( this ), UNO_QUERY ));
}
}
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_pToolBar->Clear();
m_aControllerMap.clear();
m_aCommandMap.clear();
sal_uInt16 nId( 1 );
CommandInfo aCmdInfo;
for ( sal_Int32 n = 0; n < rItemContainer->getCount(); n++ )
{
Sequence< PropertyValue > aProp;
OUString aCommandURL;
OUString aLabel;
OUString aTooltip;
sal_uInt16 nType( css::ui::ItemType::DEFAULT );
sal_uInt32 nStyle( 0 );
try
{
if ( rItemContainer->getByIndex( n ) >>= aProp )
{
bool bIsVisible( true );
for ( int i = 0; i < aProp.getLength(); i++ )
{
if ( aProp[i].Name == ITEM_DESCRIPTOR_COMMANDURL )
aProp[i].Value >>= aCommandURL;
else if ( aProp[i].Name == "Label" )
aProp[i].Value >>= aLabel;
else if ( aProp[i].Name == "Tooltip" )
aProp[i].Value >>= aTooltip;
else if ( aProp[i].Name == "Type" )
aProp[i].Value >>= nType;
else if ( aProp[i].Name == ITEM_DESCRIPTOR_VISIBLE )
aProp[i].Value >>= bIsVisible;
else if ( aProp[i].Name == "Style" )
aProp[i].Value >>= nStyle;
}
if (vcl::CommandInfoProvider::IsExperimental(aCommandURL, m_aModuleIdentifier) &&
!SvtMiscOptions().IsExperimentalMode())
{
continue;
}
if (( nType == css::ui::ItemType::DEFAULT ) && !aCommandURL.isEmpty() )
{
OUString aString(vcl::CommandInfoProvider::GetLabelForCommand(aCommandURL, m_aModuleIdentifier));
ToolBoxItemBits nItemBits = ConvertStyleToToolboxItemBits( nStyle );
m_pToolBar->InsertItem( nId, aString, nItemBits );
m_pToolBar->SetItemCommand( nId, aCommandURL );
if ( !aTooltip.isEmpty() )
m_pToolBar->SetQuickHelpText( nId, aTooltip );
else
m_pToolBar->SetQuickHelpText( nId, vcl::CommandInfoProvider::GetTooltipForCommand(aCommandURL, m_xFrame) );
if ( !aLabel.isEmpty() )
{
m_pToolBar->SetItemText( nId, aLabel );
}
else
{
m_pToolBar->SetItemText( nId, aString );
}
m_pToolBar->EnableItem( nId );
m_pToolBar->SetItemState( nId, TRISTATE_FALSE );
// 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.
CommandToInfoMap::iterator pIter = m_aCommandMap.find( aCommandURL );
if ( pIter == m_aCommandMap.end())
{
aCmdInfo.nId = nId;
const CommandToInfoMap::value_type aValue( aCommandURL, aCmdInfo );
m_aCommandMap.insert( aValue );
}
else
{
pIter->second.aIds.push_back( nId );
}
if ( !bIsVisible )
m_pToolBar->HideItem( nId );
++nId;
}
else if ( nType == css::ui::ItemType::SEPARATOR_LINE )
{
m_pToolBar->InsertSeparator();
}
else if ( nType == css::ui::ItemType::SEPARATOR_SPACE )
{
m_pToolBar->InsertSpace();
}
else if ( nType == css::ui::ItemType::SEPARATOR_LINEBREAK )
{
m_pToolBar->InsertBreak();
}
}
}
catch (const css::lang::IndexOutOfBoundsException&)
{
break;
}
}
// Support add-on toolbar merging here. Working directly on the toolbar object is much
// simpler and faster.
const 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() )
{
sal_uInt16 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 ))
{
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,
nItemId,
m_aCommandMap,
m_aModuleIdentifier,
rInstruction.aMergeCommand,
rInstruction.aMergeCommandParameter,
aItems );
}
else
{
ToolBarMerger::ProcessMergeFallback( m_pToolBar,
nItemId,
m_aCommandMap,
m_aModuleIdentifier,
rInstruction.aMergeCommand,
rInstruction.aMergeFallback,
aItems );
}
}
}
}
// 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_pToolBar->WillUsePopupMode() )
UpdateControllers();
else if ( m_pToolBar->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() )
{
try
{
OUString aUIName;
xPropSet->getPropertyValue("UIName") >>= aUIName;
if ( !aUIName.isEmpty() )
m_pToolBar->SetText( aUIName );
}
catch (const Exception&)
{
}
}
}
void ToolBarManager::FillOverflowToolbar( ToolBox const * pParent )
{
CommandInfo aCmdInfo;
bool bInsertSeparator = false;
for ( ToolBox::ImplToolItems::size_type i = 0; i < pParent->GetItemCount(); ++i )
{
sal_uInt16 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.
CommandToInfoMap::iterator pIter = m_aCommandMap.find( aCommandURL );
if ( pIter == m_aCommandMap.end())
{
aCmdInfo.nId = nId;
const CommandToInfoMap::value_type aValue( aCommandURL, aCmdInfo );
m_aCommandMap.insert( aValue );
}
else
{
pIter->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.getLength() > 0 )
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 = 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() )
{
SubToolBarToSubToolBarControllerMap::const_iterator pIter =
m_aSubToolBarControllerMap.find( aUIElementName );
if ( pIter != m_aSubToolBarControllerMap.end() )
{
const SubToolBarControllerVector& rSubToolBarVector = pIter->second;
if ( !rSubToolBarVector.empty() )
{
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(void ( SAL_CALL XToolbarController::*_pClick )())
{
SolarMutexGuard g;
if ( m_bDisposed )
return;
sal_uInt16 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.get()->*_pClick)( );
}
}
IMPL_LINK_NOARG(ToolBarManager, Click, ToolBox *, void)
{
HandleClick(&XToolbarController::click);
}
IMPL_LINK_NOARG(ToolBarManager, DropdownClick, ToolBox *, void)
{
SolarMutexGuard g;
if ( m_bDisposed )
return;
sal_uInt16 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() )
{
Reference< XWindow > xWin = xController->createPopupWindow();
if ( xWin.is() )
xWin->setFocus();
}
}
}
IMPL_LINK_NOARG(ToolBarManager, DoubleClick, ToolBox *, void)
{
HandleClick(&XToolbarController::doubleClick);
}
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;
}
bool ToolBarManager::MenuItemAllowed( sal_uInt16 ) const
{
return true;
}
void ToolBarManager::AddCustomizeMenuItems(ToolBox const * pToolBar)
{
// 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 = !SvtMenuOptions().IsEntryHidingEnabled();
::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 (MenuItemAllowed(MENUITEM_TOOLBAR_VISIBLEBUTTON))
{
pMenu->InsertItem(MENUITEM_TOOLBAR_VISIBLEBUTTON, FwkResId(STR_TOOLBAR_VISIBLE_BUTTONS));
xVisibleItemsPopupMenu = VclPtr<PopupMenu>::Create();
pMenu->SetPopupMenu(MENUITEM_TOOLBAR_VISIBLEBUTTON, xVisibleItemsPopupMenu);
}
if (MenuItemAllowed(MENUITEM_TOOLBAR_CUSTOMIZETOOLBAR) && m_pToolBar->IsCustomize())
{
pMenu->InsertItem(MENUITEM_TOOLBAR_CUSTOMIZETOOLBAR, FwkResId(STR_TOOLBAR_CUSTOMIZE_TOOLBAR));
pMenu->SetItemCommand(MENUITEM_TOOLBAR_CUSTOMIZETOOLBAR, ".uno:ConfigureToolboxVisible");
}
if (nGroupLen != pMenu->GetItemCount())
{
pMenu->InsertSeparator();
nGroupLen = pMenu->GetItemCount();
}
if (MenuItemAllowed(MENUITEM_TOOLBAR_DOCKTOOLBAR))
pMenu->InsertItem(MENUITEM_TOOLBAR_DOCKTOOLBAR, FwkResId(STR_TOOLBAR_DOCK_TOOLBAR));
if (MenuItemAllowed(MENUITEM_TOOLBAR_DOCKALLTOOLBAR))
pMenu->InsertItem(MENUITEM_TOOLBAR_DOCKALLTOOLBAR, FwkResId(STR_TOOLBAR_DOCK_ALL_TOOLBARS));
if (nGroupLen != pMenu->GetItemCount())
{
pMenu->InsertSeparator();
nGroupLen = pMenu->GetItemCount();
}
if (MenuItemAllowed(MENUITEM_TOOLBAR_LOCKTOOLBARPOSITION))
pMenu->InsertItem(MENUITEM_TOOLBAR_LOCKTOOLBARPOSITION, FwkResId(STR_TOOLBAR_LOCK_TOOLBAR));
if (MenuItemAllowed(MENUITEM_TOOLBAR_CLOSE))
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_DOCKTOOLBAR, false);
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 (SvtMiscOptions().DisableUICustomization())
{
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 )
{
sal_uInt16 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 );
}
else
{
xVisibleItemsPopupMenu->InsertSeparator();
}
}
}
// Now we go through all the contextual menu to update the icons
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 );
}
}
}
// 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);
pOverflowToolBar->SetOutStyle( pToolBar->GetOutStyle() );
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 );
}
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 > xInterface( 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( 1 );
aPropSeq[ 0 ].Name = "ResourceURL";
aPropSeq[ 0 ].Value <<= m_aResourceName;
xDisp->dispatch( aURL, aPropSeq );
}
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[nVisibleIndex].Value <<= !bVisible;
try
{
xItemContainer->replaceByIndex( i, makeAny( 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()) );
sal_uInt16 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 sal_uInt16 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( static_cast< OWeakObject* >(this), UNO_QUERY );
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_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: */
↑ V1019 Compound assignment expression 'Event.Element >>= xNameAccess' is used inside condition.
↑ V519 The 'm_bUpdateControllers' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 381, 395.
↑ V519 The 'm_bUpdateControllers' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 358, 372.