From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- .../source/fwe/classes/actiontriggercontainer.cxx | 137 ++ .../fwe/classes/actiontriggerpropertyset.cxx | 372 ++++ .../classes/actiontriggerseparatorpropertyset.cxx | 246 +++ framework/source/fwe/classes/addonmenu.cxx | 308 +++ framework/source/fwe/classes/addonsoptions.cxx | 1957 ++++++++++++++++++++ framework/source/fwe/classes/framelistanalyzer.cxx | 260 +++ framework/source/fwe/classes/fwkresid.cxx | 28 + framework/source/fwe/classes/imagewrapper.cxx | 91 + .../fwe/classes/rootactiontriggercontainer.cxx | 264 +++ .../source/fwe/classes/sfxhelperfunctions.cxx | 155 ++ 10 files changed, 3818 insertions(+) create mode 100644 framework/source/fwe/classes/actiontriggercontainer.cxx create mode 100644 framework/source/fwe/classes/actiontriggerpropertyset.cxx create mode 100644 framework/source/fwe/classes/actiontriggerseparatorpropertyset.cxx create mode 100644 framework/source/fwe/classes/addonmenu.cxx create mode 100644 framework/source/fwe/classes/addonsoptions.cxx create mode 100644 framework/source/fwe/classes/framelistanalyzer.cxx create mode 100644 framework/source/fwe/classes/fwkresid.cxx create mode 100644 framework/source/fwe/classes/imagewrapper.cxx create mode 100644 framework/source/fwe/classes/rootactiontriggercontainer.cxx create mode 100644 framework/source/fwe/classes/sfxhelperfunctions.cxx (limited to 'framework/source/fwe/classes') diff --git a/framework/source/fwe/classes/actiontriggercontainer.cxx b/framework/source/fwe/classes/actiontriggercontainer.cxx new file mode 100644 index 000000000..331eb5cb9 --- /dev/null +++ b/framework/source/fwe/classes/actiontriggercontainer.cxx @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 +#include +#include +#include +#include +#include + +using namespace cppu; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::container; + +namespace framework +{ + +ActionTriggerContainer::ActionTriggerContainer() : + PropertySetContainer() +{ +} + +ActionTriggerContainer::~ActionTriggerContainer() +{ +} + +// XInterface +Any SAL_CALL ActionTriggerContainer::queryInterface( const Type& aType ) +{ + Any a = ::cppu::queryInterface( + aType , + static_cast< XMultiServiceFactory* >(this), + static_cast< XServiceInfo* >(this), + static_cast< XTypeProvider* >(this)); + + if( a.hasValue() ) + { + return a; + } + + return PropertySetContainer::queryInterface( aType ); +} + +void ActionTriggerContainer::acquire() throw() +{ + PropertySetContainer::acquire(); +} + +void ActionTriggerContainer::release() throw() +{ + PropertySetContainer::release(); +} + +// XMultiServiceFactory +Reference< XInterface > SAL_CALL ActionTriggerContainer::createInstance( const OUString& aServiceSpecifier ) +{ + if ( aServiceSpecifier == SERVICENAME_ACTIONTRIGGER ) + return static_cast( new ActionTriggerPropertySet()); + else if ( aServiceSpecifier == SERVICENAME_ACTIONTRIGGERCONTAINER ) + return static_cast( new ActionTriggerContainer()); + else if ( aServiceSpecifier == SERVICENAME_ACTIONTRIGGERSEPARATOR ) + return static_cast( new ActionTriggerSeparatorPropertySet()); + else + throw css::uno::RuntimeException("Unknown service specifier!", static_cast(this) ); +} + +Reference< XInterface > SAL_CALL ActionTriggerContainer::createInstanceWithArguments( const OUString& ServiceSpecifier, const Sequence< Any >& /*Arguments*/ ) +{ + return createInstance( ServiceSpecifier ); +} + +Sequence< OUString > SAL_CALL ActionTriggerContainer::getAvailableServiceNames() +{ + Sequence< OUString > aSeq( 3 ); + + aSeq[0] = SERVICENAME_ACTIONTRIGGER; + aSeq[1] = SERVICENAME_ACTIONTRIGGERCONTAINER; + aSeq[2] = SERVICENAME_ACTIONTRIGGERSEPARATOR; + + return aSeq; +} + +// XServiceInfo +OUString SAL_CALL ActionTriggerContainer::getImplementationName() +{ + return IMPLEMENTATIONNAME_ACTIONTRIGGERCONTAINER; +} + +sal_Bool SAL_CALL ActionTriggerContainer::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL ActionTriggerContainer::getSupportedServiceNames() +{ + Sequence< OUString > seqServiceNames { SERVICENAME_ACTIONTRIGGERCONTAINER }; + return seqServiceNames; +} + +// XTypeProvider +Sequence< Type > SAL_CALL ActionTriggerContainer::getTypes() +{ + // Create a static typecollection ... + static ::cppu::OTypeCollection ourTypeCollection( + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get()); + + return ourTypeCollection.getTypes(); +} + +Sequence< sal_Int8 > SAL_CALL ActionTriggerContainer::getImplementationId() +{ + return css::uno::Sequence(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/classes/actiontriggerpropertyset.cxx b/framework/source/fwe/classes/actiontriggerpropertyset.cxx new file mode 100644 index 000000000..128f5815b --- /dev/null +++ b/framework/source/fwe/classes/actiontriggerpropertyset.cxx @@ -0,0 +1,372 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 +#include +#include +#include +#include +#include +#include + +using namespace cppu; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star::lang; +using namespace com::sun::star::awt; + +//struct SAL_DLLPUBLIC_IMPORT ::cppu::OBroadcastHelperVar< OMultiTypeInterfaceContainerHelper, OMultiTypeInterfaceContainerHelper::keyType >; + +namespace { + +// Handles for properties +// (PLEASE SORT THIS FIELD, IF YOU ADD NEW PROPERTIES!) +// We use an enum to define these handles, to use all numbers from 0 to nn and +// if you add someone, you don't must control this! +// But don't forget to change values of follow defines, if you do something with this enum! +enum EPROPERTIES +{ + HANDLE_COMMANDURL, + HANDLE_HELPURL, + HANDLE_IMAGE, + HANDLE_SUBCONTAINER, + HANDLE_TEXT, + PROPERTYCOUNT +}; + +} + +namespace framework +{ + +ActionTriggerPropertySet::ActionTriggerPropertySet() + : OBroadcastHelper ( m_aMutex ) + , OPropertySetHelper ( *static_cast< OBroadcastHelper * >(this) ) + , OWeakObject () +{ +} + +ActionTriggerPropertySet::~ActionTriggerPropertySet() +{ +} + +// XInterface +Any SAL_CALL ActionTriggerPropertySet::queryInterface( const Type& aType ) +{ + Any a = ::cppu::queryInterface( + aType, + static_cast< XServiceInfo* >(this), + static_cast< XTypeProvider* >(this)); + + if( a.hasValue() ) + return a; + else + { + a = OPropertySetHelper::queryInterface( aType ); + + if( a.hasValue() ) + return a; + } + + return OWeakObject::queryInterface( aType ); +} + +void SAL_CALL ActionTriggerPropertySet::acquire() throw () +{ + OWeakObject::acquire(); +} + +void SAL_CALL ActionTriggerPropertySet::release() throw () +{ + OWeakObject::release(); +} + +// XServiceInfo +OUString SAL_CALL ActionTriggerPropertySet::getImplementationName() +{ + return IMPLEMENTATIONNAME_ACTIONTRIGGER; +} + +sal_Bool SAL_CALL ActionTriggerPropertySet::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL ActionTriggerPropertySet::getSupportedServiceNames() +{ + Sequence seqServiceNames { SERVICENAME_ACTIONTRIGGER }; + return seqServiceNames; +} + +// XTypeProvider +Sequence< Type > SAL_CALL ActionTriggerPropertySet::getTypes() +{ + // Create a static typecollection ... + static ::cppu::OTypeCollection ourTypeCollection( + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get()); + + + return ourTypeCollection.getTypes(); +} + +Sequence< sal_Int8 > SAL_CALL ActionTriggerPropertySet::getImplementationId() +{ + return css::uno::Sequence(); +} + +sal_Bool SAL_CALL ActionTriggerPropertySet::convertFastPropertyValue( + Any& aConvertedValue, + Any& aOldValue, + sal_Int32 nHandle, + const Any& aValue ) +{ + // Check, if value of property will changed in method "setFastPropertyValue_NoBroadcast()". + // Return sal_True, if changed - else return sal_False. + // Attention: Method "impl_tryToChangeProperty()" can throw the IllegalArgumentException !!! + // Initialize return value with sal_False !!! + // (Handle can be invalid) + bool bReturn = false; + + switch( nHandle ) + { + case HANDLE_COMMANDURL: + bReturn = impl_tryToChangeProperty( m_aCommandURL, aValue, aOldValue, aConvertedValue ); + break; + + case HANDLE_HELPURL: + bReturn = impl_tryToChangeProperty( m_aHelpURL, aValue, aOldValue, aConvertedValue ); + break; + + case HANDLE_IMAGE: + bReturn = impl_tryToChangeProperty( m_xBitmap, aValue, aOldValue, aConvertedValue ); + break; + + case HANDLE_SUBCONTAINER: + bReturn = impl_tryToChangeProperty( m_xActionTriggerContainer, aValue, aOldValue, aConvertedValue ); + break; + + case HANDLE_TEXT: + bReturn = impl_tryToChangeProperty( m_aText, aValue, aOldValue, aConvertedValue ); + break; + } + + // Return state of operation. + return bReturn; +} + +void SAL_CALL ActionTriggerPropertySet::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, const Any& aValue ) +{ + SolarMutexGuard aGuard; + + // Search for right handle ... and try to set property value. + switch( nHandle ) + { + case HANDLE_COMMANDURL: + aValue >>= m_aCommandURL; + break; + + case HANDLE_HELPURL: + aValue >>= m_aHelpURL; + break; + + case HANDLE_IMAGE: + aValue >>= m_xBitmap; + break; + + case HANDLE_SUBCONTAINER: + aValue >>= m_xActionTriggerContainer; + break; + + case HANDLE_TEXT: + aValue >>= m_aText; + break; + } +} + +void SAL_CALL ActionTriggerPropertySet::getFastPropertyValue( + Any& aValue, sal_Int32 nHandle ) const +{ + SolarMutexGuard aGuard; + + // Search for right handle ... and try to get property value. + switch( nHandle ) + { + case HANDLE_COMMANDURL: + aValue <<= m_aCommandURL; + break; + + case HANDLE_HELPURL: + aValue <<= m_aHelpURL; + break; + + case HANDLE_IMAGE: + aValue <<= m_xBitmap; + break; + + case HANDLE_SUBCONTAINER: + aValue <<= m_xActionTriggerContainer; + break; + + case HANDLE_TEXT: + aValue <<= m_aText; + break; + } +} + +::cppu::IPropertyArrayHelper& SAL_CALL ActionTriggerPropertySet::getInfoHelper() +{ + // Define static member to give structure of properties to baseclass "OPropertySetHelper". + // "impl_getStaticPropertyDescriptor" is a non exported and static function, who will define a static propertytable. + // "true" say: Table is sorted by name. + static OPropertyArrayHelper ourInfoHelper( impl_getStaticPropertyDescriptor(), true ); + + return ourInfoHelper; +} + +Reference< XPropertySetInfo > SAL_CALL ActionTriggerPropertySet::getPropertySetInfo() +{ + // Create structure of propertysetinfo for baseclass "OPropertySetHelper". + // (Use method "getInfoHelper()".) + static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + + return xInfo; +} + +Sequence< Property > ActionTriggerPropertySet::impl_getStaticPropertyDescriptor() +{ + return + { + Property( "CommandURL" , HANDLE_COMMANDURL , cppu::UnoType::get(), PropertyAttribute::TRANSIENT ), + Property( "HelpURL" , HANDLE_HELPURL , cppu::UnoType::get(), PropertyAttribute::TRANSIENT ), + Property( "Image" , HANDLE_IMAGE , cppu::UnoType::get(), PropertyAttribute::TRANSIENT ), + Property( "SubContainer" , HANDLE_SUBCONTAINER , cppu::UnoType::get(), PropertyAttribute::TRANSIENT ), + Property( "Text" , HANDLE_TEXT , cppu::UnoType::get(), PropertyAttribute::TRANSIENT ) + }; +} + +bool ActionTriggerPropertySet::impl_tryToChangeProperty( + const OUString& sCurrentValue , + const Any& aNewValue , + Any& aOldValue , + Any& aConvertedValue ) +{ + // Set default return value if method failed. + bool bReturn = false; + // Get new value from any. + // IllegalArgumentException() can be thrown! + OUString sValue; + convertPropertyValue( sValue, aNewValue ); + + // If value change ... + if( sValue != sCurrentValue ) + { + // ... set information of change. + aOldValue <<= sCurrentValue; + aConvertedValue <<= sValue; + // Return OK - "value will be change ..." + bReturn = true; + } + else + { + // ... clear information of return parameter! + aOldValue.clear (); + aConvertedValue.clear (); + // Return NOTHING - "value will not be change ..." + bReturn = false; + } + + return bReturn; +} + +bool ActionTriggerPropertySet::impl_tryToChangeProperty( + const Reference< XBitmap >& aCurrentValue , + const Any& aNewValue , + Any& aOldValue , + Any& aConvertedValue ) +{ + // Set default return value if method failed. + bool bReturn = false; + // Get new value from any. + // IllegalArgumentException() can be thrown! + Reference< XBitmap > aValue; + convertPropertyValue( aValue, aNewValue ); + + // If value change ... + if( aValue != aCurrentValue ) + { + // ... set information of change. + aOldValue <<= aCurrentValue; + aConvertedValue <<= aValue; + // Return OK - "value will be change ..." + bReturn = true; + } + else + { + // ... clear information of return parameter! + aOldValue.clear (); + aConvertedValue.clear (); + // Return NOTHING - "value will not be change ..." + bReturn = false; + } + + return bReturn; +} + +bool ActionTriggerPropertySet::impl_tryToChangeProperty( + const Reference< XInterface >& aCurrentValue , + const Any& aNewValue , + Any& aOldValue , + Any& aConvertedValue ) +{ + // Set default return value if method failed. + bool bReturn = false; + // Get new value from any. + // IllegalArgumentException() can be thrown! + Reference< XInterface > aValue; + convertPropertyValue( aValue, aNewValue ); + + // If value change ... + if( aValue != aCurrentValue ) + { + // ... set information of change. + aOldValue <<= aCurrentValue; + aConvertedValue <<= aValue; + // Return OK - "value will be change ..." + bReturn = true; + } + else + { + // ... clear information of return parameter! + aOldValue.clear (); + aConvertedValue.clear (); + // Return NOTHING - "value will not be change ..." + bReturn = false; + } + + return bReturn; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/classes/actiontriggerseparatorpropertyset.cxx b/framework/source/fwe/classes/actiontriggerseparatorpropertyset.cxx new file mode 100644 index 000000000..eb9d6d2ec --- /dev/null +++ b/framework/source/fwe/classes/actiontriggerseparatorpropertyset.cxx @@ -0,0 +1,246 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 +#include +#include +#include +#include +#include +#include + +using namespace cppu; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star::lang; +using namespace com::sun::star::awt; + +namespace { + +// Handles for properties +// (PLEASE SORT THIS FIELD, IF YOU ADD NEW PROPERTIES!) +// We use an enum to define these handles, to use all numbers from 0 to nn and +// if you add someone, you don't must control this! +// But don't forget to change values of follow defines, if you do something with this enum! +enum EPROPERTIES +{ + HANDLE_TYPE, + PROPERTYCOUNT +}; + +} + +namespace framework +{ + +ActionTriggerSeparatorPropertySet::ActionTriggerSeparatorPropertySet() + : OBroadcastHelper ( m_aMutex ) + , OPropertySetHelper ( *static_cast< OBroadcastHelper * >(this) ) + , OWeakObject () + , m_nSeparatorType( 0 ) +{ +} + +ActionTriggerSeparatorPropertySet::~ActionTriggerSeparatorPropertySet() +{ +} + +// XInterface +Any SAL_CALL ActionTriggerSeparatorPropertySet::queryInterface( const Type& aType ) +{ + Any a = ::cppu::queryInterface( + aType, + static_cast< XServiceInfo* >(this), + static_cast< XTypeProvider* >(this)); + + if( a.hasValue() ) + return a; + else + { + a = OPropertySetHelper::queryInterface( aType ); + + if( a.hasValue() ) + return a; + } + + return OWeakObject::queryInterface( aType ); +} + +void ActionTriggerSeparatorPropertySet::acquire() throw() +{ + OWeakObject::acquire(); +} + +void ActionTriggerSeparatorPropertySet::release() throw() +{ + OWeakObject::release(); +} + +// XServiceInfo +OUString SAL_CALL ActionTriggerSeparatorPropertySet::getImplementationName() +{ + return IMPLEMENTATIONNAME_ACTIONTRIGGERSEPARATOR; +} + +sal_Bool SAL_CALL ActionTriggerSeparatorPropertySet::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL ActionTriggerSeparatorPropertySet::getSupportedServiceNames() +{ + Sequence seqServiceNames { SERVICENAME_ACTIONTRIGGERSEPARATOR }; + return seqServiceNames; +} + +// XTypeProvider +Sequence< Type > SAL_CALL ActionTriggerSeparatorPropertySet::getTypes() +{ + // Create a static typecollection ... + static ::cppu::OTypeCollection ourTypeCollection( + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get()); + + return ourTypeCollection.getTypes(); +} + +Sequence< sal_Int8 > SAL_CALL ActionTriggerSeparatorPropertySet::getImplementationId() +{ + return css::uno::Sequence(); +} + +sal_Bool SAL_CALL ActionTriggerSeparatorPropertySet::convertFastPropertyValue( + Any& aConvertedValue, + Any& aOldValue, + sal_Int32 nHandle, + const Any& aValue ) +{ + // Check, if value of property will changed in method "setFastPropertyValue_NoBroadcast()". + // Return sal_True, if changed - else return sal_False. + // Attention: Method "impl_tryToChangeProperty()" can throw the IllegalArgumentException !!! + // Initialize return value with sal_False !!! + // (Handle can be invalid) + bool bReturn = false; + + switch( nHandle ) + { + case HANDLE_TYPE: + bReturn = impl_tryToChangeProperty( m_nSeparatorType, aValue, aOldValue, aConvertedValue ); + break; + } + + // Return state of operation. + return bReturn; +} + +void SAL_CALL ActionTriggerSeparatorPropertySet::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, const Any& aValue ) +{ + SolarMutexGuard aGuard; + + // Search for right handle ... and try to set property value. + switch( nHandle ) + { + case HANDLE_TYPE: + aValue >>= m_nSeparatorType; + break; + } +} + +void SAL_CALL ActionTriggerSeparatorPropertySet::getFastPropertyValue( + Any& aValue, sal_Int32 nHandle ) const +{ + SolarMutexGuard aGuard; + + // Search for right handle ... and try to get property value. + switch( nHandle ) + { + case HANDLE_TYPE: + aValue <<= m_nSeparatorType; + break; + } +} + +::cppu::IPropertyArrayHelper& SAL_CALL ActionTriggerSeparatorPropertySet::getInfoHelper() +{ + // Define static member to give structure of properties to baseclass "OPropertySetHelper". + // "impl_getStaticPropertyDescriptor" is a non exported and static function, who will define a static propertytable. + // "true" indicates: Table is sorted by name. + static OPropertyArrayHelper ourInfoHelper( impl_getStaticPropertyDescriptor(), true ); + + return ourInfoHelper; +} + +Reference< XPropertySetInfo > SAL_CALL ActionTriggerSeparatorPropertySet::getPropertySetInfo() +{ + // Create structure of propertysetinfo for baseclass "OPropertySetHelper". + // (Use method "getInfoHelper()".) + static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + + return xInfo; +} + +Sequence< Property > ActionTriggerSeparatorPropertySet::impl_getStaticPropertyDescriptor() +{ + return + { + Property( "SeparatorType", HANDLE_TYPE, cppu::UnoType::get(), PropertyAttribute::TRANSIENT ) + }; +} + +bool ActionTriggerSeparatorPropertySet::impl_tryToChangeProperty( + sal_Int16 aCurrentValue , + const Any& aNewValue , + Any& aOldValue , + Any& aConvertedValue ) +{ + // Set default return value if method failed. + bool bReturn = false; + // Get new value from any. + // IllegalArgumentException() can be thrown! + sal_Int16 aValue = 0; + convertPropertyValue( aValue, aNewValue ); + + // If value change ... + if( aValue != aCurrentValue ) + { + // ... set information of change. + aOldValue <<= aCurrentValue; + aConvertedValue <<= aValue; + // Return OK - "value will be change ..." + bReturn = true; + } + else + { + // ... clear information of return parameter! + aOldValue.clear (); + aConvertedValue.clear (); + // Return NOTHING - "value will not be change ..." + bReturn = false; + } + + return bReturn; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/classes/addonmenu.cxx b/framework/source/fwe/classes/addonmenu.cxx new file mode 100644 index 000000000..80ac7c0e0 --- /dev/null +++ b/framework/source/fwe/classes/addonmenu.cxx @@ -0,0 +1,308 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 +#include +#include + +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::beans; + +namespace framework +{ + +bool AddonMenuManager::HasAddonMenuElements() +{ + return AddonsOptions().HasAddonsMenu(); +} + +// Create the Add-Ons menu +VclPtr AddonMenuManager::CreateAddonMenu( const Reference< XFrame >& rFrame ) +{ + AddonsOptions aOptions; + VclPtr pAddonMenu; + sal_uInt16 nUniqueMenuId = ADDONMENU_ITEMID_START; + + const Sequence< Sequence< PropertyValue > >& rAddonMenuEntries = aOptions.GetAddonsMenu(); + if ( rAddonMenuEntries.hasElements() ) + { + pAddonMenu = VclPtr::Create(); + OUString aModuleIdentifier = vcl::CommandInfoProvider::GetModuleIdentifier( rFrame ); + AddonMenuManager::BuildMenu( pAddonMenu, MENU_APPEND, nUniqueMenuId, rAddonMenuEntries, rFrame, aModuleIdentifier ); + + // Don't return an empty Add-On menu + if ( pAddonMenu->GetItemCount() == 0 ) + { + pAddonMenu.disposeAndClear(); + } + } + + return pAddonMenu; +} + +// Returns the next insert position from nPos. +sal_uInt16 AddonMenuManager::GetNextPos( sal_uInt16 nPos ) +{ + return ( nPos == MENU_APPEND ) ? MENU_APPEND : ( nPos+1 ); +} + +static sal_uInt16 FindMenuId( Menu const * pMenu, const OUString& aCommand ) +{ + sal_uInt16 nPos = 0; + OUString aCmd; + for ( nPos = 0; nPos < pMenu->GetItemCount(); nPos++ ) + { + sal_uInt16 nId = pMenu->GetItemId( nPos ); + aCmd = pMenu->GetItemCommand( nId ); + if ( aCmd == aCommand ) + return nId; + } + + return USHRT_MAX; +} + +// Merge the Add-Ons help menu items into the given menu bar at a defined pos +void AddonMenuManager::MergeAddonHelpMenu( const Reference< XFrame >& rFrame, + MenuBar const * pMergeMenuBar ) +{ + if ( !pMergeMenuBar ) + return; + + PopupMenu* pHelpMenu(nullptr); + sal_uInt16 nId = FindMenuId(pMergeMenuBar, ".uno:HelpMenu"); + if ( nId != USHRT_MAX ) + pHelpMenu = pMergeMenuBar->GetPopupMenu( nId ); + + if ( !pHelpMenu ) + return; + + // Add-Ons help menu items should be inserted after the "registration" menu item + sal_uInt16 nItemCount = pHelpMenu->GetItemCount(); + sal_uInt16 nInsSepAfterPos = MENU_APPEND; + sal_uInt16 nUniqueMenuId = ADDONMENU_ITEMID_START; + AddonsOptions aOptions; + + // try to detect the about menu item with the command URL + nId = FindMenuId(pHelpMenu, ".uno:About"); + sal_uInt16 nInsPos = pHelpMenu->GetItemPos( nId ); + + const Sequence< Sequence< PropertyValue > >& rAddonHelpMenuEntries = aOptions.GetAddonsHelpMenu(); + + if ( nInsPos < nItemCount && pHelpMenu->GetItemType( nInsPos ) != MenuItemType::SEPARATOR ) + nInsSepAfterPos = nInsPos; + + OUString aModuleIdentifier = vcl::CommandInfoProvider::GetModuleIdentifier(rFrame); + AddonMenuManager::BuildMenu( pHelpMenu, nInsPos, nUniqueMenuId, rAddonHelpMenuEntries, rFrame, aModuleIdentifier ); + + if ( pHelpMenu->GetItemCount() > nItemCount ) + { + if ( nInsSepAfterPos < MENU_APPEND ) + { + nInsSepAfterPos += ( pHelpMenu->GetItemCount() - nItemCount ); + if ( pHelpMenu->GetItemType( nInsSepAfterPos ) != MenuItemType::SEPARATOR ) + pHelpMenu->InsertSeparator(OString(), nInsSepAfterPos); + } + pHelpMenu->InsertSeparator(OString(), nItemCount); + } +} + +// Merge the addon popup menus into the given menu bar at the provided pos. +void AddonMenuManager::MergeAddonPopupMenus( const Reference< XFrame >& rFrame, + sal_uInt16 nMergeAtPos, + MenuBar* pMergeMenuBar ) +{ + if ( !pMergeMenuBar ) + return; + + AddonsOptions aAddonsOptions; + sal_uInt16 nInsertPos = nMergeAtPos; + + OUString aTitle; + OUString aURL; + OUString aTarget; + OUString aImageId; + OUString aContext; + Sequence< Sequence< PropertyValue > > aAddonSubMenu; + sal_uInt16 nUniqueMenuId = ADDONMENU_ITEMID_START; + + OUString aModuleIdentifier = vcl::CommandInfoProvider::GetModuleIdentifier(rFrame); + + const Sequence< Sequence< PropertyValue > >& rAddonMenuEntries = aAddonsOptions.GetAddonsMenuBarPart(); + for ( const Sequence< PropertyValue >& rEntry : rAddonMenuEntries ) + { + AddonMenuManager::GetMenuEntry( rEntry, + aTitle, + aURL, + aTarget, + aImageId, + aContext, + aAddonSubMenu ); + if ( !aTitle.isEmpty() && + !aURL.isEmpty() && + aAddonSubMenu.hasElements() && + AddonMenuManager::IsCorrectContext( aModuleIdentifier, aContext )) + { + sal_uInt16 nId = nUniqueMenuId++; + VclPtrInstance pAddonPopupMenu; + + AddonMenuManager::BuildMenu( pAddonPopupMenu, MENU_APPEND, nUniqueMenuId, aAddonSubMenu, rFrame, aModuleIdentifier ); + + if ( pAddonPopupMenu->GetItemCount() > 0 ) + { + pMergeMenuBar->InsertItem( nId, aTitle, MenuItemBits::NONE, OString(), nInsertPos++ ); + pMergeMenuBar->SetPopupMenu( nId, pAddonPopupMenu ); + + // Store the command URL into the VCL menu bar for later identification + pMergeMenuBar->SetItemCommand( nId, aURL ); + } + else + pAddonPopupMenu.disposeAndClear(); + } + } +} + +// Insert the menu and sub menu entries into pCurrentMenu with the aAddonMenuDefinition provided +void AddonMenuManager::BuildMenu( PopupMenu* pCurrentMenu, + sal_uInt16 nInsPos, + sal_uInt16& nUniqueMenuId, + const Sequence< Sequence< PropertyValue > >& aAddonMenuDefinition, + const Reference< XFrame >& rFrame, + const OUString& rModuleIdentifier ) +{ + Sequence< Sequence< PropertyValue > > aAddonSubMenu; + bool bInsertSeparator = false; + sal_uInt32 i = 0; + sal_uInt32 nElements = 0; + sal_uInt32 nCount = aAddonMenuDefinition.getLength(); + + OUString aTitle; + OUString aURL; + OUString aTarget; + OUString aImageId; + OUString aContext; + + for ( i = 0; i < nCount; ++i ) + { + GetMenuEntry( aAddonMenuDefinition[i], aTitle, aURL, aTarget, aImageId, aContext, aAddonSubMenu ); + + if ( !IsCorrectContext( rModuleIdentifier, aContext ) || ( aTitle.isEmpty() && aURL.isEmpty() )) + continue; + + if ( aURL == "private:separator" ) + bInsertSeparator = true; + else + { + VclPtr pSubMenu; + if ( aAddonSubMenu.hasElements() ) + { + pSubMenu = VclPtr::Create(); + AddonMenuManager::BuildMenu( pSubMenu, MENU_APPEND, nUniqueMenuId, aAddonSubMenu, rFrame, rModuleIdentifier ); + + // Don't create a menu item for an empty sub menu + if ( pSubMenu->GetItemCount() == 0 ) + { + pSubMenu.disposeAndClear(); + continue; + } + } + + if ( bInsertSeparator && nElements > 0 ) + { + // Insert a separator only when we insert a new element afterwards and we + // have already one before us + nElements = 0; + bInsertSeparator = false; + pCurrentMenu->InsertSeparator(OString(), nInsPos); + nInsPos = AddonMenuManager::GetNextPos( nInsPos ); + } + + sal_uInt16 nId = nUniqueMenuId++; + pCurrentMenu->InsertItem(nId, aTitle, MenuItemBits::NONE, OString(), nInsPos); + nInsPos = AddonMenuManager::GetNextPos( nInsPos ); + + ++nElements; + + // Store values from configuration to the New and Wizard menu entries to enable + // sfx2 based code to support high contrast mode correctly! + void* nAttributePtr = MenuAttributes::CreateAttribute(aTarget, aImageId); + pCurrentMenu->SetUserValue(nId, nAttributePtr, MenuAttributes::ReleaseAttribute); + pCurrentMenu->SetItemCommand( nId, aURL ); + + if ( pSubMenu ) + pCurrentMenu->SetPopupMenu( nId, pSubMenu ); + } + } +} + +// Retrieve the menu entry property values from a sequence +void AddonMenuManager::GetMenuEntry( const Sequence< PropertyValue >& rAddonMenuEntry, + OUString& rTitle, + OUString& rURL, + OUString& rTarget, + OUString& rImageId, + OUString& rContext, + Sequence< Sequence< PropertyValue > >& rAddonSubMenu ) +{ + // Reset submenu parameter + rAddonSubMenu = Sequence< Sequence< PropertyValue > >(); + + for ( const PropertyValue& rEntry : rAddonMenuEntry ) + { + OUString aMenuEntryPropName = rEntry.Name; + if ( aMenuEntryPropName == ADDONSMENUITEM_STRING_URL ) + rEntry.Value >>= rURL; + else if ( aMenuEntryPropName == ADDONSMENUITEM_STRING_TITLE ) + rEntry.Value >>= rTitle; + else if ( aMenuEntryPropName == ADDONSMENUITEM_STRING_TARGET ) + rEntry.Value >>= rTarget; + else if ( aMenuEntryPropName == ADDONSMENUITEM_STRING_IMAGEIDENTIFIER ) + rEntry.Value >>= rImageId; + else if ( aMenuEntryPropName == ADDONSMENUITEM_STRING_SUBMENU ) + rEntry.Value >>= rAddonSubMenu; + else if ( aMenuEntryPropName == ADDONSMENUITEM_STRING_CONTEXT ) + rEntry.Value >>= rContext; + } +} + +// Check if the context string matches the provided xModel context +bool AddonMenuManager::IsCorrectContext( const OUString& rModuleIdentifier, const OUString& rContext ) +{ + if ( rContext.isEmpty() ) + return true; + + if ( !rModuleIdentifier.isEmpty() ) + { + sal_Int32 nIndex = rContext.indexOf( rModuleIdentifier ); + return ( nIndex >= 0 ); + } + + return false; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/classes/addonsoptions.cxx b/framework/source/fwe/classes/addonsoptions.cxx new file mode 100644 index 000000000..725bec2f5 --- /dev/null +++ b/framework/source/fwe/classes/addonsoptions.cxx @@ -0,0 +1,1957 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// namespaces + +using namespace ::std; +using namespace ::utl; +using namespace ::osl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star; + +#define ROOTNODE_ADDONMENU "Office.Addons" +#define PATHDELIMITER OUString("/" ) +#define SEPARATOR_URL "private:separator" + +#define PROPERTYNAME_URL ADDONSMENUITEM_STRING_URL +#define PROPERTYNAME_TITLE ADDONSMENUITEM_STRING_TITLE +#define PROPERTYNAME_TARGET ADDONSMENUITEM_STRING_TARGET +#define PROPERTYNAME_IMAGEIDENTIFIER ADDONSMENUITEM_STRING_IMAGEIDENTIFIER +#define PROPERTYNAME_CONTEXT ADDONSMENUITEM_STRING_CONTEXT +#define PROPERTYNAME_SUBMENU ADDONSMENUITEM_STRING_SUBMENU + +#define IMAGES_NODENAME "UserDefinedImages" + +// The following order is mandatory. Please add properties at the end! +#define INDEX_URL 0 +#define INDEX_TITLE 1 +#define INDEX_IMAGEIDENTIFIER 2 +#define INDEX_TARGET 3 +#define INDEX_CONTEXT 4 +#define INDEX_SUBMENU 5 +#define INDEX_CONTROLTYPE 6 +#define INDEX_WIDTH 7 +#define INDEX_ALIGN 8 +#define INDEX_AUTOSIZE 9 +#define INDEX_OWNERDRAW 10 +#define INDEX_MANDATORY 11 +#define INDEX_STYLE 12 +#define PROPERTYCOUNT_INDEX 13 + +// The following order is mandatory. Please add properties at the end! +#define PROPERTYCOUNT_MENUITEM 6 +#define OFFSET_MENUITEM_URL 0 +#define OFFSET_MENUITEM_TITLE 1 +#define OFFSET_MENUITEM_IMAGEIDENTIFIER 2 +#define OFFSET_MENUITEM_TARGET 3 +#define OFFSET_MENUITEM_CONTEXT 4 +#define OFFSET_MENUITEM_SUBMENU 5 + +// The following order is mandatory. Please add properties at the end! +#define PROPERTYCOUNT_POPUPMENU 4 +#define OFFSET_POPUPMENU_TITLE 0 +#define OFFSET_POPUPMENU_CONTEXT 1 +#define OFFSET_POPUPMENU_SUBMENU 2 +#define OFFSET_POPUPMENU_URL 3 // Used for property set + +// The following order is mandatory. Please add properties at the end! +#define PROPERTYCOUNT_TOOLBARITEM 7 +#define OFFSET_TOOLBARITEM_URL 0 +#define OFFSET_TOOLBARITEM_TITLE 1 +#define OFFSET_TOOLBARITEM_IMAGEIDENTIFIER 2 +#define OFFSET_TOOLBARITEM_TARGET 3 +#define OFFSET_TOOLBARITEM_CONTEXT 4 +#define OFFSET_TOOLBARITEM_CONTROLTYPE 5 +#define OFFSET_TOOLBARITEM_WIDTH 6 + +// The following order is mandatory. Please add properties at the end! +#define PROPERTYCOUNT_NOTEBOOKBARITEM 8 +#define OFFSET_NOTEBOOKBARITEM_URL 0 +#define OFFSET_NOTEBOOKBARITEM_TITLE 1 +#define OFFSET_NOTEBOOKBARITEM_IMAGEIDENTIFIER 2 +#define OFFSET_NOTEBOOKBARITEM_TARGET 3 +#define OFFSET_NOTEBOOKBARITEM_CONTEXT 4 +#define OFFSET_NOTEBOOKBARITEM_CONTROLTYPE 5 +#define OFFSET_NOTEBOOKBARITEM_WIDTH 6 +#define OFFSET_NOTEBOOKBARITEM_STYLE 7 + +// The following order is mandatory. Please add properties at the end! +#define PROPERTYCOUNT_STATUSBARITEM 8 +#define OFFSET_STATUSBARITEM_URL 0 +#define OFFSET_STATUSBARITEM_TITLE 1 +#define OFFSET_STATUSBARITEM_CONTEXT 2 +#define OFFSET_STATUSBARITEM_ALIGN 3 +#define OFFSET_STATUSBARITEM_AUTOSIZE 4 +#define OFFSET_STATUSBARITEM_OWNERDRAW 5 +#define OFFSET_STATUSBARITEM_MANDATORY 6 +#define OFFSET_STATUSBARITEM_WIDTH 7 + +// The following order is mandatory. Please add properties at the end! +#define PROPERTYCOUNT_IMAGES 8 +#define PROPERTYCOUNT_EMBEDDED_IMAGES 4 +#define OFFSET_IMAGES_SMALL 0 +#define OFFSET_IMAGES_BIG 1 +#define OFFSET_IMAGES_SMALLHC 2 +#define OFFSET_IMAGES_BIGHC 3 +#define OFFSET_IMAGES_SMALL_URL 4 +#define OFFSET_IMAGES_BIG_URL 5 +#define OFFSET_IMAGES_SMALLHC_URL 6 +#define OFFSET_IMAGES_BIGHC_URL 7 + +#define PROPERTYCOUNT_MERGE_MENUBAR 6 +#define OFFSET_MERGEMENU_MERGEPOINT 0 +#define OFFSET_MERGEMENU_MERGECOMMAND 1 +#define OFFSET_MERGEMENU_MERGECOMMANDPARAMETER 2 +#define OFFSET_MERGEMENU_MERGEFALLBACK 3 +#define OFFSET_MERGEMENU_MERGECONTEXT 4 +#define OFFSET_MERGEMENU_MENUITEMS 5 + +#define PROPERTYCOUNT_MERGE_TOOLBAR 7 +#define OFFSET_MERGETOOLBAR_TOOLBAR 0 +#define OFFSET_MERGETOOLBAR_MERGEPOINT 1 +#define OFFSET_MERGETOOLBAR_MERGECOMMAND 2 +#define OFFSET_MERGETOOLBAR_MERGECOMMANDPARAMETER 3 +#define OFFSET_MERGETOOLBAR_MERGEFALLBACK 4 +#define OFFSET_MERGETOOLBAR_MERGECONTEXT 5 +#define OFFSET_MERGETOOLBAR_TOOLBARITEMS 6 + +#define PROPERTYCOUNT_MERGE_NOTEBOOKBAR 7 +#define OFFSET_MERGENOTEBOOKBAR_NOTEBOOKBAR 0 +#define OFFSET_MERGENOTEBOOKBAR_MERGEPOINT 1 +#define OFFSET_MERGENOTEBOOKBAR_MERGECOMMAND 2 +#define OFFSET_MERGENOTEBOOKBAR_MERGECOMMANDPARAMETER 3 +#define OFFSET_MERGENOTEBOOKBAR_MERGEFALLBACK 4 +#define OFFSET_MERGENOTEBOOKBAR_MERGECONTEXT 5 +#define OFFSET_MERGENOTEBOOKBAR_NOTEBOOKBARITEMS 6 + +#define PROPERTYCOUNT_MERGE_STATUSBAR 6 +#define OFFSET_MERGESTATUSBAR_MERGEPOINT 0 +#define OFFSET_MERGESTATUSBAR_MERGECOMMAND 1 +#define OFFSET_MERGESTATUSBAR_MERGECOMMANDPARAMETER 2 +#define OFFSET_MERGESTATUSBAR_MERGEFALLBACK 3 +#define OFFSET_MERGESTATUSBAR_MERGECONTEXT 4 +#define OFFSET_MERGESTATUSBAR_STATUSBARITEMS 5 + +// private declarations! + +/*-**************************************************************************************************************** + @descr struct to hold information about one menu entry. +****************************************************************************************************************-*/ + +namespace framework +{ + +class AddonsOptions_Impl : public ConfigItem +{ + + // public methods + + public: + + // constructor / destructor + + AddonsOptions_Impl(); + virtual ~AddonsOptions_Impl() override; + + // overridden methods of baseclass + + /*-**************************************************************************************************** + @short called for notify of configmanager + @descr This method is called from the ConfigManager before application ends or from the + PropertyChangeListener if the sub tree broadcasts changes. You must update your + internal values. + + @seealso baseclass ConfigItem + + @param "lPropertyNames" is the list of properties which should be updated. + *//*-*****************************************************************************************************/ + + virtual void Notify( const Sequence< OUString >& lPropertyNames ) override; + + // public interface + + /*-**************************************************************************************************** + @short base implementation of public interface for "SvtDynamicMenuOptions"! + @descr These class is used as static member of "SvtDynamicMenuOptions" ... + => The code exist only for one time and isn't duplicated for every instance! + *//*-*****************************************************************************************************/ + + bool HasAddonsMenu () const; + sal_Int32 GetAddonsToolBarCount() const; + sal_Int32 GetAddonsNotebookBarCount() const; + const Sequence< Sequence< PropertyValue > >& GetAddonsMenu () const { return m_aCachedMenuProperties;} + const Sequence< Sequence< PropertyValue > >& GetAddonsMenuBarPart () const { return m_aCachedMenuBarPartProperties;} + const Sequence< Sequence< PropertyValue > >& GetAddonsToolBarPart ( sal_uInt32 nIndex ) const; + const Sequence< Sequence< PropertyValue > >& GetAddonsNotebookBarPart ( sal_uInt32 nIndex ) const; + OUString GetAddonsToolbarResourceName( sal_uInt32 nIndex ) const; + OUString GetAddonsNotebookBarResourceName( sal_uInt32 nIndex ) const; + const Sequence< Sequence< PropertyValue > >& GetAddonsHelpMenu () const { return m_aCachedHelpMenuProperties;} + Image GetImageFromURL( const OUString& aURL, bool bBig, bool bNoScale ); + const MergeMenuInstructionContainer& GetMergeMenuInstructions() const { return m_aCachedMergeMenuInsContainer;} + bool GetMergeToolbarInstructions( const OUString& rToolbarName, MergeToolbarInstructionContainer& rToolbarInstructions ) const; + bool GetMergeNotebookBarInstructions( const OUString& rNotebookBarName, MergeNotebookBarInstructionContainer& rNotebookBarInstructions ) const; + const MergeStatusbarInstructionContainer& GetMergeStatusbarInstructions() const { return m_aCachedStatusbarMergingInstructions;} + void ReadConfigurationData(); + + private: + enum ImageSize + { + IMGSIZE_SMALL = 0, + IMGSIZE_BIG + }; + + struct OneImageEntry + { + Image aScaled; ///< cached scaled image + Image aImage; ///< original un-scaled image + OUString aURL; ///< URL in case it is not loaded yet + }; + + struct ImageEntry + { + // if the image is set, it was embedded in some way, + // otherwise we use the associated URL to load on demand + + // accessed in this order + OneImageEntry aSizeEntry[2]; + ImageEntry() {} + void addImage(ImageSize eSize, const Image &rImage, const OUString &rURL); + }; + + typedef std::unordered_map< OUString, ImageEntry > ImageManager; + typedef std::unordered_map< OUString, sal_uInt32 > StringToIndexMap; + typedef std::vector< Sequence< Sequence< PropertyValue > > > AddonToolBars; + typedef std::vector< Sequence< Sequence< PropertyValue > > > AddonNotebookBars; + typedef std::unordered_map< OUString, MergeToolbarInstructionContainer > ToolbarMergingInstructions; + typedef std::unordered_map< OUString, MergeNotebookBarInstructionContainer > NotebookBarMergingInstructions; + + /*-**************************************************************************************************** + @short return list of key names of our configuration management which represent our module tree + @descr These methods return the current list of key names! We need it to get needed values from our + configuration management! + @param "nCount" , returns count of menu entries for "new" + @return A list of configuration key names is returned. + *//*-*****************************************************************************************************/ + + void ReadAddonMenuSet( Sequence< Sequence< PropertyValue > >& aAddonMenuSeq ); + void ReadOfficeMenuBarSet( Sequence< Sequence< PropertyValue > >& aAddonOfficeMenuBarSeq ); + void ReadOfficeToolBarSet( AddonToolBars& rAddonOfficeToolBars, std::vector< OUString >& rAddonOfficeToolBarResNames ); + bool ReadToolBarItemSet( const OUString& rToolBarItemSetNodeName, Sequence< Sequence< PropertyValue > >& aAddonOfficeToolBarSeq ); + void ReadOfficeNotebookBarSet( AddonNotebookBars& rAddonOfficeNotebookBars, std::vector< OUString >& rAddonOfficeNotebookBarResNames ); + bool ReadNotebookBarItemSet( const OUString& rNotebookBarItemSetNodeName, Sequence< Sequence< PropertyValue > >& aAddonOfficeNotebookBarSeq ); + + void ReadOfficeHelpSet( Sequence< Sequence< PropertyValue > >& aAddonOfficeHelpMenuSeq ); + void ReadImages( ImageManager& aImageManager ); + void ReadMenuMergeInstructions( MergeMenuInstructionContainer& rContainer ); + void ReadToolbarMergeInstructions( ToolbarMergingInstructions& rToolbarMergeMap ); + void ReadNotebookBarMergeInstructions( NotebookBarMergingInstructions& rNotebookBarMergeMap ); + void ReadStatusbarMergeInstructions( MergeStatusbarInstructionContainer& rContainer ); + + void ReadMergeMenuData( const OUString& aMergeAddonInstructionBase, Sequence< Sequence< PropertyValue > >& rMergeMenu ); + bool ReadMergeToolbarData( const OUString& aMergeAddonInstructionBase, Sequence< Sequence< PropertyValue > >& rMergeToolbarItems ); + bool ReadMergeNotebookBarData( const OUString& aMergeAddonInstructionBase, Sequence< Sequence< PropertyValue > >& rMergeNotebookBarItems ); + bool ReadMergeStatusbarData( const OUString& aMergeAddonInstructionBase, Sequence< Sequence< PropertyValue > >& rMergeStatusbar ); + bool ReadMenuItem( const OUString& aMenuItemNodeName, Sequence< PropertyValue >& aMenuItem, bool bIgnoreSubMenu = false ); + bool ReadPopupMenu( const OUString& aPopupMenuNodeName, Sequence< PropertyValue >& aPopupMenu ); + void AppendPopupMenu( Sequence< PropertyValue >& aTargetPopupMenu, const Sequence< PropertyValue >& rSourcePopupMenu ); + bool ReadToolBarItem( const OUString& aToolBarItemNodeName, Sequence< PropertyValue >& aToolBarItem ); + bool ReadNotebookBarItem( const OUString& aNotebookBarItemNodeName, Sequence< PropertyValue >& aNotebookBarItem ); + + bool ReadStatusBarItem( const OUString& aStatusbarItemNodeName, Sequence< PropertyValue >& aStatusbarItem ); + std::unique_ptr ReadImageData( const OUString& aImagesNodeName ); + void ReadAndAssociateImages( const OUString& aURL, const OUString& aImageId ); + Image ReadImageFromURL( const OUString& aURL ); + bool HasAssociatedImages( const OUString& aURL ); + void SubstituteVariables( OUString& aURL ); + + void ReadSubMenuEntries( const Sequence< OUString >& aSubMenuNodeNames, Sequence< Sequence< PropertyValue > >& rSubMenu ); + OUString GeneratePrefixURL(); + + Sequence< OUString > GetPropertyNamesMenuItem( const OUString& aPropertyRootNode ) const; + Sequence< OUString > GetPropertyNamesPopupMenu( const OUString& aPropertyRootNode ) const; + Sequence< OUString > GetPropertyNamesToolBarItem( const OUString& aPropertyRootNode ) const; + Sequence< OUString > GetPropertyNamesNotebookBarItem( const OUString& aPropertyRootNode ) const; + + Sequence< OUString > GetPropertyNamesStatusbarItem( const OUString& aPropertyRootNode ) const; + Sequence< OUString > GetPropertyNamesImages( const OUString& aPropertyRootNode ) const; + bool CreateImageFromSequence( Image& rImage, Sequence< sal_Int8 >& rBitmapDataSeq ) const; + + DECL_LINK(NotifyEvent, void*, void); + + virtual void ImplCommit() override; + + // private member + + private: + sal_Int32 m_nRootAddonPopupMenuId; + OUString m_aPropNames[PROPERTYCOUNT_INDEX]; + OUString m_aPropImagesNames[PROPERTYCOUNT_IMAGES]; + OUString m_aPropMergeMenuNames[PROPERTYCOUNT_MERGE_MENUBAR]; + OUString m_aPropMergeToolbarNames[PROPERTYCOUNT_MERGE_TOOLBAR]; + OUString m_aPropMergeNotebookBarNames[PROPERTYCOUNT_MERGE_NOTEBOOKBAR]; + OUString m_aPropMergeStatusbarNames[PROPERTYCOUNT_MERGE_STATUSBAR]; + OUString m_aPathDelimiter; + OUString m_aRootAddonPopupMenuURLPrexfix; + Sequence< Sequence< PropertyValue > > m_aCachedMenuProperties; + Sequence< Sequence< PropertyValue > > m_aCachedMenuBarPartProperties; + AddonToolBars m_aCachedToolBarPartProperties; + AddonNotebookBars m_aCachedNotebookBarPartProperties; + std::vector< OUString > m_aCachedToolBarPartResourceNames; + std::vector< OUString > m_aCachedNotebookBarPartResourceNames; + Sequence< Sequence< PropertyValue > > m_aCachedHelpMenuProperties; + ImageManager m_aImageManager; + Sequence< Sequence< PropertyValue > > m_aEmptyAddonToolBar; + Sequence< Sequence< PropertyValue > > m_aEmptyAddonNotebookBar; + MergeMenuInstructionContainer m_aCachedMergeMenuInsContainer; + ToolbarMergingInstructions m_aCachedToolbarMergingInstructions; + NotebookBarMergingInstructions m_aCachedNotebookBarMergingInstructions; + MergeStatusbarInstructionContainer m_aCachedStatusbarMergingInstructions; +}; + +void AddonsOptions_Impl::ImageEntry::addImage(ImageSize eSize, + const Image &rImage, + const OUString &rURL) +{ + aSizeEntry[static_cast(eSize)].aImage = rImage; + aSizeEntry[static_cast(eSize)].aURL = rURL; +} + +// constructor + +AddonsOptions_Impl::AddonsOptions_Impl() + // Init baseclasses first + : ConfigItem( ROOTNODE_ADDONMENU ), + m_nRootAddonPopupMenuId( 0 ), + m_aPathDelimiter( PATHDELIMITER ), + m_aRootAddonPopupMenuURLPrexfix( ADDONSPOPUPMENU_URL_PREFIX_STR ) +{ + // initialize array with fixed property names + m_aPropNames[ INDEX_URL ] = PROPERTYNAME_URL; + m_aPropNames[ INDEX_TITLE ] = PROPERTYNAME_TITLE; + m_aPropNames[ INDEX_TARGET ] = PROPERTYNAME_TARGET; + m_aPropNames[ INDEX_IMAGEIDENTIFIER ] = PROPERTYNAME_IMAGEIDENTIFIER; + m_aPropNames[ INDEX_CONTEXT ] = PROPERTYNAME_CONTEXT; + m_aPropNames[ INDEX_SUBMENU ] = PROPERTYNAME_SUBMENU; // Submenu set! + m_aPropNames[ INDEX_CONTROLTYPE ] = "ControlType"; + m_aPropNames[ INDEX_WIDTH ] = "Width"; + m_aPropNames[ INDEX_ALIGN ] = "Alignment"; + m_aPropNames[ INDEX_AUTOSIZE ] = "AutoSize"; + m_aPropNames[ INDEX_OWNERDRAW ] = "OwnerDraw"; + m_aPropNames[ INDEX_MANDATORY ] = "Mandatory"; + m_aPropNames[ INDEX_STYLE ] = "Style"; + + // initialize array with fixed images property names + m_aPropImagesNames[ OFFSET_IMAGES_SMALL ] = "ImageSmall"; + m_aPropImagesNames[ OFFSET_IMAGES_BIG ] = "ImageBig"; + m_aPropImagesNames[ OFFSET_IMAGES_SMALLHC ] = "ImageSmallHC"; + m_aPropImagesNames[ OFFSET_IMAGES_BIGHC ] = "ImageBigHC"; + m_aPropImagesNames[ OFFSET_IMAGES_SMALL_URL ] = "ImageSmallURL"; + m_aPropImagesNames[ OFFSET_IMAGES_BIG_URL ] = "ImageBigURL"; + m_aPropImagesNames[ OFFSET_IMAGES_SMALLHC_URL ] = "ImageSmallHCURL"; + m_aPropImagesNames[ OFFSET_IMAGES_BIGHC_URL ] = "ImageBigHCURL"; + + // initialize array with fixed merge menu property names + m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MERGEPOINT ] = "MergePoint"; + m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MERGECOMMAND ] = "MergeCommand"; + m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MERGECOMMANDPARAMETER ] = "MergeCommandParameter"; + m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MERGEFALLBACK ] = "MergeFallback"; + m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MERGECONTEXT ] = "MergeContext"; + m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MENUITEMS ] = "MenuItems"; + + m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_TOOLBAR ] = "MergeToolBar"; + m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_MERGEPOINT ] = "MergePoint"; + m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_MERGECOMMAND ] = "MergeCommand"; + m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_MERGECOMMANDPARAMETER ] = "MergeCommandParameter"; + m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_MERGEFALLBACK ] = "MergeFallback"; + m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_MERGECONTEXT ] = "MergeContext"; + m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_TOOLBARITEMS ] = "ToolBarItems"; + + m_aPropMergeNotebookBarNames[ OFFSET_MERGENOTEBOOKBAR_NOTEBOOKBAR ] = "MergeNotebookBar"; + m_aPropMergeNotebookBarNames[ OFFSET_MERGENOTEBOOKBAR_MERGEPOINT ] = "MergePoint"; + m_aPropMergeNotebookBarNames[ OFFSET_MERGENOTEBOOKBAR_MERGECOMMAND ] = "MergeCommand"; + m_aPropMergeNotebookBarNames[ OFFSET_MERGENOTEBOOKBAR_MERGECOMMANDPARAMETER ] = "MergeCommandParameter"; + m_aPropMergeNotebookBarNames[ OFFSET_MERGENOTEBOOKBAR_MERGEFALLBACK ] = "MergeFallback"; + m_aPropMergeNotebookBarNames[ OFFSET_MERGENOTEBOOKBAR_MERGECONTEXT ] = "MergeContext"; + m_aPropMergeNotebookBarNames[ OFFSET_MERGENOTEBOOKBAR_NOTEBOOKBARITEMS ] = "NotebookBarItems"; + + m_aPropMergeStatusbarNames[ OFFSET_MERGESTATUSBAR_MERGEPOINT ] = "MergePoint"; + m_aPropMergeStatusbarNames[ OFFSET_MERGESTATUSBAR_MERGECOMMAND ] = "MergeCommand"; + m_aPropMergeStatusbarNames[ OFFSET_MERGESTATUSBAR_MERGECOMMANDPARAMETER ] = "MergeCommandParameter"; + m_aPropMergeStatusbarNames[ OFFSET_MERGESTATUSBAR_MERGEFALLBACK ] = "MergeFallback"; + m_aPropMergeStatusbarNames[ OFFSET_MERGESTATUSBAR_MERGECONTEXT ] = "MergeContext"; + m_aPropMergeStatusbarNames[ OFFSET_MERGESTATUSBAR_STATUSBARITEMS ] = "StatusBarItems"; + + ReadConfigurationData(); + + // Enable notification mechanism of our baseclass. + // We need it to get information about changes outside these class on our used configuration keys! + Sequence aNotifySeq { "AddonUI" }; + EnableNotification( aNotifySeq ); +} + +// destructor + +AddonsOptions_Impl::~AddonsOptions_Impl() +{ + assert(!IsModified()); // should have been committed +} + +void AddonsOptions_Impl::ReadConfigurationData() +{ + // reset members to be read again from configuration + m_aCachedMenuProperties = Sequence< Sequence< PropertyValue > >(); + m_aCachedMenuBarPartProperties = Sequence< Sequence< PropertyValue > >(); + m_aCachedToolBarPartProperties = AddonToolBars(); + m_aCachedNotebookBarPartProperties = AddonNotebookBars(); + m_aCachedHelpMenuProperties = Sequence< Sequence< PropertyValue > >(); + m_aCachedToolBarPartResourceNames.clear(); + m_aCachedNotebookBarPartResourceNames.clear(); + m_aImageManager = ImageManager(); + + ReadAddonMenuSet( m_aCachedMenuProperties ); + ReadOfficeMenuBarSet( m_aCachedMenuBarPartProperties ); + ReadOfficeToolBarSet( m_aCachedToolBarPartProperties, m_aCachedToolBarPartResourceNames ); + ReadOfficeNotebookBarSet( m_aCachedNotebookBarPartProperties, m_aCachedNotebookBarPartResourceNames ); + + ReadOfficeHelpSet( m_aCachedHelpMenuProperties ); + ReadImages( m_aImageManager ); + + m_aCachedMergeMenuInsContainer.clear(); + m_aCachedToolbarMergingInstructions.clear(); + m_aCachedNotebookBarMergingInstructions.clear(); + m_aCachedStatusbarMergingInstructions.clear(); + + ReadMenuMergeInstructions( m_aCachedMergeMenuInsContainer ); + ReadToolbarMergeInstructions( m_aCachedToolbarMergingInstructions ); + ReadNotebookBarMergeInstructions( m_aCachedNotebookBarMergingInstructions ); + ReadStatusbarMergeInstructions( m_aCachedStatusbarMergingInstructions ); +} + +// public method + +void AddonsOptions_Impl::Notify( const Sequence< OUString >& /*lPropertyNames*/ ) +{ + Application::PostUserEvent(LINK(this, AddonsOptions_Impl, NotifyEvent)); +} + +// public method + +void AddonsOptions_Impl::ImplCommit() +{ + SAL_WARN("fwk", "AddonsOptions_Impl::ImplCommit(): Not implemented yet!"); +} + +// public method + +bool AddonsOptions_Impl::HasAddonsMenu() const +{ + return m_aCachedMenuProperties.hasElements(); +} + +// public method + +sal_Int32 AddonsOptions_Impl::GetAddonsToolBarCount() const +{ + return m_aCachedToolBarPartProperties.size(); +} + +// public method + +sal_Int32 AddonsOptions_Impl::GetAddonsNotebookBarCount() const +{ + return m_aCachedNotebookBarPartProperties.size(); +} + +// public method + +const Sequence< Sequence< PropertyValue > >& AddonsOptions_Impl::GetAddonsToolBarPart( sal_uInt32 nIndex ) const +{ + if ( /*nIndex >= 0 &&*/ nIndex < m_aCachedToolBarPartProperties.size() ) + return m_aCachedToolBarPartProperties[nIndex]; + else + return m_aEmptyAddonToolBar; +} + +// public method + +const Sequence< Sequence< PropertyValue > >& AddonsOptions_Impl::GetAddonsNotebookBarPart( sal_uInt32 nIndex ) const +{ + if ( /*nIndex >= 0 &&*/ nIndex < m_aCachedNotebookBarPartProperties.size() ) + return m_aCachedNotebookBarPartProperties[nIndex]; + else + return m_aEmptyAddonNotebookBar; +} + +// public method + +OUString AddonsOptions_Impl::GetAddonsToolbarResourceName( sal_uInt32 nIndex ) const +{ + if ( nIndex < m_aCachedToolBarPartResourceNames.size() ) + return m_aCachedToolBarPartResourceNames[nIndex]; + else + return OUString(); +} + +// public method + +OUString AddonsOptions_Impl::GetAddonsNotebookBarResourceName( sal_uInt32 nIndex ) const +{ + if ( nIndex < m_aCachedNotebookBarPartResourceNames.size() ) + return m_aCachedNotebookBarPartResourceNames[nIndex]; + else + return OUString(); +} + +// public method + +bool AddonsOptions_Impl::GetMergeToolbarInstructions( + const OUString& rToolbarName, + MergeToolbarInstructionContainer& rToolbarInstructions ) const +{ + ToolbarMergingInstructions::const_iterator pIter = m_aCachedToolbarMergingInstructions.find( rToolbarName ); + if ( pIter != m_aCachedToolbarMergingInstructions.end() ) + { + rToolbarInstructions = pIter->second; + return true; + } + else + return false; +} + +// public method + +bool AddonsOptions_Impl::GetMergeNotebookBarInstructions( + const OUString& rNotebookBarName, + MergeNotebookBarInstructionContainer& rNotebookBarInstructions ) const +{ + NotebookBarMergingInstructions::const_iterator pIter = m_aCachedNotebookBarMergingInstructions.find( rNotebookBarName ); + if ( pIter != m_aCachedNotebookBarMergingInstructions.end() ) + { + rNotebookBarInstructions = pIter->second; + return true; + } + else + return false; +} + +// public method + +static Image ScaleImage( const Image &rImage, bool bBig ) +{ + Size aSize = ToolBox::GetDefaultImageSize(bBig ? ToolBoxButtonSize::Large : ToolBoxButtonSize::Small); + BitmapEx aScaleBmp(rImage.GetBitmapEx()); + SAL_INFO("fwk", "Addons: expensive scale image from " + << aScaleBmp.GetSizePixel() << " to " << aSize); + aScaleBmp.Scale(aSize, BmpScaleFlag::BestQuality); + return Image(aScaleBmp); +} + +Image AddonsOptions_Impl::GetImageFromURL( const OUString& aURL, bool bBig, bool bNoScale ) +{ + Image aImage; + + SAL_INFO("fwk", "Expensive: Addons GetImageFromURL " << aURL << + " big " << (bBig?"big":"little") << + " scale " << (bNoScale ? "noscale" : "scale")); + + ImageManager::iterator pIter = m_aImageManager.find(aURL); + if ( pIter != m_aImageManager.end() ) + { + ImageSize eSize = bBig ? IMGSIZE_BIG : IMGSIZE_SMALL; + int nIdx = static_cast(eSize); + int nOtherIdx = nIdx ? 0 : 1; + + OneImageEntry& rSizeEntry = pIter->second.aSizeEntry[nIdx]; + OneImageEntry& rOtherEntry = pIter->second.aSizeEntry[nOtherIdx]; + // actually read the image ... + if (!rSizeEntry.aImage) + rSizeEntry.aImage = ReadImageFromURL(rSizeEntry.aURL); + + if (!rSizeEntry.aImage) + { // try the other size and scale it + aImage = ScaleImage(ReadImageFromURL(rOtherEntry.aURL), bBig); + rSizeEntry.aImage = aImage; + if (!rSizeEntry.aImage) + SAL_WARN("fwk", "failed to load addons image " << aURL); + } + + // FIXME: bNoScale is not terribly meaningful or useful + + if (!aImage && bNoScale) + aImage = rSizeEntry.aImage; + + if (!aImage && !!rSizeEntry.aScaled) + aImage = rSizeEntry.aScaled; + + else // scale to the correct size for the theme / toolbox + { + aImage = rSizeEntry.aImage; + if (!aImage) // use and scale the other if one size is missing + aImage = rOtherEntry.aImage; + + aImage = ScaleImage(aImage, bBig); + rSizeEntry.aScaled = aImage; // cache for next time + } + } + + return aImage; +} + +void AddonsOptions_Impl::ReadAddonMenuSet( Sequence< Sequence< PropertyValue > >& rAddonMenuSeq ) +{ + // Read the AddonMenu set and fill property sequences + OUString aAddonMenuNodeName( "AddonUI/AddonMenu" ); + Sequence< OUString > aAddonMenuNodeSeq = GetNodeNames( aAddonMenuNodeName ); + OUString aAddonMenuItemNode( aAddonMenuNodeName + m_aPathDelimiter ); + + sal_uInt32 nCount = aAddonMenuNodeSeq.getLength(); + sal_uInt32 nIndex = 0; + Sequence< PropertyValue > aMenuItem( PROPERTYCOUNT_MENUITEM ); + + // Init the property value sequence + aMenuItem[ OFFSET_MENUITEM_URL ].Name = m_aPropNames[ INDEX_URL ]; + aMenuItem[ OFFSET_MENUITEM_TITLE ].Name = m_aPropNames[ INDEX_TITLE ]; + aMenuItem[ OFFSET_MENUITEM_TARGET ].Name = m_aPropNames[ INDEX_TARGET ]; + aMenuItem[ OFFSET_MENUITEM_IMAGEIDENTIFIER ].Name = m_aPropNames[ INDEX_IMAGEIDENTIFIER]; + aMenuItem[ OFFSET_MENUITEM_CONTEXT ].Name = m_aPropNames[ INDEX_CONTEXT ]; + aMenuItem[ OFFSET_MENUITEM_SUBMENU ].Name = m_aPropNames[ INDEX_SUBMENU ]; // Submenu set! + + for ( sal_uInt32 n = 0; n < nCount; n++ ) + { + OUString aRootMenuItemNode( aAddonMenuItemNode + aAddonMenuNodeSeq[n] ); + + // Read the MenuItem + if ( ReadMenuItem( aRootMenuItemNode, aMenuItem ) ) + { + // Successfully read a menu item, append to our list + sal_uInt32 nMenuItemCount = rAddonMenuSeq.getLength() + 1; + rAddonMenuSeq.realloc( nMenuItemCount ); + rAddonMenuSeq[nIndex++] = aMenuItem; + } + } +} + +void AddonsOptions_Impl::ReadOfficeHelpSet( Sequence< Sequence< PropertyValue > >& rAddonOfficeHelpMenuSeq ) +{ + // Read the AddonMenu set and fill property sequences + OUString aAddonHelpMenuNodeName( "AddonUI/OfficeHelp" ); + Sequence< OUString > aAddonHelpMenuNodeSeq = GetNodeNames( aAddonHelpMenuNodeName ); + OUString aAddonHelpMenuItemNode( aAddonHelpMenuNodeName + m_aPathDelimiter ); + + sal_uInt32 nCount = aAddonHelpMenuNodeSeq.getLength(); + sal_uInt32 nIndex = 0; + Sequence< PropertyValue > aMenuItem( PROPERTYCOUNT_MENUITEM ); + + // Init the property value sequence + aMenuItem[ OFFSET_MENUITEM_URL ].Name = m_aPropNames[ INDEX_URL ]; + aMenuItem[ OFFSET_MENUITEM_TITLE ].Name = m_aPropNames[ INDEX_TITLE ]; + aMenuItem[ OFFSET_MENUITEM_TARGET ].Name = m_aPropNames[ INDEX_TARGET ]; + aMenuItem[ OFFSET_MENUITEM_IMAGEIDENTIFIER ].Name = m_aPropNames[ INDEX_IMAGEIDENTIFIER]; + aMenuItem[ OFFSET_MENUITEM_CONTEXT ].Name = m_aPropNames[ INDEX_CONTEXT ]; + aMenuItem[ OFFSET_MENUITEM_SUBMENU ].Name = m_aPropNames[ INDEX_SUBMENU ]; // Submenu set! + + for ( sal_uInt32 n = 0; n < nCount; n++ ) + { + OUString aRootMenuItemNode( aAddonHelpMenuItemNode + aAddonHelpMenuNodeSeq[n] ); + + // Read the MenuItem + if ( ReadMenuItem( aRootMenuItemNode, aMenuItem, true ) ) + { + // Successfully read a menu item, append to our list + sal_uInt32 nMenuItemCount = rAddonOfficeHelpMenuSeq.getLength() + 1; + rAddonOfficeHelpMenuSeq.realloc( nMenuItemCount ); + rAddonOfficeHelpMenuSeq[nIndex++] = aMenuItem; + } + } +} + +void AddonsOptions_Impl::ReadOfficeMenuBarSet( Sequence< Sequence< PropertyValue > >& rAddonOfficeMenuBarSeq ) +{ + // Read the OfficeMenuBar set and fill property sequences + OUString aAddonMenuBarNodeName( "AddonUI/OfficeMenuBar" ); + Sequence< OUString > aAddonMenuBarNodeSeq = GetNodeNames( aAddonMenuBarNodeName ); + OUString aAddonMenuBarNode( aAddonMenuBarNodeName + m_aPathDelimiter ); + + sal_uInt32 nCount = aAddonMenuBarNodeSeq.getLength(); + sal_uInt32 nIndex = 0; + Sequence< PropertyValue > aPopupMenu( PROPERTYCOUNT_POPUPMENU ); + + // Init the property value sequence + aPopupMenu[ OFFSET_POPUPMENU_TITLE ].Name = m_aPropNames[ INDEX_TITLE ]; + aPopupMenu[ OFFSET_POPUPMENU_CONTEXT ].Name = m_aPropNames[ INDEX_CONTEXT]; + aPopupMenu[ OFFSET_POPUPMENU_SUBMENU ].Name = m_aPropNames[ INDEX_SUBMENU]; + aPopupMenu[ OFFSET_POPUPMENU_URL ].Name = m_aPropNames[ INDEX_URL ]; + + StringToIndexMap aTitleToIndexMap; + + for ( sal_uInt32 n = 0; n < nCount; n++ ) + { + OUString aPopupMenuNode( aAddonMenuBarNode + aAddonMenuBarNodeSeq[n] ); + + // Read the MenuItem + if ( ReadPopupMenu( aPopupMenuNode, aPopupMenu ) ) + { + // Successfully read a popup menu, append to our list + OUString aPopupTitle; + if ( aPopupMenu[OFFSET_POPUPMENU_TITLE].Value >>= aPopupTitle ) + { + StringToIndexMap::const_iterator pIter = aTitleToIndexMap.find( aPopupTitle ); + if ( pIter != aTitleToIndexMap.end() ) + { + // title already there => concat both popup menus + Sequence< PropertyValue >& rOldPopupMenu = rAddonOfficeMenuBarSeq[pIter->second]; + AppendPopupMenu( rOldPopupMenu, aPopupMenu ); + } + else + { + // not found + sal_uInt32 nMenuItemCount = rAddonOfficeMenuBarSeq.getLength() + 1; + rAddonOfficeMenuBarSeq.realloc( nMenuItemCount ); + rAddonOfficeMenuBarSeq[nIndex] = aPopupMenu; + aTitleToIndexMap.emplace( aPopupTitle, nIndex ); + ++nIndex; + } + } + } + } +} + +void AddonsOptions_Impl::ReadOfficeToolBarSet( AddonToolBars& rAddonOfficeToolBars, std::vector< OUString >& rAddonOfficeToolBarResNames ) +{ + // Read the OfficeToolBar set and fill property sequences + OUString aAddonToolBarNodeName( "AddonUI/OfficeToolBar" ); + Sequence< OUString > aAddonToolBarNodeSeq = GetNodeNames( aAddonToolBarNodeName ); + OUString aAddonToolBarNode( aAddonToolBarNodeName + m_aPathDelimiter ); + + sal_uInt32 nCount = aAddonToolBarNodeSeq.getLength(); + + for ( sal_uInt32 n = 0; n < nCount; n++ ) + { + OUString aToolBarItemNode( aAddonToolBarNode + aAddonToolBarNodeSeq[n] ); + rAddonOfficeToolBarResNames.push_back( aAddonToolBarNodeSeq[n] ); + rAddonOfficeToolBars.push_back( m_aEmptyAddonToolBar ); + ReadToolBarItemSet( aToolBarItemNode, rAddonOfficeToolBars[n] ); + } +} + +bool AddonsOptions_Impl::ReadToolBarItemSet( const OUString& rToolBarItemSetNodeName, Sequence< Sequence< PropertyValue > >& rAddonOfficeToolBarSeq ) +{ + sal_uInt32 nToolBarItemCount = rAddonOfficeToolBarSeq.getLength(); + OUString aAddonToolBarItemSetNode( rToolBarItemSetNodeName + m_aPathDelimiter ); + Sequence< OUString > aAddonToolBarItemSetNodeSeq = GetNodeNames( rToolBarItemSetNodeName ); + Sequence< PropertyValue > aToolBarItem( PROPERTYCOUNT_TOOLBARITEM ); + + // Init the property value sequence + aToolBarItem[ OFFSET_TOOLBARITEM_URL ].Name = m_aPropNames[ INDEX_URL ]; + aToolBarItem[ OFFSET_TOOLBARITEM_TITLE ].Name = m_aPropNames[ INDEX_TITLE ]; + aToolBarItem[ OFFSET_TOOLBARITEM_IMAGEIDENTIFIER ].Name = m_aPropNames[ INDEX_IMAGEIDENTIFIER]; + aToolBarItem[ OFFSET_TOOLBARITEM_TARGET ].Name = m_aPropNames[ INDEX_TARGET ]; + aToolBarItem[ OFFSET_TOOLBARITEM_CONTEXT ].Name = m_aPropNames[ INDEX_CONTEXT ]; + aToolBarItem[ OFFSET_TOOLBARITEM_CONTROLTYPE ].Name = m_aPropNames[ INDEX_CONTROLTYPE ]; + aToolBarItem[ OFFSET_TOOLBARITEM_WIDTH ].Name = m_aPropNames[ INDEX_WIDTH ]; + + sal_uInt32 nCount = aAddonToolBarItemSetNodeSeq.getLength(); + for ( sal_uInt32 n = 0; n < nCount; n++ ) + { + OUString aToolBarItemNode( aAddonToolBarItemSetNode + aAddonToolBarItemSetNodeSeq[n] ); + + // Read the ToolBarItem + if ( ReadToolBarItem( aToolBarItemNode, aToolBarItem ) ) + { + // Successfully read a toolbar item, append to our list + sal_uInt32 nAddonCount = rAddonOfficeToolBarSeq.getLength(); + rAddonOfficeToolBarSeq.realloc( nAddonCount+1 ); + rAddonOfficeToolBarSeq[nAddonCount] = aToolBarItem; + } + } + + return ( o3tl::make_unsigned(rAddonOfficeToolBarSeq.getLength()) > nToolBarItemCount ); +} + +void AddonsOptions_Impl::ReadOfficeNotebookBarSet( + AddonNotebookBars& rAddonOfficeNotebookBars, + std::vector& rAddonOfficeNotebookBarResNames) +{ + // Read the OfficeToolBar set and fill property sequences + OUString aAddonNotebookBarNodeName("AddonUI/OfficeNotebookBar"); + Sequence aAddonNotebookBarNodeSeq = GetNodeNames(aAddonNotebookBarNodeName); + OUString aAddonNotebookBarNode(aAddonNotebookBarNodeName + m_aPathDelimiter); + + sal_uInt32 nCount = aAddonNotebookBarNodeSeq.getLength(); + + for (sal_uInt32 n = 0; n < nCount; n++) + { + OUString aNotebookBarItemNode(aAddonNotebookBarNode + aAddonNotebookBarNodeSeq[n]); + rAddonOfficeNotebookBarResNames.push_back(aAddonNotebookBarNodeSeq[n]); + rAddonOfficeNotebookBars.push_back(m_aEmptyAddonNotebookBar); + ReadNotebookBarItemSet(aNotebookBarItemNode, rAddonOfficeNotebookBars[n]); + } +} + +bool AddonsOptions_Impl::ReadNotebookBarItemSet( + const OUString& rNotebookBarItemSetNodeName, + Sequence>& rAddonOfficeNotebookBarSeq) +{ + sal_uInt32 nNotebookBarItemCount = rAddonOfficeNotebookBarSeq.getLength(); + OUString aAddonNotebookBarItemSetNode(rNotebookBarItemSetNodeName + m_aPathDelimiter); + Sequence aAddonNotebookBarItemSetNodeSeq = GetNodeNames(rNotebookBarItemSetNodeName); + Sequence aNotebookBarItem(PROPERTYCOUNT_NOTEBOOKBARITEM); + + // Init the property value sequence + aNotebookBarItem[OFFSET_NOTEBOOKBARITEM_URL].Name = m_aPropNames[INDEX_URL]; + aNotebookBarItem[OFFSET_NOTEBOOKBARITEM_TITLE].Name = m_aPropNames[INDEX_TITLE]; + aNotebookBarItem[OFFSET_NOTEBOOKBARITEM_IMAGEIDENTIFIER].Name + = m_aPropNames[INDEX_IMAGEIDENTIFIER]; + aNotebookBarItem[OFFSET_NOTEBOOKBARITEM_TARGET].Name = m_aPropNames[INDEX_TARGET]; + aNotebookBarItem[OFFSET_NOTEBOOKBARITEM_CONTEXT].Name = m_aPropNames[INDEX_CONTEXT]; + aNotebookBarItem[OFFSET_NOTEBOOKBARITEM_CONTROLTYPE].Name = m_aPropNames[INDEX_CONTROLTYPE]; + aNotebookBarItem[OFFSET_NOTEBOOKBARITEM_WIDTH].Name = m_aPropNames[INDEX_WIDTH]; + aNotebookBarItem[OFFSET_NOTEBOOKBARITEM_STYLE].Name = m_aPropNames[INDEX_STYLE]; + + sal_uInt32 nCount = aAddonNotebookBarItemSetNodeSeq.getLength(); + for (sal_uInt32 n = 0; n < nCount; n++) + { + OUString aNotebookBarItemNode(aAddonNotebookBarItemSetNode + + aAddonNotebookBarItemSetNodeSeq[n]); + // Read the NotebookBarItem + if (ReadNotebookBarItem(aNotebookBarItemNode, aNotebookBarItem)) + { + // Successfully read a toolbar item, append to our list + sal_uInt32 nAddonCount = rAddonOfficeNotebookBarSeq.getLength(); + rAddonOfficeNotebookBarSeq.realloc(nAddonCount + 1); + rAddonOfficeNotebookBarSeq[nAddonCount] = aNotebookBarItem; + } + } + + return (o3tl::make_unsigned(rAddonOfficeNotebookBarSeq.getLength()) + > nNotebookBarItemCount); +} + +void AddonsOptions_Impl::ReadImages( ImageManager& aImageManager ) +{ + // Read the user-defined Images set and fill image manager + OUString aAddonImagesNodeName( "AddonUI/Images" ); + Sequence< OUString > aAddonImagesNodeSeq = GetNodeNames( aAddonImagesNodeName ); + OUString aAddonImagesNode( aAddonImagesNodeName + m_aPathDelimiter ); + + sal_uInt32 nCount = aAddonImagesNodeSeq.getLength(); + + // Init the property value sequence + Sequence< OUString > aAddonImageItemNodePropNames( 1 ); + OUString aURL; + + for ( sal_uInt32 n = 0; n < nCount; n++ ) + { + OUString aImagesItemNode( aAddonImagesNode + aAddonImagesNodeSeq[n] ); + + // Create sequence for data access + aAddonImageItemNodePropNames[0] = aImagesItemNode + + m_aPathDelimiter + + m_aPropNames[ OFFSET_MENUITEM_URL ]; + + Sequence< Any > aAddonImageItemNodeValues = GetProperties( aAddonImageItemNodePropNames ); + + // An user-defined image entry must have a URL. As "ImageIdentifier" has a higher priority + // we also check if we already have an images association. + if (( aAddonImageItemNodeValues[0] >>= aURL ) && + !aURL.isEmpty() && + !HasAssociatedImages( aURL )) + { + OUString aImagesUserDefinedItemNode = aImagesItemNode + + m_aPathDelimiter + + IMAGES_NODENAME + + m_aPathDelimiter; + + // Read a user-defined images data + std::unique_ptr pImageEntry = ReadImageData( aImagesUserDefinedItemNode ); + if ( pImageEntry ) + { + // Successfully read a user-defined images item, put it into our image manager + aImageManager.emplace( aURL, std::move(*pImageEntry) ); + } + } + } +} + +OUString AddonsOptions_Impl::GeneratePrefixURL() +{ + // Create a unique prefixed Add-On popup menu URL so it can be identified later as a runtime popup menu. + // They use a different image manager, so they must be identified by the sfx2/framework code. + OUString aPopupMenuURL; + OUStringBuffer aBuf( m_aRootAddonPopupMenuURLPrexfix.getLength() + 3 ); + aBuf.append( m_aRootAddonPopupMenuURLPrexfix ); + aBuf.append( OUString::number( ++m_nRootAddonPopupMenuId )); + aPopupMenuURL = aBuf.makeStringAndClear(); + return aPopupMenuURL; +} + +void AddonsOptions_Impl::ReadMenuMergeInstructions( MergeMenuInstructionContainer& aContainer ) +{ + const OUString aMenuMergeRootName( "AddonUI/OfficeMenuBarMerging/" ); + + Sequence< OUString > aAddonMergeNodesSeq = GetNodeNames( aMenuMergeRootName ); + + sal_uInt32 nCount = aAddonMergeNodesSeq.getLength(); + + // Init the property value sequence + Sequence< OUString > aNodePropNames( 5 ); + + for ( sal_uInt32 i = 0; i < nCount; i++ ) + { + OUString aMergeAddonInstructions( aMenuMergeRootName + aAddonMergeNodesSeq[i] ); + + Sequence< OUString > aAddonInstMergeNodesSeq = GetNodeNames( aMergeAddonInstructions ); + sal_uInt32 nCountAddons = aAddonInstMergeNodesSeq.getLength(); + + for ( sal_uInt32 j = 0; j < nCountAddons; j++ ) + { + OUStringBuffer aMergeAddonInstructionBase( aMergeAddonInstructions ); + aMergeAddonInstructionBase.append( m_aPathDelimiter ); + aMergeAddonInstructionBase.append( aAddonInstMergeNodesSeq[j] ); + aMergeAddonInstructionBase.append( m_aPathDelimiter ); + + // Create sequence for data access + OUStringBuffer aBuffer( aMergeAddonInstructionBase ); + aBuffer.append( m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MERGEPOINT ] ); + aNodePropNames[0] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append( m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MERGECOMMAND ] ); + aNodePropNames[1] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append( m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MERGECOMMANDPARAMETER ] ); + aNodePropNames[2] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append( m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MERGEFALLBACK ] ); + aNodePropNames[3] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append( m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MERGECONTEXT ] ); + aNodePropNames[4] = aBuffer.makeStringAndClear(); + + Sequence< Any > aNodePropValues = GetProperties( aNodePropNames ); + + MergeMenuInstruction aMergeMenuInstruction; + aNodePropValues[0] >>= aMergeMenuInstruction.aMergePoint; + aNodePropValues[1] >>= aMergeMenuInstruction.aMergeCommand; + aNodePropValues[2] >>= aMergeMenuInstruction.aMergeCommandParameter; + aNodePropValues[3] >>= aMergeMenuInstruction.aMergeFallback; + aNodePropValues[4] >>= aMergeMenuInstruction.aMergeContext; + + OUString aMergeMenuBase = aMergeAddonInstructionBase.makeStringAndClear(); + ReadMergeMenuData( aMergeMenuBase, aMergeMenuInstruction.aMergeMenu ); + + aContainer.push_back( aMergeMenuInstruction ); + } + } +} + +void AddonsOptions_Impl::ReadMergeMenuData( const OUString& aMergeAddonInstructionBase, Sequence< Sequence< PropertyValue > >& rMergeMenu ) +{ + OUString aMergeMenuBaseNode( aMergeAddonInstructionBase+m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MENUITEMS ] ); + + Sequence< OUString > aSubMenuNodeNames = GetNodeNames( aMergeMenuBaseNode ); + aMergeMenuBaseNode += m_aPathDelimiter; + + // extend the node names to have full path strings + for ( OUString& rName : aSubMenuNodeNames ) + rName = aMergeMenuBaseNode + rName; + + ReadSubMenuEntries( aSubMenuNodeNames, rMergeMenu ); +} + +void AddonsOptions_Impl::ReadToolbarMergeInstructions( ToolbarMergingInstructions& rCachedToolbarMergingInstructions ) +{ + const OUString aToolbarMergeRootName( "AddonUI/OfficeToolbarMerging/" ); + + Sequence< OUString > aAddonMergeNodesSeq = GetNodeNames( aToolbarMergeRootName ); + sal_uInt32 nCount = aAddonMergeNodesSeq.getLength(); + + // Init the property value sequence + Sequence< OUString > aNodePropNames( 6 ); + + for ( sal_uInt32 i = 0; i < nCount; i++ ) + { + OUString aMergeAddonInstructions( aToolbarMergeRootName + aAddonMergeNodesSeq[i] ); + + Sequence< OUString > aAddonInstMergeNodesSeq = GetNodeNames( aMergeAddonInstructions ); + sal_uInt32 nCountAddons = aAddonInstMergeNodesSeq.getLength(); + + for ( sal_uInt32 j = 0; j < nCountAddons; j++ ) + { + OUStringBuffer aMergeAddonInstructionBase( aMergeAddonInstructions ); + aMergeAddonInstructionBase.append( m_aPathDelimiter ); + aMergeAddonInstructionBase.append( aAddonInstMergeNodesSeq[j] ); + aMergeAddonInstructionBase.append( m_aPathDelimiter ); + + // Create sequence for data access + OUStringBuffer aBuffer( aMergeAddonInstructionBase ); + aBuffer.append( m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_TOOLBAR ] ); + aNodePropNames[0] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append( m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_MERGEPOINT ] ); + aNodePropNames[1] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append( m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_MERGECOMMAND ] ); + aNodePropNames[2] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append( m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_MERGECOMMANDPARAMETER ] ); + aNodePropNames[3] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append( m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_MERGEFALLBACK ] ); + aNodePropNames[4] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append( m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_MERGECONTEXT ] ); + aNodePropNames[5] = aBuffer.makeStringAndClear(); + + Sequence< Any > aNodePropValues = GetProperties( aNodePropNames ); + + MergeToolbarInstruction aMergeToolbarInstruction; + aNodePropValues[0] >>= aMergeToolbarInstruction.aMergeToolbar; + aNodePropValues[1] >>= aMergeToolbarInstruction.aMergePoint; + aNodePropValues[2] >>= aMergeToolbarInstruction.aMergeCommand; + aNodePropValues[3] >>= aMergeToolbarInstruction.aMergeCommandParameter; + aNodePropValues[4] >>= aMergeToolbarInstruction.aMergeFallback; + aNodePropValues[5] >>= aMergeToolbarInstruction.aMergeContext; + + ReadMergeToolbarData( aMergeAddonInstructionBase.makeStringAndClear(), + aMergeToolbarInstruction.aMergeToolbarItems ); + + MergeToolbarInstructionContainer& rVector = rCachedToolbarMergingInstructions[ aMergeToolbarInstruction.aMergeToolbar ]; + rVector.push_back( aMergeToolbarInstruction ); + } + } +} + +bool AddonsOptions_Impl::ReadMergeToolbarData( const OUString& aMergeAddonInstructionBase, Sequence< Sequence< PropertyValue > >& rMergeToolbarItems ) +{ + OUString aMergeToolbarBaseNode = aMergeAddonInstructionBase + + m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_TOOLBARITEMS ]; + + return ReadToolBarItemSet( aMergeToolbarBaseNode, rMergeToolbarItems ); +} + +void AddonsOptions_Impl::ReadNotebookBarMergeInstructions( + NotebookBarMergingInstructions& rCachedNotebookBarMergingInstructions) +{ + const OUString aNotebookBarMergeRootName("AddonUI/OfficeNotebookBarMerging/"); + + Sequence aAddonMergeNodesSeq = GetNodeNames(aNotebookBarMergeRootName); + sal_uInt32 nCount = aAddonMergeNodesSeq.getLength(); + + // Init the property value sequence + Sequence aNodePropNames(6); + + for (sal_uInt32 i = 0; i < nCount; i++) + { + OUString aMergeAddonInstructions(aNotebookBarMergeRootName + aAddonMergeNodesSeq[i]); + + Sequence aAddonInstMergeNodesSeq = GetNodeNames(aMergeAddonInstructions); + sal_uInt32 nCountAddons = aAddonInstMergeNodesSeq.getLength(); + + for (sal_uInt32 j = 0; j < nCountAddons; j++) + { + OUStringBuffer aMergeAddonInstructionBase(aMergeAddonInstructions); + aMergeAddonInstructionBase.append(m_aPathDelimiter); + aMergeAddonInstructionBase.append(aAddonInstMergeNodesSeq[j]); + aMergeAddonInstructionBase.append(m_aPathDelimiter); + + // Create sequence for data access + OUStringBuffer aBuffer(aMergeAddonInstructionBase); + aBuffer.append(m_aPropMergeNotebookBarNames[OFFSET_MERGENOTEBOOKBAR_NOTEBOOKBAR]); + aNodePropNames[0] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append(m_aPropMergeNotebookBarNames[OFFSET_MERGENOTEBOOKBAR_MERGEPOINT]); + aNodePropNames[1] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append(m_aPropMergeNotebookBarNames[OFFSET_MERGENOTEBOOKBAR_MERGECOMMAND]); + aNodePropNames[2] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append( + m_aPropMergeNotebookBarNames[OFFSET_MERGENOTEBOOKBAR_MERGECOMMANDPARAMETER]); + aNodePropNames[3] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append(m_aPropMergeNotebookBarNames[OFFSET_MERGENOTEBOOKBAR_MERGEFALLBACK]); + aNodePropNames[4] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append(m_aPropMergeNotebookBarNames[OFFSET_MERGENOTEBOOKBAR_MERGECONTEXT]); + aNodePropNames[5] = aBuffer.makeStringAndClear(); + + Sequence aNodePropValues = GetProperties(aNodePropNames); + + MergeNotebookBarInstruction aMergeNotebookBarInstruction; + aNodePropValues[0] >>= aMergeNotebookBarInstruction.aMergeNotebookBar; + aNodePropValues[1] >>= aMergeNotebookBarInstruction.aMergePoint; + aNodePropValues[2] >>= aMergeNotebookBarInstruction.aMergeCommand; + aNodePropValues[3] >>= aMergeNotebookBarInstruction.aMergeCommandParameter; + aNodePropValues[4] >>= aMergeNotebookBarInstruction.aMergeFallback; + aNodePropValues[5] >>= aMergeNotebookBarInstruction.aMergeContext; + + ReadMergeNotebookBarData(aMergeAddonInstructionBase.makeStringAndClear(), + aMergeNotebookBarInstruction.aMergeNotebookBarItems); + + MergeNotebookBarInstructionContainer& rVector + = rCachedNotebookBarMergingInstructions[aMergeNotebookBarInstruction + .aMergeNotebookBar]; + rVector.push_back(aMergeNotebookBarInstruction); + } + } +} + +bool AddonsOptions_Impl::ReadMergeNotebookBarData( + const OUString& aMergeAddonInstructionBase, + Sequence>& rMergeNotebookBarItems) +{ + OUString aMergeNotebookBarBaseNode = aMergeAddonInstructionBase + + m_aPropMergeNotebookBarNames[OFFSET_MERGENOTEBOOKBAR_NOTEBOOKBARITEMS]; + + return ReadNotebookBarItemSet(aMergeNotebookBarBaseNode, rMergeNotebookBarItems); +} + +void AddonsOptions_Impl::ReadStatusbarMergeInstructions( MergeStatusbarInstructionContainer& aContainer ) +{ + const OUString aStatusbarMergeRootName( "AddonUI/OfficeStatusbarMerging/" ); + + Sequence< OUString > aAddonMergeNodesSeq = GetNodeNames( aStatusbarMergeRootName ); + sal_uInt32 nCount = aAddonMergeNodesSeq.getLength(); + + Sequence< OUString > aNodePropNames( 5 ); + + for ( sal_uInt32 i = 0; i < nCount; i++ ) + { + OUString aMergeAddonInstructions( aStatusbarMergeRootName + aAddonMergeNodesSeq[i] ); + + Sequence< OUString > aAddonInstMergeNodesSeq = GetNodeNames( aMergeAddonInstructions ); + sal_uInt32 nCountAddons = aAddonInstMergeNodesSeq.getLength(); + + for ( sal_uInt32 j = 0; j < nCountAddons; j++ ) + { + OUStringBuffer aMergeAddonInstructionBase( aMergeAddonInstructions ); + aMergeAddonInstructionBase.append( m_aPathDelimiter ); + aMergeAddonInstructionBase.append( aAddonInstMergeNodesSeq[j] ); + aMergeAddonInstructionBase.append( m_aPathDelimiter ); + + // Create sequence for data access + OUStringBuffer aBuffer( aMergeAddonInstructionBase ); + aBuffer.append( m_aPropMergeMenuNames[ OFFSET_MERGESTATUSBAR_MERGEPOINT ] ); + aNodePropNames[0] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append( m_aPropMergeMenuNames[ OFFSET_MERGESTATUSBAR_MERGECOMMAND ] ); + aNodePropNames[1] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append( m_aPropMergeMenuNames[ OFFSET_MERGESTATUSBAR_MERGECOMMANDPARAMETER ] ); + aNodePropNames[2] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append( m_aPropMergeMenuNames[ OFFSET_MERGESTATUSBAR_MERGEFALLBACK ] ); + aNodePropNames[3] = aBuffer.makeStringAndClear(); + + aBuffer = aMergeAddonInstructionBase; + aBuffer.append( m_aPropMergeMenuNames[ OFFSET_MERGESTATUSBAR_MERGECONTEXT ] ); + aNodePropNames[4] = aBuffer.makeStringAndClear(); + + Sequence< Any > aNodePropValues = GetProperties( aNodePropNames ); + + MergeStatusbarInstruction aMergeStatusbarInstruction; + aNodePropValues[0] >>= aMergeStatusbarInstruction.aMergePoint; + aNodePropValues[1] >>= aMergeStatusbarInstruction.aMergeCommand; + aNodePropValues[2] >>= aMergeStatusbarInstruction.aMergeCommandParameter; + // aNodePropValues[3] >>= aMergeStatusbarInstruction.aMergeFallback; + aNodePropValues[4] >>= aMergeStatusbarInstruction.aMergeContext; + + ReadMergeStatusbarData( aMergeAddonInstructionBase.makeStringAndClear(), + aMergeStatusbarInstruction.aMergeStatusbarItems ); + + aContainer.push_back( aMergeStatusbarInstruction ); + } + } +} + +bool AddonsOptions_Impl::ReadMergeStatusbarData( + const OUString& aMergeAddonInstructionBase, + Sequence< Sequence< PropertyValue > >& rMergeStatusbarItems ) +{ + sal_uInt32 nStatusbarItemCount = rMergeStatusbarItems.getLength(); + + OUString aMergeStatusbarBaseNode = aMergeAddonInstructionBase + + m_aPropMergeStatusbarNames[ OFFSET_MERGESTATUSBAR_STATUSBARITEMS ]; + + OUString aAddonStatusbarItemSetNode( aMergeStatusbarBaseNode + m_aPathDelimiter ); + Sequence< OUString > aAddonStatusbarItemSetNodeSeq = GetNodeNames( aMergeStatusbarBaseNode ); + + Sequence< PropertyValue > aStatusbarItem( PROPERTYCOUNT_STATUSBARITEM ); + aStatusbarItem[ OFFSET_STATUSBARITEM_URL ].Name = m_aPropNames[ INDEX_URL ]; + aStatusbarItem[ OFFSET_STATUSBARITEM_TITLE ].Name = m_aPropNames[ INDEX_TITLE ]; + aStatusbarItem[ OFFSET_STATUSBARITEM_CONTEXT ].Name = m_aPropNames[ INDEX_CONTEXT ]; + aStatusbarItem[ OFFSET_STATUSBARITEM_ALIGN ].Name = m_aPropNames[ INDEX_ALIGN ]; + aStatusbarItem[ OFFSET_STATUSBARITEM_AUTOSIZE ].Name = m_aPropNames[ INDEX_AUTOSIZE ]; + aStatusbarItem[ OFFSET_STATUSBARITEM_OWNERDRAW ].Name = m_aPropNames[ INDEX_OWNERDRAW ]; + aStatusbarItem[ OFFSET_STATUSBARITEM_MANDATORY ].Name = m_aPropNames[ INDEX_MANDATORY ]; + aStatusbarItem[ OFFSET_STATUSBARITEM_WIDTH ].Name = m_aPropNames[ INDEX_WIDTH ]; + + sal_uInt32 nCount = aAddonStatusbarItemSetNodeSeq.getLength(); + for ( sal_uInt32 n = 0; n < nCount; n++ ) + { + OUString aStatusbarItemNode( aAddonStatusbarItemSetNode + aAddonStatusbarItemSetNodeSeq[n] ); + + if ( ReadStatusBarItem( aStatusbarItemNode, aStatusbarItem ) ) + { + sal_uInt32 nAddonCount = rMergeStatusbarItems.getLength(); + rMergeStatusbarItems.realloc( nAddonCount+1 ); + rMergeStatusbarItems[nAddonCount] = aStatusbarItem; + } + } + + return ( o3tl::make_unsigned(rMergeStatusbarItems.getLength()) > nStatusbarItemCount ); +} + +bool AddonsOptions_Impl::ReadStatusBarItem( + const OUString& aStatusarItemNodeName, + Sequence< PropertyValue >& aStatusbarItem ) +{ + bool bResult( false ); + OUString aURL; + OUString aAddonStatusbarItemTreeNode( aStatusarItemNodeName + m_aPathDelimiter ); + + Sequence< Any > aStatusbarItemNodePropValues = GetProperties( GetPropertyNamesStatusbarItem( aAddonStatusbarItemTreeNode ) ); + + // Command URL is required + if (( aStatusbarItemNodePropValues[ OFFSET_STATUSBARITEM_URL ] >>= aURL ) && aURL.getLength() > 0 ) + { + aStatusbarItem[ OFFSET_STATUSBARITEM_URL ].Value <<= aURL; + aStatusbarItem[ OFFSET_STATUSBARITEM_TITLE ].Value = aStatusbarItemNodePropValues[ OFFSET_STATUSBARITEM_TITLE ]; + aStatusbarItem[ OFFSET_STATUSBARITEM_CONTEXT ].Value = aStatusbarItemNodePropValues[ OFFSET_STATUSBARITEM_CONTEXT ]; + aStatusbarItem[ OFFSET_STATUSBARITEM_ALIGN ].Value = aStatusbarItemNodePropValues[ OFFSET_STATUSBARITEM_ALIGN ]; + aStatusbarItem[ OFFSET_STATUSBARITEM_AUTOSIZE ].Value = aStatusbarItemNodePropValues[ OFFSET_STATUSBARITEM_AUTOSIZE ]; + aStatusbarItem[ OFFSET_STATUSBARITEM_OWNERDRAW ].Value = aStatusbarItemNodePropValues[ OFFSET_STATUSBARITEM_OWNERDRAW ]; + aStatusbarItem[ OFFSET_STATUSBARITEM_MANDATORY ].Value = aStatusbarItemNodePropValues[ OFFSET_STATUSBARITEM_MANDATORY ]; + + // Configuration uses hyper for long. Therefore transform into sal_Int32 + sal_Int64 nValue( 0 ); + aStatusbarItemNodePropValues[ OFFSET_STATUSBARITEM_WIDTH ] >>= nValue; + aStatusbarItem[ OFFSET_STATUSBARITEM_WIDTH ].Value <<= sal_Int32( nValue ); + + bResult = true; + } + + return bResult; +} + +bool AddonsOptions_Impl::ReadMenuItem( const OUString& aMenuNodeName, Sequence< PropertyValue >& aMenuItem, bool bIgnoreSubMenu ) +{ + bool bResult = false; + OUString aStrValue; + OUString aAddonMenuItemTreeNode( aMenuNodeName + m_aPathDelimiter ); + + Sequence< Any > aMenuItemNodePropValues = GetProperties( GetPropertyNamesMenuItem( aAddonMenuItemTreeNode ) ); + if (( aMenuItemNodePropValues[ OFFSET_MENUITEM_TITLE ] >>= aStrValue ) && !aStrValue.isEmpty() ) + { + aMenuItem[ OFFSET_MENUITEM_TITLE ].Value <<= aStrValue; + + OUString aRootSubMenuName( aAddonMenuItemTreeNode + m_aPropNames[ INDEX_SUBMENU ] ); + Sequence< OUString > aRootSubMenuNodeNames = GetNodeNames( aRootSubMenuName ); + if ( aRootSubMenuNodeNames.hasElements() && !bIgnoreSubMenu ) + { + // Set a unique prefixed Add-On popup menu URL so it can be identified later + OUString aPopupMenuURL = GeneratePrefixURL(); + OUString aPopupMenuImageId; + + aMenuItemNodePropValues[ OFFSET_MENUITEM_IMAGEIDENTIFIER ] >>= aPopupMenuImageId; + ReadAndAssociateImages( aPopupMenuURL, aPopupMenuImageId ); + + // A popup menu must have a title and can have a URL and ImageIdentifier + // Set the other property values to empty + aMenuItem[ OFFSET_MENUITEM_URL ].Value <<= aPopupMenuURL; + aMenuItem[ OFFSET_MENUITEM_TARGET ].Value <<= OUString(); + aMenuItem[ OFFSET_MENUITEM_IMAGEIDENTIFIER ].Value <<= aPopupMenuImageId; + aMenuItem[ OFFSET_MENUITEM_CONTEXT ].Value = aMenuItemNodePropValues[ OFFSET_MENUITEM_CONTEXT ]; + + // Continue to read the sub menu nodes + Sequence< Sequence< PropertyValue > > aSubMenuSeq; + OUString aSubMenuRootNodeName( aRootSubMenuName + m_aPathDelimiter ); + for ( OUString& rName : aRootSubMenuNodeNames ) + rName = aSubMenuRootNodeName + rName; + ReadSubMenuEntries( aRootSubMenuNodeNames, aSubMenuSeq ); + aMenuItem[ OFFSET_MENUITEM_SUBMENU ].Value <<= aSubMenuSeq; + bResult = true; + } + else if (( aMenuItemNodePropValues[ OFFSET_MENUITEM_URL ] >>= aStrValue ) && !aStrValue.isEmpty() ) + { + // A simple menu item => read the other properties; + OUString aMenuImageId; + + aMenuItemNodePropValues[ OFFSET_MENUITEM_IMAGEIDENTIFIER ] >>= aMenuImageId; + ReadAndAssociateImages( aStrValue, aMenuImageId ); + + aMenuItem[ OFFSET_MENUITEM_URL ].Value <<= aStrValue; + aMenuItem[ OFFSET_MENUITEM_TARGET ].Value = aMenuItemNodePropValues[ OFFSET_MENUITEM_TARGET ]; + aMenuItem[ OFFSET_MENUITEM_IMAGEIDENTIFIER ].Value <<= aMenuImageId; + aMenuItem[ OFFSET_MENUITEM_CONTEXT ].Value = aMenuItemNodePropValues[ OFFSET_MENUITEM_CONTEXT ]; + aMenuItem[ OFFSET_MENUITEM_SUBMENU ].Value <<= Sequence< Sequence< PropertyValue > >(); // Submenu set! + + bResult = true; + } + } + else if (( aMenuItemNodePropValues[ OFFSET_MENUITEM_URL ] >>= aStrValue ) && + aStrValue == SEPARATOR_URL ) + { + // Separator + aMenuItem[ OFFSET_MENUITEM_URL ].Value <<= aStrValue; + aMenuItem[ OFFSET_MENUITEM_TARGET ].Value <<= OUString(); + aMenuItem[ OFFSET_MENUITEM_IMAGEIDENTIFIER ].Value <<= OUString(); + aMenuItem[ OFFSET_MENUITEM_CONTEXT ].Value <<= OUString(); + aMenuItem[ OFFSET_MENUITEM_SUBMENU ].Value <<= Sequence< Sequence< PropertyValue > >(); // Submenu set! + bResult = true; + } + + return bResult; +} + +bool AddonsOptions_Impl::ReadPopupMenu( const OUString& aPopupMenuNodeName, Sequence< PropertyValue >& aPopupMenu ) +{ + bool bResult = false; + OUString aStrValue; + OUString aAddonPopupMenuTreeNode( aPopupMenuNodeName + m_aPathDelimiter ); + + Sequence< Any > aPopupMenuNodePropValues = GetProperties( GetPropertyNamesPopupMenu( aAddonPopupMenuTreeNode ) ); + if (( aPopupMenuNodePropValues[ OFFSET_POPUPMENU_TITLE ] >>= aStrValue ) && + !aStrValue.isEmpty() ) + { + aPopupMenu[ OFFSET_POPUPMENU_TITLE ].Value <<= aStrValue; + + OUString aRootSubMenuName( aAddonPopupMenuTreeNode + m_aPropNames[ INDEX_SUBMENU ] ); + Sequence< OUString > aRootSubMenuNodeNames = GetNodeNames( aRootSubMenuName ); + if ( aRootSubMenuNodeNames.hasElements() ) + { + // A top-level popup menu needs a title + // Set a unique prefixed Add-On popup menu URL so it can be identified later + OUString aPopupMenuURL = GeneratePrefixURL(); + + aPopupMenu[ OFFSET_POPUPMENU_URL ].Value <<= aPopupMenuURL; + aPopupMenu[ OFFSET_POPUPMENU_CONTEXT ].Value = aPopupMenuNodePropValues[ OFFSET_POPUPMENU_CONTEXT ]; + + // Continue to read the sub menu nodes + Sequence< Sequence< PropertyValue > > aSubMenuSeq; + OUString aSubMenuRootNodeName( aRootSubMenuName + m_aPathDelimiter ); + for ( OUString& rName : aRootSubMenuNodeNames ) + rName = aSubMenuRootNodeName + rName; + ReadSubMenuEntries( aRootSubMenuNodeNames, aSubMenuSeq ); + aPopupMenu[ OFFSET_POPUPMENU_SUBMENU ].Value <<= aSubMenuSeq; + bResult = true; + } + } + + return bResult; +} + +void AddonsOptions_Impl::AppendPopupMenu( Sequence< PropertyValue >& rTargetPopupMenu, const Sequence< PropertyValue >& rSourcePopupMenu ) +{ + Sequence< Sequence< PropertyValue > > aTargetSubMenuSeq; + Sequence< Sequence< PropertyValue > > aSourceSubMenuSeq; + + if (( rTargetPopupMenu[ OFFSET_POPUPMENU_SUBMENU ].Value >>= aTargetSubMenuSeq ) && + ( rSourcePopupMenu[ OFFSET_POPUPMENU_SUBMENU ].Value >>= aSourceSubMenuSeq )) + { + sal_uInt32 nIndex = aTargetSubMenuSeq.getLength(); + aTargetSubMenuSeq.realloc( nIndex + aSourceSubMenuSeq.getLength() ); + for ( Sequence const & rSeq : std::as_const(aSourceSubMenuSeq) ) + aTargetSubMenuSeq[nIndex++] = rSeq; + rTargetPopupMenu[ OFFSET_POPUPMENU_SUBMENU ].Value <<= aTargetSubMenuSeq; + } +} + +bool AddonsOptions_Impl::ReadToolBarItem( const OUString& aToolBarItemNodeName, Sequence< PropertyValue >& aToolBarItem ) +{ + bool bResult = false; + OUString aTitle; + OUString aURL; + OUString aAddonToolBarItemTreeNode( aToolBarItemNodeName + m_aPathDelimiter ); + + Sequence< Any > aToolBarItemNodePropValues = GetProperties( GetPropertyNamesToolBarItem( aAddonToolBarItemTreeNode ) ); + + // A toolbar item must have a command URL + if (( aToolBarItemNodePropValues[ OFFSET_TOOLBARITEM_URL ] >>= aURL ) && !aURL.isEmpty() ) + { + if ( aURL == SEPARATOR_URL ) + { + // A separator toolbar item only needs a URL + aToolBarItem[ OFFSET_TOOLBARITEM_URL ].Value <<= aURL; + aToolBarItem[ OFFSET_TOOLBARITEM_TITLE ].Value <<= OUString(); + aToolBarItem[ OFFSET_TOOLBARITEM_TARGET ].Value <<= OUString(); + aToolBarItem[ OFFSET_TOOLBARITEM_IMAGEIDENTIFIER ].Value <<= OUString(); + aToolBarItem[ OFFSET_TOOLBARITEM_CONTEXT ].Value <<= OUString(); + aToolBarItem[ OFFSET_TOOLBARITEM_CONTROLTYPE ].Value <<= OUString(); + aToolBarItem[ OFFSET_TOOLBARITEM_WIDTH ].Value <<= sal_Int32( 0 ); + + bResult = true; + } + else if (( aToolBarItemNodePropValues[ OFFSET_TOOLBARITEM_TITLE ] >>= aTitle ) && !aTitle.isEmpty() ) + { + // A normal toolbar item must also have title => read the other properties; + OUString aImageId; + + // Try to map a user-defined image URL to our internal private image URL + aToolBarItemNodePropValues[ OFFSET_TOOLBARITEM_IMAGEIDENTIFIER ] >>= aImageId; + ReadAndAssociateImages( aURL, aImageId ); + + aToolBarItem[ OFFSET_TOOLBARITEM_URL ].Value <<= aURL; + aToolBarItem[ OFFSET_TOOLBARITEM_TITLE ].Value <<= aTitle; + aToolBarItem[ OFFSET_TOOLBARITEM_TARGET ].Value = aToolBarItemNodePropValues[ OFFSET_TOOLBARITEM_TARGET ]; + aToolBarItem[ OFFSET_TOOLBARITEM_IMAGEIDENTIFIER ].Value <<= aImageId; + aToolBarItem[ OFFSET_TOOLBARITEM_CONTEXT ].Value = aToolBarItemNodePropValues[ OFFSET_TOOLBARITEM_CONTEXT ]; + aToolBarItem[ OFFSET_TOOLBARITEM_CONTROLTYPE ].Value = aToolBarItemNodePropValues[ OFFSET_TOOLBARITEM_CONTROLTYPE ]; + + // Configuration uses hyper for long. Therefore transform into sal_Int32 + sal_Int64 nValue( 0 ); + aToolBarItemNodePropValues[ OFFSET_TOOLBARITEM_WIDTH ] >>= nValue; + aToolBarItem[ OFFSET_TOOLBARITEM_WIDTH ].Value <<= sal_Int32( nValue ); + + bResult = true; + } + } + + return bResult; +} + +bool AddonsOptions_Impl::ReadNotebookBarItem( const OUString& aNotebookBarItemNodeName, Sequence< PropertyValue >& aNotebookBarItem ) +{ + bool bResult = false; + OUString aTitle; + OUString aURL; + OUString aAddonNotebookBarItemTreeNode( aNotebookBarItemNodeName + m_aPathDelimiter ); + + Sequence< Any > aNotebookBarItemNodePropValues = GetProperties( GetPropertyNamesNotebookBarItem( aAddonNotebookBarItemTreeNode ) ); + + // A toolbar item must have a command URL + if (( aNotebookBarItemNodePropValues[ OFFSET_NOTEBOOKBARITEM_URL ] >>= aURL ) && !aURL.isEmpty() ) + { + if ( aURL == SEPARATOR_URL ) + { + // A separator toolbar item only needs a URL + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_URL ].Value <<= aURL; + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_TITLE ].Value <<= OUString(); + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_TARGET ].Value <<= OUString(); + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_IMAGEIDENTIFIER ].Value <<= OUString(); + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_CONTEXT ].Value <<= OUString(); + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_CONTROLTYPE ].Value <<= OUString(); + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_WIDTH ].Value <<= sal_Int32( 0 ); + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_STYLE ].Value <<= OUString(); + + bResult = true; + } + else if (( aNotebookBarItemNodePropValues[ OFFSET_NOTEBOOKBARITEM_TITLE ] >>= aTitle ) && !aTitle.isEmpty() ) + { + // A normal toolbar item must also have title => read the other properties; + OUString aImageId; + + // Try to map a user-defined image URL to our internal private image URL + aNotebookBarItemNodePropValues[ OFFSET_NOTEBOOKBARITEM_IMAGEIDENTIFIER ] >>= aImageId; + ReadAndAssociateImages( aURL, aImageId ); + + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_URL ].Value <<= aURL; + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_TITLE ].Value <<= aTitle; + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_TARGET ].Value = aNotebookBarItemNodePropValues[ OFFSET_NOTEBOOKBARITEM_TARGET ]; + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_IMAGEIDENTIFIER ].Value <<= aImageId; + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_CONTEXT ].Value = aNotebookBarItemNodePropValues[ OFFSET_NOTEBOOKBARITEM_CONTEXT ]; + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_CONTROLTYPE ].Value = aNotebookBarItemNodePropValues[ OFFSET_NOTEBOOKBARITEM_CONTROLTYPE ]; + + // Configuration uses hyper for long. Therefore transform into sal_Int32 + sal_Int64 nValue( 0 ); + aNotebookBarItemNodePropValues[ OFFSET_NOTEBOOKBARITEM_WIDTH ] >>= nValue; + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_WIDTH ].Value <<= sal_Int32( nValue ); + aNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_STYLE ].Value = aNotebookBarItemNodePropValues[ OFFSET_NOTEBOOKBARITEM_STYLE ]; + + bResult = true; + } + } + + return bResult; +} + +void AddonsOptions_Impl::ReadSubMenuEntries( const Sequence< OUString >& aSubMenuNodeNames, Sequence< Sequence< PropertyValue > >& rSubMenuSeq ) +{ + Sequence< PropertyValue > aMenuItem( PROPERTYCOUNT_MENUITEM ); + + // Init the property value sequence + aMenuItem[ OFFSET_MENUITEM_URL ].Name = PROPERTYNAME_URL; + aMenuItem[ OFFSET_MENUITEM_TITLE ].Name = PROPERTYNAME_TITLE; + aMenuItem[ OFFSET_MENUITEM_TARGET ].Name = PROPERTYNAME_TARGET; + aMenuItem[ OFFSET_MENUITEM_IMAGEIDENTIFIER ].Name = PROPERTYNAME_IMAGEIDENTIFIER; + aMenuItem[ OFFSET_MENUITEM_CONTEXT ].Name = PROPERTYNAME_CONTEXT; + aMenuItem[ OFFSET_MENUITEM_SUBMENU ].Name = PROPERTYNAME_SUBMENU; // Submenu set! + + sal_uInt32 nIndex = 0; + sal_uInt32 nCount = aSubMenuNodeNames.getLength(); + for ( sal_uInt32 n = 0; n < nCount; n++ ) + { + if ( ReadMenuItem( aSubMenuNodeNames[n], aMenuItem )) + { + sal_uInt32 nSubMenuCount = rSubMenuSeq.getLength() + 1; + rSubMenuSeq.realloc( nSubMenuCount ); + rSubMenuSeq[nIndex++] = aMenuItem; + } + } +} + +bool AddonsOptions_Impl::HasAssociatedImages( const OUString& aURL ) +{ + // FIXME: potentially this is not so useful in a world of delayed image loading + ImageManager::const_iterator pIter = m_aImageManager.find( aURL ); + return ( pIter != m_aImageManager.end() ); +} + +void AddonsOptions_Impl::SubstituteVariables( OUString& aURL ) +{ + aURL = comphelper::getExpandedUri( + comphelper::getProcessComponentContext(), aURL); +} + +Image AddonsOptions_Impl::ReadImageFromURL(const OUString& aImageURL) +{ + Image aImage; + + std::unique_ptr pStream = UcbStreamHelper::CreateStream( aImageURL, StreamMode::STD_READ ); + if ( pStream && ( pStream->GetErrorCode() == ERRCODE_NONE )) + { + // Use graphic class to also support more graphic formats (bmp,png,...) + Graphic aGraphic; + + GraphicFilter& rGF = GraphicFilter::GetGraphicFilter(); + rGF.ImportGraphic( aGraphic, OUString(), *pStream ); + + BitmapEx aBitmapEx = aGraphic.GetBitmapEx(); + + Size aBmpSize = aBitmapEx.GetSizePixel(); + if ( !aBmpSize.IsEmpty() ) + { + // Support non-transparent bitmaps to be downward compatible with OOo 1.1.x addons + if( !aBitmapEx.IsTransparent() ) + aBitmapEx = BitmapEx( aBitmapEx.GetBitmap(), COL_LIGHTMAGENTA ); + + aImage = Image(aBitmapEx); + } + } + + return aImage; +} + +void AddonsOptions_Impl::ReadAndAssociateImages( const OUString& aURL, const OUString& aImageId ) +{ + if ( aImageId.isEmpty() ) + return; + + ImageEntry aImageEntry; + OUString aImageURL( aImageId ); + + SubstituteVariables( aImageURL ); + + // Loop to create the two possible image names and try to read the bitmap files + static const char* aExtArray[] = { "_16", "_26" }; + for ( size_t i = 0; i < SAL_N_ELEMENTS(aExtArray); i++ ) + { + OUStringBuffer aFileURL( aImageURL ); + aFileURL.appendAscii( aExtArray[i] ); + aFileURL.append( ".bmp" ); + + aImageEntry.addImage( !i ? IMGSIZE_SMALL : IMGSIZE_BIG, + Image(), aFileURL.makeStringAndClear() ); + } + + m_aImageManager.emplace( aURL, aImageEntry ); +} + +std::unique_ptr AddonsOptions_Impl::ReadImageData( const OUString& aImagesNodeName ) +{ + Sequence< OUString > aImageDataNodeNames = GetPropertyNamesImages( aImagesNodeName ); + Sequence< Any > aPropertyData; + Sequence< sal_Int8 > aImageDataSeq; + OUString aImageURL; + + std::unique_ptr pEntry; + + // It is possible to use both forms (embedded image data and URLs to external bitmap files) at the + // same time. Embedded image data has a higher priority. + aPropertyData = GetProperties( aImageDataNodeNames ); + for ( int i = 0; i < PROPERTYCOUNT_IMAGES; i++ ) + { + if ( i < PROPERTYCOUNT_EMBEDDED_IMAGES ) + { + // Extract image data from the embedded hex binary sequence + Image aImage; + if (( aPropertyData[i] >>= aImageDataSeq ) && + aImageDataSeq.hasElements() && + ( CreateImageFromSequence( aImage, aImageDataSeq ) ) ) + { + if ( !pEntry ) + pEntry.reset(new ImageEntry); + pEntry->addImage(i == OFFSET_IMAGES_SMALL ? IMGSIZE_SMALL : IMGSIZE_BIG, aImage, ""); + } + } + else + { + if(!pEntry) + pEntry.reset(new ImageEntry()); + + // Retrieve image data from an external bitmap file. Make sure that embedded image data + // has a higher priority. + aPropertyData[i] >>= aImageURL; + + SubstituteVariables( aImageURL ); + + pEntry->addImage(IMGSIZE_BIG, Image(), aImageURL); + } + } + + return pEntry; +} + +bool AddonsOptions_Impl::CreateImageFromSequence( Image& rImage, Sequence< sal_Int8 >& rBitmapDataSeq ) const +{ + bool bResult = false; + + if ( rBitmapDataSeq.hasElements() ) + { + SvMemoryStream aMemStream( rBitmapDataSeq.getArray(), rBitmapDataSeq.getLength(), StreamMode::STD_READ ); + BitmapEx aBitmapEx; + + ReadDIBBitmapEx(aBitmapEx, aMemStream); + + if( !aBitmapEx.IsTransparent() ) + { + // Support non-transparent bitmaps to be downward compatible with OOo 1.1.x addons + aBitmapEx = BitmapEx( aBitmapEx.GetBitmap(), COL_LIGHTMAGENTA ); + } + + rImage = Image( aBitmapEx ); + bResult = true; + } + + return bResult; +} + +Sequence< OUString > AddonsOptions_Impl::GetPropertyNamesMenuItem( const OUString& aPropertyRootNode ) const +{ + Sequence< OUString > lResult( PROPERTYCOUNT_MENUITEM ); + + // Create property names dependent from the root node name + lResult[OFFSET_MENUITEM_URL] = aPropertyRootNode + m_aPropNames[ INDEX_URL ]; + lResult[OFFSET_MENUITEM_TITLE] = aPropertyRootNode + m_aPropNames[ INDEX_TITLE ]; + lResult[OFFSET_MENUITEM_IMAGEIDENTIFIER] = aPropertyRootNode + m_aPropNames[ INDEX_IMAGEIDENTIFIER ]; + lResult[OFFSET_MENUITEM_TARGET] = aPropertyRootNode + m_aPropNames[ INDEX_TARGET ]; + lResult[OFFSET_MENUITEM_CONTEXT] = aPropertyRootNode + m_aPropNames[ INDEX_CONTEXT ]; + lResult[OFFSET_MENUITEM_SUBMENU] = aPropertyRootNode + m_aPropNames[ INDEX_SUBMENU ]; + + return lResult; +} + +Sequence< OUString > AddonsOptions_Impl::GetPropertyNamesPopupMenu( const OUString& aPropertyRootNode ) const +{ + // The URL is automatically set and not read from the configuration. + Sequence< OUString > lResult( PROPERTYCOUNT_POPUPMENU-1 ); + + // Create property names dependent from the root node name + lResult[OFFSET_POPUPMENU_TITLE] = aPropertyRootNode + m_aPropNames[ INDEX_TITLE ]; + lResult[OFFSET_POPUPMENU_CONTEXT] = aPropertyRootNode + m_aPropNames[ INDEX_CONTEXT ]; + lResult[OFFSET_POPUPMENU_SUBMENU] = aPropertyRootNode + m_aPropNames[ INDEX_SUBMENU ]; + + return lResult; +} + +Sequence< OUString > AddonsOptions_Impl::GetPropertyNamesToolBarItem( const OUString& aPropertyRootNode ) const +{ + Sequence< OUString > lResult( PROPERTYCOUNT_TOOLBARITEM ); + + // Create property names dependent from the root node name + lResult[0] = aPropertyRootNode + m_aPropNames[ INDEX_URL ]; + lResult[1] = aPropertyRootNode + m_aPropNames[ INDEX_TITLE ]; + lResult[2] = aPropertyRootNode + m_aPropNames[ INDEX_IMAGEIDENTIFIER]; + lResult[3] = aPropertyRootNode + m_aPropNames[ INDEX_TARGET ]; + lResult[4] = aPropertyRootNode + m_aPropNames[ INDEX_CONTEXT ]; + lResult[5] = aPropertyRootNode + m_aPropNames[ INDEX_CONTROLTYPE ]; + lResult[6] = aPropertyRootNode + m_aPropNames[ INDEX_WIDTH ]; + + return lResult; +} + +Sequence< OUString > AddonsOptions_Impl::GetPropertyNamesNotebookBarItem( const OUString& aPropertyRootNode ) const +{ + Sequence< OUString > lResult( PROPERTYCOUNT_NOTEBOOKBARITEM ); + + // Create property names dependent from the root node name + lResult[0] = aPropertyRootNode + m_aPropNames[ INDEX_URL ]; + lResult[1] = aPropertyRootNode + m_aPropNames[ INDEX_TITLE ]; + lResult[2] = aPropertyRootNode + m_aPropNames[ INDEX_IMAGEIDENTIFIER]; + lResult[3] = aPropertyRootNode + m_aPropNames[ INDEX_TARGET ]; + lResult[4] = aPropertyRootNode + m_aPropNames[ INDEX_CONTEXT ]; + lResult[5] = aPropertyRootNode + m_aPropNames[ INDEX_CONTROLTYPE ]; + lResult[6] = aPropertyRootNode + m_aPropNames[ INDEX_WIDTH ]; + lResult[7] = aPropertyRootNode + m_aPropNames[ INDEX_STYLE ]; + + return lResult; +} + +Sequence< OUString > AddonsOptions_Impl::GetPropertyNamesStatusbarItem( + const OUString& aPropertyRootNode ) const +{ + Sequence< OUString > lResult( PROPERTYCOUNT_STATUSBARITEM ); + + lResult[0] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_URL ] ); + lResult[1] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_TITLE ] ); + lResult[2] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_CONTEXT ] ); + lResult[3] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_ALIGN ] ); + lResult[4] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_AUTOSIZE ] ); + lResult[5] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_OWNERDRAW ] ); + lResult[6] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_MANDATORY ] ); + lResult[7] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_WIDTH ] ); + + return lResult; +} + +Sequence< OUString > AddonsOptions_Impl::GetPropertyNamesImages( const OUString& aPropertyRootNode ) const +{ + Sequence< OUString > lResult( PROPERTYCOUNT_IMAGES ); + + // Create property names dependent from the root node name + lResult[0] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_SMALL ]; + lResult[1] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_BIG ]; + lResult[2] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_SMALLHC ]; + lResult[3] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_BIGHC ]; + lResult[4] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_SMALL_URL ]; + lResult[5] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_BIG_URL ]; + lResult[6] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_SMALLHC_URL]; + lResult[7] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_BIGHC_URL ]; + + return lResult; +} + +namespace{ + //global + std::weak_ptr g_pAddonsOptions; +} + +AddonsOptions::AddonsOptions() +{ + // Global access, must be guarded (multithreading!). + MutexGuard aGuard( GetOwnStaticMutex() ); + + m_pImpl = g_pAddonsOptions.lock(); + if( !m_pImpl ) + { + m_pImpl = std::make_shared(); + g_pAddonsOptions = m_pImpl; + } +} + +AddonsOptions::~AddonsOptions() +{ + // Global access, must be guarded (multithreading!) + MutexGuard aGuard( GetOwnStaticMutex() ); + + m_pImpl.reset(); +} + +// public method + +bool AddonsOptions::HasAddonsMenu() const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->HasAddonsMenu(); +} + +// public method + +sal_Int32 AddonsOptions::GetAddonsToolBarCount() const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetAddonsToolBarCount(); +} + +// public method + +sal_Int32 AddonsOptions::GetAddonsNotebookBarCount() const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetAddonsNotebookBarCount(); +} + +// public method + +const Sequence< Sequence< PropertyValue > >& AddonsOptions::GetAddonsMenu() const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetAddonsMenu(); +} + +// public method + +const Sequence< Sequence< PropertyValue > >& AddonsOptions::GetAddonsMenuBarPart() const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetAddonsMenuBarPart(); +} + +// public method + +const Sequence< Sequence< PropertyValue > >& AddonsOptions::GetAddonsToolBarPart( sal_uInt32 nIndex ) const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetAddonsToolBarPart( nIndex ); +} + +// public method + +const Sequence< Sequence< PropertyValue > >& AddonsOptions::GetAddonsNotebookBarPart( sal_uInt32 nIndex ) const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetAddonsNotebookBarPart( nIndex ); +} + +// public method + +OUString AddonsOptions::GetAddonsToolbarResourceName( sal_uInt32 nIndex ) const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetAddonsToolbarResourceName( nIndex ); +} + +// public method + +OUString AddonsOptions::GetAddonsNotebookBarResourceName( sal_uInt32 nIndex ) const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetAddonsNotebookBarResourceName( nIndex ); +} + +// public method + +const Sequence< Sequence< PropertyValue > >& AddonsOptions::GetAddonsHelpMenu() const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetAddonsHelpMenu(); +} + +// public method + +const MergeMenuInstructionContainer& AddonsOptions::GetMergeMenuInstructions() const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetMergeMenuInstructions(); +} + +// public method + +bool AddonsOptions::GetMergeToolbarInstructions( + const OUString& rToolbarName, + MergeToolbarInstructionContainer& rToolbarInstructions ) const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetMergeToolbarInstructions( + rToolbarName, rToolbarInstructions ); +} + +// public method + +bool AddonsOptions::GetMergeNotebookBarInstructions( + const OUString& rNotebookBarName, + MergeNotebookBarInstructionContainer& rNotebookBarInstructions ) const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetMergeNotebookBarInstructions( + rNotebookBarName, rNotebookBarInstructions ); +} + +//public method + +const MergeStatusbarInstructionContainer& AddonsOptions::GetMergeStatusbarInstructions() const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetMergeStatusbarInstructions(); +} + +// public method + +Image AddonsOptions::GetImageFromURL( const OUString& aURL, bool bBig, bool bNoScale ) const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetImageFromURL( aURL, bBig, bNoScale ); +} + +// public method + +Image AddonsOptions::GetImageFromURL( const OUString& aURL, bool bBig ) const +{ + return GetImageFromURL( aURL, bBig, false ); +} + +Mutex& AddonsOptions::GetOwnStaticMutex() +{ + // Create static mutex variable. + static Mutex ourMutex; + + return ourMutex; +} + +IMPL_LINK_NOARG(AddonsOptions_Impl, NotifyEvent, void*, void) +{ + MutexGuard aGuard(AddonsOptions::GetOwnStaticMutex()); + ReadConfigurationData(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/classes/framelistanalyzer.cxx b/framework/source/fwe/classes/framelistanalyzer.cxx new file mode 100644 index 000000000..55edf3147 --- /dev/null +++ b/framework/source/fwe/classes/framelistanalyzer.cxx @@ -0,0 +1,260 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace framework{ + +FrameListAnalyzer::FrameListAnalyzer( const css::uno::Reference< css::frame::XFramesSupplier >& xSupplier , + const css::uno::Reference< css::frame::XFrame >& xReferenceFrame , + FrameAnalyzerFlags eDetectMode ) + : m_xSupplier (xSupplier ) + , m_xReferenceFrame(xReferenceFrame) + , m_eDetectMode (eDetectMode ) +{ + impl_analyze(); +} + +FrameListAnalyzer::~FrameListAnalyzer() +{ +} + +/** returns an analyzed list of all currently opened (top!) frames inside the desktop tree. + + We try to get a snapshot of all opened frames, which are part of the desktop frame container. + Of course we can't access frames, which stands outside of this tree. + But it's necessary to collect top frames here only. Otherwise we interpret closing of last + frame wrong. Further we analyze this list and split into different parts. + E.g. for "CloseDoc" we must know, which frames of the given list refer to the same model. + These frames must be closed then. But all other frames must be untouched. + In case the request was "CloseWin" these split lists can be used too, to decide if the last window + or document was closed. Then we have to initialize the backing window... + Last but not least we must know something about our special help frame. It must be handled + separately. And last but not least - the backing component frame must be detected too. +*/ + +void FrameListAnalyzer::impl_analyze() +{ + // reset all members to get a consistent state + m_bReferenceIsHidden = false; + m_bReferenceIsHelp = false; + m_bReferenceIsBacking = false; + m_xHelp.clear(); + m_xBackingComponent.clear(); + + // try to get the task container by using the given supplier + css::uno::Reference< css::container::XIndexAccess > xFrameContainer = m_xSupplier->getFrames(); + + // All return list get an initial size to include all possible frames. + // They will be packed at the end of this method ... using the actual step positions then. + sal_Int32 nVisibleStep = 0; + sal_Int32 nHiddenStep = 0; + sal_Int32 nModelStep = 0; + sal_Int32 nCount = xFrameContainer->getCount(); + + m_lOtherVisibleFrames.resize(nCount); + m_lOtherHiddenFrames.resize(nCount); + m_lModelFrames.resize(nCount); + + // ask for the model of the given reference frame. + // It must be compared with the model of every frame of the container + // to sort it into the list of frames with the same model. + // Suppress this step, if right detect mode isn't set. + css::uno::Reference< css::frame::XModel > xReferenceModel; + if (m_eDetectMode & FrameAnalyzerFlags::Model) + { + css::uno::Reference< css::frame::XController > xReferenceController; + if (m_xReferenceFrame.is()) + xReferenceController = m_xReferenceFrame->getController(); + if (xReferenceController.is()) + xReferenceModel = xReferenceController->getModel(); + } + + // check, if the reference frame is in hidden mode. + // But look, if this analyze step is really needed. + css::uno::Reference< css::beans::XPropertySet > xSet(m_xReferenceFrame, css::uno::UNO_QUERY); + if ( (m_eDetectMode & FrameAnalyzerFlags::Hidden) && xSet.is() ) + { + xSet->getPropertyValue(FRAME_PROPNAME_ASCII_ISHIDDEN) >>= m_bReferenceIsHidden; + } + + // check, if the reference frame includes the backing component. + // But look, if this analyze step is really needed. + if ((m_eDetectMode & FrameAnalyzerFlags::BackingComponent) && m_xReferenceFrame.is() ) + { + try + { + css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); + css::uno::Reference< css::frame::XModuleManager2 > xModuleMgr = css::frame::ModuleManager::create(xContext); + OUString sModule = xModuleMgr->identify(m_xReferenceFrame); + m_bReferenceIsBacking = sModule == "com.sun.star.frame.StartModule"; + } + catch(const css::frame::UnknownModuleException&) + { + } + catch(const css::uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("fwk"); + } + } + + // check, if the reference frame includes the help module. + // But look, if this analyze step is really needed. + if ( + (m_eDetectMode & FrameAnalyzerFlags::Help) && + (m_xReferenceFrame.is() ) && + (m_xReferenceFrame->getName() == SPECIALTARGET_HELPTASK) + ) + { + m_bReferenceIsHelp = true; + } + + try + { + // Step over all frames of the desktop frame container and analyze it. + for (sal_Int32 i=0; i xFrame; + if ( + !(xFrameContainer->getByIndex(i) >>= xFrame) || + !(xFrame.is() ) || + (xFrame==m_xReferenceFrame ) + ) + continue; + + if ( + (m_eDetectMode & FrameAnalyzerFlags::Zombie) && + ( + (!xFrame->getContainerWindow().is()) || + (!xFrame->getComponentWindow().is()) + ) + ) + { + SAL_INFO("fwk", "FrameListAnalyzer::impl_analyze(): ZOMBIE!"); + } + + // a) Is it the special help task? + // Return it separated from any return list. + if ( + (m_eDetectMode & FrameAnalyzerFlags::Help) && + (xFrame->getName()==SPECIALTARGET_HELPTASK) + ) + { + m_xHelp = xFrame; + continue; + } + + // b) Or is includes this task the special backing component? + // Return it separated from any return list. + // But check if the reference task itself is the backing frame. + // Our user must know it to decide right. + if (m_eDetectMode & FrameAnalyzerFlags::BackingComponent) + { + try + { + css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); + css::uno::Reference< css::frame::XModuleManager2 > xModuleMgr = css::frame::ModuleManager::create(xContext); + OUString sModule = xModuleMgr->identify(xFrame); + if (sModule == "com.sun.star.frame.StartModule") + { + m_xBackingComponent = xFrame; + continue; + } + } + catch (const css::uno::Exception&) + { + } + } + + // c) Or is it the a task, which uses the specified model? + // Add it to the list of "model frames". + if (m_eDetectMode & FrameAnalyzerFlags::Model) + { + css::uno::Reference< css::frame::XController > xController = xFrame->getController(); + css::uno::Reference< css::frame::XModel > xModel; + if (xController.is()) + xModel = xController->getModel(); + if (xModel==xReferenceModel) + { + m_lModelFrames[nModelStep] = xFrame; + ++nModelStep; + continue; + } + } + + // d) Or is it the a task, which use another or no model at all? + // Add it to the list of "other frames". But look for its + // visible state ... if it's allowed to do so. + + bool bHidden = false; + if (m_eDetectMode & FrameAnalyzerFlags::Hidden) + { + xSet.set(xFrame, css::uno::UNO_QUERY); + if (xSet.is()) + { + xSet->getPropertyValue(FRAME_PROPNAME_ASCII_ISHIDDEN) >>= bHidden; + } + } + + if (bHidden) + { + m_lOtherHiddenFrames[nHiddenStep] = xFrame; + ++nHiddenStep; + } + else + { + m_lOtherVisibleFrames[nVisibleStep] = xFrame; + ++nVisibleStep; + } + } + } + catch (const css::lang::IndexOutOfBoundsException&) + { + // stop copying if index seems to be wrong. + // This interface can't really guarantee its count for multithreaded + // environments. So it can occur! + } + + // Pack both lists by using the actual step positions. + // All empty or ignorable items should exist at the end of these lists + // behind the position pointers. So they will be removed by a reallocation. + m_lOtherVisibleFrames.resize(nVisibleStep); + m_lOtherHiddenFrames.resize(nHiddenStep); + m_lModelFrames.resize(nModelStep); +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/classes/fwkresid.cxx b/framework/source/fwe/classes/fwkresid.cxx new file mode 100644 index 000000000..b6dcaecff --- /dev/null +++ b/framework/source/fwe/classes/fwkresid.cxx @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 +#include + +OUString FwkResId(const char* pId) +{ + return Translate::get(pId, Translate::Create("fwk")); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/classes/imagewrapper.cxx b/framework/source/fwe/classes/imagewrapper.cxx new file mode 100644 index 000000000..b95bbbc34 --- /dev/null +++ b/framework/source/fwe/classes/imagewrapper.cxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 +#include +#include +#include +#include +#include + +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; + +namespace framework +{ + +static Sequence< sal_Int8 > const & impl_getStaticIdentifier() +{ + static const sal_uInt8 pGUID[16] = { 0x46, 0xAD, 0x69, 0xFB, 0xA7, 0xBE, 0x44, 0x83, 0xB2, 0xA7, 0xB3, 0xEC, 0x59, 0x4A, 0xB7, 0x00 }; + static css::uno::Sequence< sal_Int8 > seqID(reinterpret_cast(pGUID), 16); + return seqID; +} + +ImageWrapper::ImageWrapper( const Image& aImage ) : m_aImage( aImage ) +{ +} + +ImageWrapper::~ImageWrapper() +{ +} + +Sequence< sal_Int8 > const & ImageWrapper::GetUnoTunnelId() +{ + return impl_getStaticIdentifier(); +} + +// XBitmap +css::awt::Size SAL_CALL ImageWrapper::getSize() +{ + SolarMutexGuard aGuard; + + BitmapEx aBitmapEx( m_aImage.GetBitmapEx() ); + Size aBitmapSize( aBitmapEx.GetSizePixel() ); + + return css::awt::Size( aBitmapSize.Width(), aBitmapSize.Height() ); +} + +Sequence< sal_Int8 > SAL_CALL ImageWrapper::getDIB() +{ + SolarMutexGuard aGuard; + + SvMemoryStream aMem; + WriteDIB(m_aImage.GetBitmapEx().GetBitmap(), aMem, false, true); + return Sequence< sal_Int8 >( static_cast(aMem.GetData()), aMem.Tell() ); +} + +Sequence< sal_Int8 > SAL_CALL ImageWrapper::getMaskDIB() +{ + SolarMutexGuard aGuard; + + return vcl::bitmap::GetMaskDIB(m_aImage.GetBitmapEx()); +} + +// XUnoTunnel +sal_Int64 SAL_CALL ImageWrapper::getSomething( const Sequence< sal_Int8 >& aIdentifier ) +{ + if ( aIdentifier == impl_getStaticIdentifier() ) + return reinterpret_cast< sal_Int64 >( this ); + else + return 0; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/classes/rootactiontriggercontainer.cxx b/framework/source/fwe/classes/rootactiontriggercontainer.cxx new file mode 100644 index 000000000..8ce69fde7 --- /dev/null +++ b/framework/source/fwe/classes/rootactiontriggercontainer.cxx @@ -0,0 +1,264 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace cppu; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::container; +using namespace com::sun::star::beans; + +namespace framework +{ + +static Sequence< sal_Int8 > const & impl_getStaticIdentifier() +{ + static const sal_uInt8 pGUID[16] = { 0x17, 0x0F, 0xA2, 0xC9, 0xCA, 0x50, 0x4A, 0xD3, 0xA6, 0x3B, 0x39, 0x99, 0xC5, 0x96, 0x43, 0x27 }; + static css::uno::Sequence< sal_Int8 > seqID(reinterpret_cast(pGUID), 16); + return seqID; +} + +RootActionTriggerContainer::RootActionTriggerContainer( const Menu* pMenu, const OUString* pMenuIdentifier ) : + PropertySetContainer() + , m_bContainerCreated( false ) + , m_pMenu( pMenu ) + , m_pMenuIdentifier( pMenuIdentifier ) +{ +} + +RootActionTriggerContainer::~RootActionTriggerContainer() +{ +} + +// XInterface +Any SAL_CALL RootActionTriggerContainer::queryInterface( const Type& aType ) +{ + Any a = ::cppu::queryInterface( + aType , + static_cast< XMultiServiceFactory* >(this), + static_cast< XServiceInfo* >(this), + static_cast< XUnoTunnel* >(this), + static_cast< XTypeProvider* >(this), + static_cast< XNamed* >(this)); + + if( a.hasValue() ) + { + return a; + } + + return PropertySetContainer::queryInterface( aType ); +} + +void SAL_CALL RootActionTriggerContainer::acquire() throw () +{ + PropertySetContainer::acquire(); +} + +void SAL_CALL RootActionTriggerContainer::release() throw () +{ + PropertySetContainer::release(); +} + +// XMultiServiceFactory +Reference< XInterface > SAL_CALL RootActionTriggerContainer::createInstance( const OUString& aServiceSpecifier ) +{ + if ( aServiceSpecifier == SERVICENAME_ACTIONTRIGGER ) + return static_cast( new ActionTriggerPropertySet()); + else if ( aServiceSpecifier == SERVICENAME_ACTIONTRIGGERCONTAINER ) + return static_cast( new ActionTriggerContainer()); + else if ( aServiceSpecifier == SERVICENAME_ACTIONTRIGGERSEPARATOR ) + return static_cast( new ActionTriggerSeparatorPropertySet()); + else + throw css::uno::RuntimeException("Unknown service specifier!", static_cast(this) ); +} + +Reference< XInterface > SAL_CALL RootActionTriggerContainer::createInstanceWithArguments( const OUString& ServiceSpecifier, const Sequence< Any >& /*Arguments*/ ) +{ + return createInstance( ServiceSpecifier ); +} + +Sequence< OUString > SAL_CALL RootActionTriggerContainer::getAvailableServiceNames() +{ + Sequence< OUString > aSeq( 3 ); + + aSeq[0] = SERVICENAME_ACTIONTRIGGER; + aSeq[1] = SERVICENAME_ACTIONTRIGGERCONTAINER; + aSeq[2] = SERVICENAME_ACTIONTRIGGERSEPARATOR; + + return aSeq; +} + +// XIndexContainer +void SAL_CALL RootActionTriggerContainer::insertByIndex( sal_Int32 Index, const Any& Element ) +{ + SolarMutexGuard g; + + if ( !m_bContainerCreated ) + FillContainer(); + + PropertySetContainer::insertByIndex( Index, Element ); +} + +void SAL_CALL RootActionTriggerContainer::removeByIndex( sal_Int32 Index ) +{ + SolarMutexGuard g; + + if ( !m_bContainerCreated ) + FillContainer(); + + PropertySetContainer::removeByIndex( Index ); +} + +// XIndexReplace +void SAL_CALL RootActionTriggerContainer::replaceByIndex( sal_Int32 Index, const Any& Element ) +{ + SolarMutexGuard g; + + if ( !m_bContainerCreated ) + FillContainer(); + + PropertySetContainer::replaceByIndex( Index, Element ); +} + +// XIndexAccess +sal_Int32 SAL_CALL RootActionTriggerContainer::getCount() +{ + SolarMutexGuard g; + + if ( !m_bContainerCreated ) + { + if ( m_pMenu ) + { + SolarMutexGuard aSolarMutexGuard; + return m_pMenu->GetItemCount(); + } + else + return 0; + } + else + { + return PropertySetContainer::getCount(); + } +} + +Any SAL_CALL RootActionTriggerContainer::getByIndex( sal_Int32 Index ) +{ + SolarMutexGuard g; + + if ( !m_bContainerCreated ) + FillContainer(); + + return PropertySetContainer::getByIndex( Index ); +} + +// XElementAccess +Type SAL_CALL RootActionTriggerContainer::getElementType() +{ + return cppu::UnoType::get(); +} + +sal_Bool SAL_CALL RootActionTriggerContainer::hasElements() +{ + if ( m_pMenu ) + { + SolarMutexGuard aSolarMutexGuard; + return ( m_pMenu->GetItemCount() > 0 ); + } + + return false; +} + +// XServiceInfo +OUString SAL_CALL RootActionTriggerContainer::getImplementationName() +{ + return IMPLEMENTATIONNAME_ROOTACTIONTRIGGERCONTAINER; +} + +sal_Bool SAL_CALL RootActionTriggerContainer::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL RootActionTriggerContainer::getSupportedServiceNames() +{ + Sequence< OUString > seqServiceNames { SERVICENAME_ACTIONTRIGGERCONTAINER }; + return seqServiceNames; +} + +// XUnoTunnel +sal_Int64 SAL_CALL RootActionTriggerContainer::getSomething( const Sequence< sal_Int8 >& aIdentifier ) +{ + if ( aIdentifier == impl_getStaticIdentifier() ) + return reinterpret_cast< sal_Int64 >( this ); + else + return 0; +} + +// XTypeProvider +Sequence< Type > SAL_CALL RootActionTriggerContainer::getTypes() +{ + // Create a static typecollection ... + static ::cppu::OTypeCollection ourTypeCollection( + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get()); + + return ourTypeCollection.getTypes(); +} + +Sequence< sal_Int8 > SAL_CALL RootActionTriggerContainer::getImplementationId() +{ + return css::uno::Sequence(); +} + +// private implementation helper +void RootActionTriggerContainer::FillContainer() +{ + m_bContainerCreated = true; + ActionTriggerHelper::FillActionTriggerContainerFromMenu( + this, + m_pMenu ); +} +OUString RootActionTriggerContainer::getName() +{ + OUString sRet; + if( m_pMenuIdentifier ) + sRet = *m_pMenuIdentifier; + return sRet; +} + +void RootActionTriggerContainer::setName( const OUString& ) +{ + throw RuntimeException(); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/classes/sfxhelperfunctions.cxx b/framework/source/fwe/classes/sfxhelperfunctions.cxx new file mode 100644 index 000000000..c6fe0bf03 --- /dev/null +++ b/framework/source/fwe/classes/sfxhelperfunctions.cxx @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 +#include +#include + +static pfunc_setToolBoxControllerCreator pToolBoxControllerCreator = nullptr; +static pfunc_setStatusBarControllerCreator pStatusBarControllerCreator = nullptr; +static pfunc_getRefreshToolbars pRefreshToolbars = nullptr; +static pfunc_createDockingWindow pCreateDockingWindow = nullptr; +static pfunc_isDockingWindowVisible pIsDockingWindowVisible = nullptr; + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; + +namespace framework +{ + +pfunc_setToolBoxControllerCreator SetToolBoxControllerCreator( pfunc_setToolBoxControllerCreator pSetToolBoxControllerCreator ) +{ + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + pfunc_setToolBoxControllerCreator pOldSetToolBoxControllerCreator = pToolBoxControllerCreator; + pToolBoxControllerCreator = pSetToolBoxControllerCreator; + return pOldSetToolBoxControllerCreator; +} + +svt::ToolboxController* CreateToolBoxController( const Reference< XFrame >& rFrame, ToolBox* pToolbox, unsigned short nID, const OUString& aCommandURL ) +{ + pfunc_setToolBoxControllerCreator pFactory = nullptr; + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + pFactory = pToolBoxControllerCreator; + } + + if ( pFactory ) + return (*pFactory)( rFrame, pToolbox, nID, aCommandURL ); + else + return nullptr; +} + +pfunc_setStatusBarControllerCreator SetStatusBarControllerCreator( pfunc_setStatusBarControllerCreator pSetStatusBarControllerCreator ) +{ + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + pfunc_setStatusBarControllerCreator pOldSetStatusBarControllerCreator = pSetStatusBarControllerCreator; + pStatusBarControllerCreator = pSetStatusBarControllerCreator; + return pOldSetStatusBarControllerCreator; +} + +svt::StatusbarController* CreateStatusBarController( const Reference< XFrame >& rFrame, StatusBar* pStatusBar, unsigned short nID, const OUString& aCommandURL ) +{ + pfunc_setStatusBarControllerCreator pFactory = nullptr; + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + pFactory = pStatusBarControllerCreator; + } + + if ( pFactory ) + return (*pFactory)( rFrame, pStatusBar, nID, aCommandURL ); + else + return nullptr; +} + +pfunc_getRefreshToolbars SetRefreshToolbars( pfunc_getRefreshToolbars pNewRefreshToolbarsFunc ) +{ + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + pfunc_getRefreshToolbars pOldFunc = pRefreshToolbars; + pRefreshToolbars = pNewRefreshToolbarsFunc; + + return pOldFunc; +} + +void RefreshToolbars( css::uno::Reference< css::frame::XFrame > const & rFrame ) +{ + pfunc_getRefreshToolbars pCallback = nullptr; + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + pCallback = pRefreshToolbars; + } + + if ( pCallback ) + (*pCallback)( rFrame ); +} + +pfunc_createDockingWindow SetDockingWindowCreator( pfunc_createDockingWindow pNewCreateDockingWindow ) +{ + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + pfunc_createDockingWindow pOldFunc = pCreateDockingWindow; + pCreateDockingWindow = pNewCreateDockingWindow; + + return pOldFunc; +} + +void CreateDockingWindow( const css::uno::Reference< css::frame::XFrame >& rFrame, const OUString& rResourceURL ) +{ + pfunc_createDockingWindow pFactory = nullptr; + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + pFactory = pCreateDockingWindow; + } + + if ( pFactory ) + (*pFactory)( rFrame, rResourceURL ); +} + +pfunc_isDockingWindowVisible SetIsDockingWindowVisible( pfunc_isDockingWindowVisible pNewIsDockingWindowVisible) +{ + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + pfunc_isDockingWindowVisible pOldFunc = pIsDockingWindowVisible; + pIsDockingWindowVisible = pNewIsDockingWindowVisible; + + return pOldFunc; +} + +bool IsDockingWindowVisible( const css::uno::Reference< css::frame::XFrame >& rFrame, const OUString& rResourceURL ) +{ + pfunc_isDockingWindowVisible pCall = nullptr; + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + pCall = pIsDockingWindowVisible; + } + + if ( pCall ) + return (*pCall)( rFrame, rResourceURL ); + else + return false; +} + +using namespace ::com::sun::star; +uno::Reference GetFirstListenerWith( + uno::Reference const& xEventFocus, + std::function const&)> const& rPredicate) +{ + return GetFirstListenerWith_Impl(xEventFocus, rPredicate); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3